[
  {
    "path": ".dockerignore",
    "content": "**/*.md\n**/.gitkeep\n**/.vscode\n.dockerignore\n.editorconfig\n.eslintrc.js\n.git\n.gitconfig\n.github\n.gitignore\n.husky\n.next\n.prettierignore\n.vscode\ncharts\nconfig/db/*\nconfig/logs/*\nconfig/*.json\ncypress\ndist\nDockerfile*\ncompose.yaml\ngen-docs\ndocs\nLICENSE\nnode_modules\npublic/os_logo_filled.png\npublic/preview.jpg\nstylelint.config.js\n"
  },
  {
    "path": ".editorconfig",
    "content": "# editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\ntrim_trailing_whitespace = true\n\n[*.md]\ntrim_trailing_whitespace = false"
  },
  {
    "path": ".gitattributes",
    "content": "* text eol=lf\n\n#\n## These files are binary and should be left untouched\n#\n\n# (binary is a macro for -text -diff)\n*.png binary\n*.jpg binary\n*.jpeg binary\n*.gif binary\n*.ico binary\n*.mov binary\n*.mp4 binary\n*.mp3 binary\n*.flv binary\n*.fla binary\n*.swf binary\n*.gz binary\n*.zip binary\n*.7z binary\n*.ttf binary\n*.eot binary\n*.woff binary\n*.pyc binary\n*.pdf binary\n\n#\n## Theses files/directories should be excluded from git archives\n#\n\n.husky export-ignore\n.vscode export-ignore\ndocs export-ignore\n\n.git* export-ignore\n*ignore export-ignore\n*.md export-ignore\n\n.editorconfig export-ignore\nDockerfile.local export-ignore\ncompose.yaml export-ignore\nstylelint.config.js export-ignore\n\npublic/os_logo_filled.png export-ignore\npublic/preview.jpg export-ignore\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# Global code ownership\n*                               @seerr-team/seerr-core\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "open_collective: seerr\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug.yml",
    "content": "name: 🐛 Bug Report\ndescription: Report a problem\nlabels: ['awaiting triage']\ntype: bug\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n\n        Please note that we use GitHub issues exclusively for bug reports and feature requests. For support requests, please use our other support channels to get help.\n  - type: textarea\n    id: description\n    attributes:\n      label: Description\n      description: Please provide a clear and concise description of the bug or issue.\n    validations:\n      required: true\n  - type: input\n    id: version\n    attributes:\n      label: Version\n      description: What version of Seerr are you running? (You can find this in Settings → About → Version.)\n    validations:\n      required: true\n  - type: textarea\n    id: repro-steps\n    attributes:\n      label: Steps to Reproduce\n      description: Please tell us how we can reproduce the undesired behavior.\n      placeholder: |\n        1. Go to [...]\n        2. Click on [...]\n        3. Scroll down to [...]\n        4. See error in [...]\n    validations:\n      required: true\n  - type: textarea\n    id: screenshots\n    attributes:\n      label: Screenshots\n      description: If applicable, please provide screenshots depicting the problem.\n  - type: textarea\n    id: logs\n    attributes:\n      label: Logs\n      description: Please copy and paste any relevant log output. (This will be automatically formatted into code, so no need for backticks.)\n      render: shell\n  - type: dropdown\n    id: platform\n    attributes:\n      label: Platform\n      options:\n        - desktop\n        - smartphone\n        - tablet\n    validations:\n      required: true\n  - type: dropdown\n    id: database\n    attributes:\n      options:\n        - SQLite (default)\n        - PostgreSQL\n      label: Database\n      description: Which database backend are you using?\n    validations:\n      required: true\n  - type: input\n    id: device\n    attributes:\n      label: Device\n      description: e.g., iPhone X, Surface Pro, Samsung Galaxy Tab\n    validations:\n      required: true\n  - type: input\n    id: os\n    attributes:\n      label: Operating System\n      description: e.g., iOS 8.1, Windows 10, Android 11\n    validations:\n      required: true\n  - type: input\n    id: browser\n    attributes:\n      label: Browser\n      description: e.g., Chrome, Safari, Edge, Firefox\n    validations:\n      required: true\n  - type: textarea\n    id: additional-context\n    attributes:\n      label: Additional Context\n      description: Please provide any additional information that may be relevant or helpful.\n  - type: checkboxes\n    id: search-existing\n    attributes:\n      label: Search Existing Issues\n      description: Have you searched existing issues to see if this bug has already been reported?\n      options:\n        - label: Yes, I have searched existing issues.\n          required: true\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: Code of Conduct\n      description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/seerr-team/seerr/blob/develop/CODE_OF_CONDUCT.md)\n      options:\n        - label: I agree to follow Seerr's Code of Conduct\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: 💬 Support via Discord\n    url: https://discord.gg/seerr\n    about: Chat with other users and the Seerr dev team\n  - name: 💬 Support via GitHub Discussions\n    url: https://github.com/seerr-team/seerr/discussions\n    about: Ask questions and discuss with other community members\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/documentation.yml",
    "content": "name: 📚 Documentation\ndescription: Report a docs problem or suggest a docs improvement\ntitle: \"[Docs]: \"\nlabels: [\"documentation\", \"awaiting triage\"]\ntype: task\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for helping improve the docs!\n\n        Use this template for documentation issues (typos, unclear steps, missing info, outdated screenshots).\n        For app bugs or feature ideas, please use the other templates.\n  - type: input\n    id: doc-location\n    attributes:\n      label: Page / Location\n      description: Link to the docs page or the file/path (e.g. https://docs.seerr.dev/... or README.md)\n      placeholder: \"https://docs.seerr.dev/...\"\n    validations:\n      required: true\n  - type: dropdown\n    id: doc-area\n    attributes:\n      label: Docs Area\n      options:\n        - docs site\n        - migration guide\n        - README / repo docs\n        - API / integrations\n        - other\n    validations:\n      required: true\n  - type: textarea\n    id: problem\n    attributes:\n      label: What’s wrong / missing?\n      description: Describe the issue in the docs.\n    validations:\n      required: true\n  - type: textarea\n    id: suggested-fix\n    attributes:\n      label: Suggested change\n      description: If you know what should be changed, describe it (or paste proposed wording).\n    validations:\n      required: false\n  - type: checkboxes\n    id: search-existing\n    attributes:\n      label: Search Existing Issues\n      description: Have you searched existing issues to see if this has already been reported?\n      options:\n        - label: Yes, I have searched existing issues.\n          required: true\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: Code of Conduct\n      description: By submitting this issue, you agree to follow our Code of Conduct.\n      options:\n        - label: I agree to follow Seerr's [Code of Conduct](https://github.com/seerr-team/seerr/blob/develop/CODE_OF_CONDUCT.md).\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/enhancement.yml",
    "content": "name: ✨ Feature Request\ndescription: Suggest an idea\nlabels: ['awaiting triage']\ntype: feature\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this feature request!\n\n        Please note that we use GitHub issues exclusively for bug reports and feature requests. For support requests, please use our other support channels to get help.\n  - type: textarea\n    id: description\n    attributes:\n      label: Description\n      description: Is your feature request related to a problem? If so, please provide a clear and concise description of the problem; e.g., \"I'm always frustrated when [...].\"\n    validations:\n      required: true\n  - type: textarea\n    id: desired-behavior\n    attributes:\n      label: Desired Behavior\n      description: Provide a clear and concise description of what you want to happen.\n    validations:\n      required: true\n  - type: textarea\n    id: additional-context\n    attributes:\n      label: Additional Context\n      description: Provide any additional information or screenshots that may be relevant or helpful.\n  - type: checkboxes\n    id: search-existing\n    attributes:\n      label: Search Existing Issues\n      description: Have you searched existing issues to see if this feature has already been requested?\n      options:\n        - label: Yes, I have searched existing issues.\n          required: true\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: Code of Conduct\n      description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/seerr-team/seerr/blob/develop/CODE_OF_CONDUCT.md)\n      options:\n        - label: I agree to follow Seerr's Code of Conduct\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/maintenance.yml",
    "content": "name: 🧰 Maintenance / Chore\ndescription: CI, GitHub Actions, build, dependencies, refactors (non-feature work)\ntitle: \"[Chore]: \"\nlabels: [\"maintenance\", \"awaiting triage\"]\ntype: task\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Maintainers / contributors: use this for internal tasks (CI, workflows, tooling, refactors).\n        If you're reporting a user-facing bug or requesting a feature, use the other templates.\n  - type: dropdown\n    id: area\n    attributes:\n      label: Area\n      options:\n        - CI / GitHub Actions\n        - build / packaging\n        - dependencies\n        - release process\n        - refactor / tech debt\n        - tooling / scripts\n        - other\n    validations:\n      required: true\n  - type: textarea\n    id: summary\n    attributes:\n      label: Summary\n      description: What needs doing and why?\n    validations:\n      required: true\n  - type: textarea\n    id: acceptance\n    attributes:\n      label: Acceptance criteria\n      description: What does \"done\" look like?\n      placeholder: |\n        - [ ] ...\n        - [ ] ...\n    validations:\n      required: false\n  - type: input\n    id: related\n    attributes:\n      label: Related links\n      description: PRs, failing workflow runs, logs, or relevant issues.\n    validations:\n      required: false\n  - type: checkboxes\n    id: search-existing\n    attributes:\n      label: Search Existing Issues\n      description: Have you searched existing issues to see if this has already been reported?\n      options:\n        - label: Yes, I have searched existing issues.\n          required: true\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: Code of Conduct\n      description: By submitting this issue, you agree to follow our Code of Conduct.\n      options:\n        - label: I agree to follow Seerr's [Code of Conduct](https://github.com/seerr-team/seerr/blob/develop/CODE_OF_CONDUCT.md).\n          required: true\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\n    Please read contributing guide before submitting\n    your pull request. Please fill in each section below to help us better prioritize your pull request. Thanks!\n-->\n\n## Description\n\n<!--- Describe your changes in detail -->\n<!--- Why is this change required? What problem does it solve? -->\n<!--- If it fixes an open issue, please link to the issue here. -->\n\n- Fixes #XXXX\n\n## How Has This Been Tested?\n\n<!--- Please describe in detail how you tested your changes. -->\n<!--- Include details of your testing environment, and the tests you ran to -->\n<!--- see how your change affects other areas of the code, etc. -->\n\n## Screenshots / Logs (if applicable)\n\n## Checklist:\n\n<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->\n<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->\n\n- [ ] I have read and followed the contribution [guidelines](https://github.com/seerr-team/seerr/blob/develop/CONTRIBUTING.md).\n- [ ] Disclosed any use of AI (see our [policy](https://github.com/seerr-team/seerr/blob/develop/CONTRIBUTING.md#ai-assistance-notice))\n- [ ] I have updated the documentation accordingly.\n- [ ] All new and existing tests passed.\n- [ ] Successful build `pnpm build`\n- [ ] Translation keys `pnpm i18n:extract`\n- [ ] Database migration (if required)\n"
  },
  {
    "path": ".github/cliff.toml",
    "content": "# git-cliff ~ configuration\n# https://git-cliff.org/docs/configuration\n\n[changelog]\nheader = \"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n\n{%- set excluded_users = [\"github-actions[bot]\", \"dependabot[bot]\", \"renovate[bot]\"] -%}\n\n{% macro print_commit(commit) -%}\n    - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\\\n        {% if commit.breaking %}[**breaking**] {% endif %}\\\n        {{ commit.message | upper_first }} - \\\n        ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n{% endmacro -%}\n\n{% if version %}\\\n    {% if previous.version %}\\\n        ## [{{ version | trim_start_matches(pat=\"v\") }}]({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format=\"%Y-%m-%d\") }}\n    {% else %}\\\n        ## [{{ version | trim_start_matches(pat=\"v\") }}] - {{ timestamp | date(format=\"%Y-%m-%d\") }}\n    {% endif %}\\\n{% else %}\\\n    ## [unreleased]\n{% endif %}\\\n\n{%- for group, commits in commits | group_by(attribute=\"group\") %}\n    ### {{ group | striptags | trim | upper_first }}\n    {%- for commit in commits | filter(attribute=\"scope\") | sort(attribute=\"scope\") %}\n        {{ self::print_commit(commit=commit) }}\n    {%- endfor %}\n    {%- for commit in commits %}\n        {%- if not commit.scope %}\n            {{ self::print_commit(commit=commit) }}\n        {%- endif %}\n    {%- endfor -%}\n{%- endfor -%}\n\n{%- set valid_contributors = [] -%}\n{%- for c in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\n  {%- if c.username and c.username not in excluded_users and c.username not in valid_contributors %}\n    {%- set_global valid_contributors = valid_contributors | concat(with=c.username) %}\n  {%- endif %}\n{%- endfor %}\n\n{%- if valid_contributors | length > 0 %}\n## New Contributors ❤️\n  {%- for username in valid_contributors %}\n* @{{ username }} made their first contribution\n  {%- endfor %}\n{%- endif %}\n\"\"\"\nfooter = \"\"\"\n<!-- generated by git-cliff -->\n\"\"\"\ntrim = true\npostprocessors = []\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\nsplit_commits = false\nfilter_commits = true\ncommit_preprocessors = [\n  { pattern = '.*\\[skip ci\\].*', replace = \"\" },\n  { pattern = '.*\\[ci skip\\].*', replace = \"\" },\n]\ncommit_parsers = [\n  { message = '.*\\(helm\\).*', skip = true },\n  { message = '^chore\\(release\\): prepare for', skip = true },\n  { message = '^chore\\(deps.*\\)', skip = true },\n  { body = \".*security\", group = \"<!-- 0 -->🛡️ Security\" },\n  { message = \"^feat\", group = \"<!-- 1 -->🚀 Features\" },\n  { message = \"^fix\", group = \"<!-- 2 -->🐛 Bug Fixes\" },\n  { message = \"^doc\", group = \"<!-- 3 -->📖 Documentation\" },\n  { message = \"^perf\", group = \"<!-- 4 -->⚡ Performance\" },\n  { message = \"^refactor\", group = \"<!-- 5 -->🚜 Refactor\" },\n  { message = \"^style\", group = \"<!-- 6 -->🎨 Styling\" },\n  { message = \"^test\", group = \"<!-- 7 -->🧪 Testing\" },\n  { message = \"^chore|^ci\", group = \"<!-- 8 -->⚙️ Miscellaneous Tasks\" },\n  { message = \"^revert\", group = \"<!-- 9 -->◀️ Revert\" },\n]\nprotect_breaking_commits = false\ntag_pattern = \"v?[0-9]+\\\\.[0-9]+\\\\.[0-9]+.*\"\nskip_tags = \"beta|alpha|rc\"\ntopo_order = false\nsort_commits = \"newest\"\n"
  },
  {
    "path": ".github/renovate/actions.json5",
    "content": "{\n  $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n\n  extends: ['helpers:pinGitHubActionDigests'],\n\n  packageRules: [\n    // All GitHub Actions need manual review\n    {\n      matchManagers: ['github-actions'],\n      groupName: 'GitHub Actions',\n    },\n  ],\n}\n"
  },
  {
    "path": ".github/renovate/docker.json5",
    "content": "{\n  $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n\n  extends: [\n    'docker:enableMajor',\n    'docker:pinDigests'\n  ],\n\n  packageRules: [\n    {\n      matchManagers: ['docker-compose'],\n      pinDigests: false,\n    },\n  ],\n}\n"
  },
  {
    "path": ".github/renovate/groups.json5",
    "content": "{\n  $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n\n  packageRules: [\n    // Node.js\n    {\n      matchPackageNames: ['node'],\n      matchManagers: ['dockerfile', 'npm'],\n      groupName: 'Node.js',\n      commitMessageTopic: 'Node.js',\n    },\n\n    // Database packages\n    {\n      matchPackageNames: ['pg', 'sqlite3', 'typeorm'],\n      groupName: 'Database',\n    },\n  ],\n}\n"
  },
  {
    "path": ".github/renovate/helm.json5",
    "content": "{\n  $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n\n  packageRules: [\n    {\n      matchManagers: ['helm-values'],\n      matchFileNames: ['charts/*/values.yaml'],\n      minimumReleaseAge: '0',\n      pinDigests: false,\n    },\n  ],\n\n  customManagers: [\n    {\n      customType: 'regex',\n      description: 'Update appVersion in Chart.yaml to match Docker image',\n      fileMatch: ['(^|/)Chart\\\\.yaml$'],\n      matchStrings: [\n        \"#\\\\s+renovate:\\\\s+image=(?<depName>\\\\S*)\\nappVersion:\\\\s+'(?<currentValue>\\\\S*)'\",\n      ],\n      datasourceTemplate: 'docker',\n    },\n  ],\n}\n"
  },
  {
    "path": ".github/renovate/labels.json5",
    "content": "{\n  $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n\n  packageRules: [\n    // JavaScript/npm packages\n    {\n      matchManagers: ['npm'],\n      addLabels: ['javascript'],\n    },\n\n    // GitHub Actions\n    {\n      matchManagers: ['github-actions'],\n      addLabels: ['github_actions'],\n    },\n\n    // Docker images\n    {\n      matchManagers: ['dockerfile', 'docker-compose'],\n      addLabels: ['docker'],\n    },\n\n    // Helm charts\n    {\n      matchManagers: ['helm-values'],\n      addLabels: ['helm'],\n    },\n  ],\n}\n"
  },
  {
    "path": ".github/renovate/pnpm.json5",
    "content": "{\n  $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n\n  // Run pnpm dedupe after dependency updates\n  postUpdateOptions: ['pnpmDedupe'],\n\n  lockFileMaintenance: {\n    enabled: true,\n  },\n\n}\n"
  },
  {
    "path": ".github/renovate/semanticCommits.json5",
    "content": "{\n  $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n\n  packageRules: [\n    // Default for all dependencies\n    {\n      matchPackagePatterns: ['*'],\n      semanticCommitType: 'chore',\n      semanticCommitScope: 'deps',\n    },\n\n    // Node.js runtime\n    {\n      matchPackageNames: ['node'],\n      semanticCommitType: 'build',\n      semanticCommitScope: 'node',\n    },\n\n    // GitHub Actions\n    {\n      matchManagers: ['github-actions'],\n      semanticCommitType: 'ci',\n      semanticCommitScope: 'actions',\n    },\n\n    // Docker\n    {\n      matchManagers: ['dockerfile'],\n      semanticCommitType: 'build',\n      semanticCommitScope: 'docker',\n    },\n  ],\n}\n"
  },
  {
    "path": ".github/renovate.json5",
    "content": "{\n  $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n  extends: [\n    'config:recommended',\n    ':dependencyDashboard',\n    ':timezone(UTC)',\n    'group:allNonMajor',\n    'group:nextjsMonorepo',\n    'group:reactMonorepo',\n    'group:typescript-eslintMonorepo',\n    'group:tailwindcssMonorepo',\n    'github>seerr-team/seerr//.github/renovate/actions.json5',\n    'github>seerr-team/seerr//.github/renovate/docker.json5',\n    'github>seerr-team/seerr//.github/renovate/groups.json5',\n    'github>seerr-team/seerr//.github/renovate/helm.json5',\n    'github>seerr-team/seerr//.github/renovate/labels.json5',\n    'github>seerr-team/seerr//.github/renovate/pnpm.json5',\n    'github>seerr-team/seerr//.github/renovate/semanticCommits.json5',\n  ],\n  dependencyDashboardTitle: 'Renovate Dashboard 🤖',\n  suppressNotifications: ['prEditedNotification', 'prIgnoreNotification'],\n  rebaseWhen: 'conflicted',\n  labels: ['dependencies'],\n  minimumReleaseAge: '7 days',\n}\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Seerr CI\n\non:\n  pull_request:\n    branches:\n      - '*'\n  push:\n    branches:\n      - develop\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nenv:\n  DOCKER_HUB: seerr/seerr\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  i18n:\n    name: i18n Check\n    if: github.event_name == 'pull_request'\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n      pull-requests: write\n    env:\n      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      GH_REPO: ${{ github.repository }}\n      NUMBER: ${{ github.event.pull_request.number }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Pnpm Setup\n        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0\n\n      - name: Set up Node.js\n        uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0\n        with:\n          node-version-file: 'package.json'\n\n      - name: Get pnpm store directory\n        shell: bash\n        run: echo \"STORE_PATH=$(pnpm store path --silent)\" >> $GITHUB_ENV\n\n      - name: Setup pnpm cache\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0\n        with:\n          path: ${{ env.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n\n      - name: Install dependencies\n        env:\n          CI: true\n        run: pnpm install\n\n      - name: i18n Check\n        shell: bash\n        env:\n          I18N_LABEL: i18n-out-of-sync\n          BODY: |\n            The i18n check failed because translation messages are out of sync.\n\n            This usually happens when you've added or modified translation strings in your code but haven't updated the translation file.\n\n            Please run `pnpm i18n:extract` and commit the changes.\n        run: |\n          retry() { n=0; until \"$@\"; do n=$((n+1)); [ $n -ge 3 ] && break; echo \"retry $n: $*\" >&2; sleep 2; done; }\n          check_failed=0; node bin/check-i18n.js || check_failed=$?\n          pr_labels=$(gh pr view \"$NUMBER\" -R \"$GH_REPO\" --json labels -q '.labels[].name' 2>/dev/null) || true\n          has_label=0\n          while IFS= read -r name; do [ -n \"$name\" ] && [ \"$name\" = \"$I18N_LABEL\" ] && has_label=1 && break; done <<< \"$pr_labels\"\n          if [ \"$check_failed\" -eq 1 ]; then\n            [ \"$has_label\" -eq 0 ] && { retry gh pr edit \"$NUMBER\" -R \"$GH_REPO\" --add-label \"$I18N_LABEL\" || true; retry gh pr comment \"$NUMBER\" -R \"$GH_REPO\" -b \"$BODY\" || true; }\n          else\n            [ \"$has_label\" -eq 1 ] && retry gh pr edit \"$NUMBER\" -R \"$GH_REPO\" --remove-label \"$I18N_LABEL\" || true\n          fi\n          exit $check_failed\n  test:\n    name: Lint & Test Build\n    if: github.event_name == 'pull_request'\n    runs-on: ubuntu-24.04\n    container: node:22.22.1-alpine3.22@sha256:9f96f09f127f06feaff1e7faa4a34a3020cf5c1138c988782e59959641facabe\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Pnpm Setup\n        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0\n\n      - name: Get pnpm store directory\n        shell: sh\n        run: |\n          echo \"STORE_PATH=$(pnpm store path --silent)\" >> $GITHUB_ENV\n\n      - name: Setup pnpm cache\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0\n        with:\n          path: ${{ env.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n\n      - name: Install dependencies\n        env:\n          CI: true\n        run: pnpm install\n\n      - name: Lint\n        run: pnpm lint\n\n      - name: Formatting\n        run: pnpm format:check\n\n      - name: Build\n        run: pnpm build\n\n  unit-test:\n    name: Unit Tests\n    if: github.event_name == 'pull_request'\n    runs-on: ubuntu-24.04\n    container: node:22.22.1-alpine3.22@sha256:9f96f09f127f06feaff1e7faa4a34a3020cf5c1138c988782e59959641facabe\n    permissions:\n      checks: write\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Pnpm Setup\n        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0\n\n      - name: Get pnpm store directory\n        shell: sh\n        run: |\n          echo \"STORE_PATH=$(pnpm store path --silent)\" >> $GITHUB_ENV\n\n      - name: Setup pnpm cache\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0\n        with:\n          path: ${{ env.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n\n      - name: Install dependencies\n        env:\n          CI: true\n        run: pnpm install\n\n      - name: Run tests\n        env:\n          CI: true\n        run: pnpm test\n\n      - name: Publish test report\n        uses: mikepenz/action-junit-report@49b2ca06f62aa7ef83ae6769a2179271e160d8e4 # v6.3.1\n        if: success() || failure() # always run even if the previous step fails\n        with:\n          report_paths: 'report.xml'\n\n  build:\n    name: Build (per-arch, native runners)\n    if: github.ref == 'refs/heads/develop'\n    strategy:\n      matrix:\n        include:\n          - runner: ubuntu-24.04\n            platform: linux/amd64\n            arch: amd64\n          - runner: ubuntu-24.04-arm\n            platform: linux/arm64\n            arch: arm64\n    runs-on: ${{ matrix.runner }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Commit timestamp\n        id: ts\n        run: echo \"TIMESTAMP=$(git log -1 --pretty=%ct)\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0\n\n      - name: Warm cache (no push) — ${{ matrix.platform }}\n        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2\n        with:\n          context: .\n          file: ./Dockerfile\n          platforms: ${{ matrix.platform }}\n          push: false\n          build-args: |\n            COMMIT_TAG=${{ github.sha }}\n            BUILD_VERSION=develop\n            SOURCE_DATE_EPOCH=${{ steps.ts.outputs.TIMESTAMP }}\n          cache-from: type=gha,scope=${{ matrix.platform }}\n          cache-to: type=gha,mode=max,scope=${{ matrix.platform }}\n          provenance: false\n\n  publish:\n    name: Publish multi-arch image\n    needs: build\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n      packages: write\n      id-token: write\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Commit timestamp\n        id: ts\n        run: echo \"TIMESTAMP=$(git log -1 --pretty=%ct)\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0\n\n      - name: Log in to Docker Hub\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_TOKEN }}\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Extract metadata\n        id: meta\n        uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0\n        with:\n          images: |\n            ${{ env.DOCKER_HUB }}\n            ghcr.io/${{ github.repository }}\n          tags: |\n            type=raw,value=develop\n            type=sha\n          labels: |\n            org.opencontainers.image.created=${{ steps.ts.outputs.TIMESTAMP }}\n\n      - name: Build & Push (multi-arch, single tag)\n        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2\n        with:\n          context: .\n          file: ./Dockerfile\n          platforms: linux/amd64,linux/arm64\n          push: true\n          build-args: |\n            COMMIT_TAG=${{ github.sha }}\n            BUILD_VERSION=develop\n            SOURCE_DATE_EPOCH=${{ steps.ts.outputs.TIMESTAMP }}\n          labels: ${{ steps.meta.outputs.labels }}\n          tags: ${{ steps.meta.outputs.tags }}\n          cache-from: |\n            type=gha,scope=linux/amd64\n            type=gha,scope=linux/arm64\n          cache-to: type=gha,mode=max\n          provenance: false\n\n  discord:\n    name: Send Discord Notification\n    needs: publish\n    if: always() && github.event_name != 'pull_request'\n    runs-on: ubuntu-24.04\n    steps:\n      - name: Determine Workflow Status\n        id: status\n        run: |\n          case \"${{ needs.publish.result }}\" in\n            success)   echo \"status=Success\"   >> $GITHUB_OUTPUT; echo \"colour=3066993\"  >> $GITHUB_OUTPUT ;;\n            failure)   echo \"status=Failure\"   >> $GITHUB_OUTPUT; echo \"colour=15158332\" >> $GITHUB_OUTPUT ;;\n            cancelled) echo \"status=Cancelled\" >> $GITHUB_OUTPUT; echo \"colour=10181046\" >> $GITHUB_OUTPUT ;;\n            *)         echo \"status=Skipped\"   >> $GITHUB_OUTPUT; echo \"colour=9807270\"  >> $GITHUB_OUTPUT ;;\n          esac\n\n      - name: Send Discord notification\n        shell: bash\n        run: |\n          WEBHOOK=\"${{ secrets.DISCORD_WEBHOOK }}\"\n\n          PAYLOAD=$(cat <<EOF\n          {\n            \"embeds\": [{\n              \"title\": \"${{ steps.status.outputs.status }}: ${{ github.workflow }}\",\n              \"color\": ${{ steps.status.outputs.colour }},\n              \"fields\": [\n                { \"name\": \"Repository\",   \"value\": \"[${{ github.repository }}](${{ github.server_url }}/${{ github.repository }})\", \"inline\": true },\n                { \"name\": \"Ref\",          \"value\": \"${{ github.ref }}\", \"inline\": true },\n                { \"name\": \"Event\",        \"value\": \"${{ github.event_name }}\", \"inline\": true },\n                { \"name\": \"Triggered by\", \"value\": \"${{ github.actor }}\", \"inline\": true },\n                { \"name\": \"Workflow\",     \"value\": \"[${{ github.workflow }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\", \"inline\": true }\n              ],\n            }]\n          }\n          EOF\n          )\n\n          curl -sS -H \"Content-Type: application/json\" -X POST -d \"$PAYLOAD\" \"$WEBHOOK\" || true\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: 'CodeQL'\n\non:\n  push:\n    branches: ['develop']\n    paths-ignore:\n      - '**/*.md'\n      - 'docs/**'\n  pull_request:\n    branches: ['develop']\n    paths-ignore:\n      - '**/*.md'\n      - 'docs/**'\n  schedule:\n    - cron: '50 7 * * 5'\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-24.04\n    timeout-minutes: 10\n    permissions:\n      contents: read\n      security-events: write\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [actions, javascript]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6\n        with:\n          languages: ${{ matrix.language }}\n          queries: +security-and-quality\n\n      - name: Autobuild\n        uses: github/codeql-action/autobuild@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6\n        with:\n          category: '/language:${{ matrix.language }}'\n"
  },
  {
    "path": ".github/workflows/conflict_labeler.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Merge Conflict Labeler\n\non:\n  push:\n    branches: [develop]\n\n  pull_request_target:\n    branches: [develop]\n    types: [opened, synchronize, reopened]\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  label:\n    name: Labeling\n    runs-on: ubuntu-24.04\n    timeout-minutes: 10\n    permissions:\n      contents: read\n      pull-requests: write\n    steps:\n      - name: Apply label\n        uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3.0.3\n        with:\n          dirtyLabel: 'merge conflict'\n          commentOnDirty: 'This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.'\n          repoToken: '${{ secrets.GITHUB_TOKEN }}'\n"
  },
  {
    "path": ".github/workflows/create-tag.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Create tag\n\non:\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  determine-tag-version:\n    name: Determine tag version\n    if: github.ref == 'refs/heads/main'\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n    outputs:\n      tag_version: ${{ steps.git-cliff.outputs.tag_version }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Install git-cliff\n        uses: taiki-e/install-action@a37010ded18ff788be4440302bd6830b1ae50d8b # v2.68.25\n        with:\n          tool: git-cliff\n\n      - name: Get tag version\n        id: git-cliff\n        run: |\n          tag_version=$(git-cliff -c .github/cliff.toml --bumped-version --unreleased)\n          echo \"Next tag version is ${tag_version}\"\n          echo \"tag_version=${tag_version}\" >> \"$GITHUB_OUTPUT\"\n\n  create-tag:\n    name: Create tag\n    if: github.ref == 'refs/heads/main'\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: write\n    needs: determine-tag-version\n    env:\n      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      TAG_VERSION: ${{ needs.determine-tag-version.outputs.tag_version }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          ssh-key: '${{ secrets.COMMIT_KEY }}'\n\n      - name: Pnpm Setup\n        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0\n\n      - name: Set up Node.js\n        uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0\n        with:\n          node-version-file: 'package.json'\n          # For workflows with elevated privileges we recommend disabling automatic caching.\n          # https://github.com/actions/setup-node\n          package-manager-cache: false\n\n      - name: Configure git\n        run: |\n          git config --global user.name \"${{ github.actor }}\"\n          git config --global user.email \"${{ github.actor }}@users.noreply.github.com\"\n\n      - name: Bump package.json\n        run: npm version ${TAG_VERSION} --no-commit-hooks --no-git-tag-version\n\n      - name: Commit updated files\n        run: |\n          git add package.json\n          git commit -m \"chore(release): prepare ${TAG_VERSION}\"\n          git push\n\n      - name: Create git tag\n        run: |\n          git tag ${TAG_VERSION}\n          git push origin ${TAG_VERSION}\n"
  },
  {
    "path": ".github/workflows/cypress.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Cypress Tests\n\non:\n  pull_request:\n    branches: ['*']\n    paths:\n      - '{src,server,config,cypress}/**'\n      - 'cypress.config.ts'\n      - 'package.json'\n      - 'pnpm-lock.yaml'\n      - 'next.config.js'\n      - 'tsconfig.json'\n      - '.github/workflows/cypress.yml'\n  push:\n    branches: [develop]\n    paths:\n      - '{src,server,config,cypress}/**'\n      - 'cypress.config.ts'\n      - 'package.json'\n      - 'pnpm-lock.yaml'\n      - 'next.config.js'\n      - 'tsconfig.json'\n      - '.github/workflows/cypress.yml'\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  cypress-run:\n    name: Cypress Run\n    runs-on: ubuntu-24.04\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Set up Node.js\n        uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0\n        with:\n          node-version-file: package.json\n          package-manager-cache: false\n\n      - name: Pnpm Setup\n        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0\n\n      - name: Install dependencies\n        run: pnpm install --frozen-lockfile\n\n      - name: Setup cypress cache\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0\n        with:\n          path: ~/.cache/Cypress\n          key: ${{ runner.os }}-cypress-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-cypress-store-\n\n      - name: Install Cypress binary\n        env:\n          CYPRESS_CACHE_FOLDER: ~/.cache/Cypress\n        run: pnpm exec cypress install\n\n      - name: Cypress run\n        uses: cypress-io/github-action@f790eee7a50d9505912f50c2095510be7de06aa7 # v6.10.9\n        with:\n          install: false\n          build: pnpm cypress:build\n          start: pnpm start\n          wait-on: 'http://localhost:5055'\n          record: true\n        env:\n          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          WITH_MIGRATIONS: true\n          # Fix test titles in cypress dashboard\n          COMMIT_INFO_MESSAGE: ${{github.event.pull_request.title}}\n          COMMIT_INFO_SHA: ${{github.event.pull_request.head.sha}}\n"
  },
  {
    "path": ".github/workflows/detect-duplicate.yml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Duplicate Issue Detector\n\non:\n  issues:\n    types: [opened]\n\npermissions: {}\n\nenv:\n  EMBEDDING_MODEL: ${{ vars.EMBEDDING_MODEL }}\n  GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n  GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}\n\njobs:\n  detect-duplicate:\n    runs-on: ubuntu-24.04\n    if: ${{ !github.event.issue.pull_request }}\n    permissions:\n      issues: write\n      actions: read\n      contents: read\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n\n      - name: Pnpm Setup\n        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0\n\n      - name: Set up Node.js\n        uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0\n        with:\n          node-version-file: 'package.json'\n\n      - name: Get pnpm store directory\n        shell: bash\n        run: echo \"STORE_PATH=$(pnpm store path --silent)\" >> $GITHUB_ENV\n\n      - name: Setup pnpm cache\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0\n        with:\n          path: ${{ env.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n\n      - name: Install dependencies\n        working-directory: bin/duplicate-detector\n        env:\n          CI: true\n        run: pnpm install --frozen-lockfile\n\n      - name: Download issue index\n        uses: dawidd6/action-download-artifact@5c98f0b039f36ef966fdb7dfa9779262785ecb05 # v14\n        with:\n          name: issue-index\n          workflow: rebuild-issue-index.yml\n          path: bin/duplicate-detector\n          search_artifacts: true\n          if_no_artifact_found: warn\n\n      - name: Build index if missing\n        working-directory: bin/duplicate-detector\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          GITHUB_REPOSITORY: ${{ github.repository }}\n          INDEX_PATH: issue_index.json\n        run: |\n          if [ ! -f issue_index.json ]; then\n            echo \"No index found — building from scratch...\"\n            node build-index.mjs\n          fi\n\n      - name: Detect duplicates\n        working-directory: bin/duplicate-detector\n        continue-on-error: true\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          GITHUB_REPOSITORY: ${{ github.repository }}\n          ISSUE_NUMBER: ${{ github.event.issue.number }}\n          INDEX_PATH: issue_index.json\n        run: node detect.mjs\n"
  },
  {
    "path": ".github/workflows/docs-deploy.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Deploy to GitHub Pages\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - develop\n    paths:\n      - 'docs/**'\n      - 'gen-docs/**'\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  build:\n    name: Build Docusaurus\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Set up Node.js\n        uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0\n        with:\n          node-version-file: package.json\n          package-manager-cache: false\n\n      - name: Pnpm Setup\n        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0\n\n      - name: Get pnpm store directory\n        shell: sh\n        run: |\n          echo \"STORE_PATH=$(pnpm store path --silent)\" >> $GITHUB_ENV\n\n      - name: Setup pnpm cache\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0\n        with:\n          path: ${{ env.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n\n      - name: Install dependencies\n        run: |\n          cd gen-docs\n          pnpm install --frozen-lockfile\n\n      - name: Build website\n        working-directory: gen-docs\n        run: pnpm build\n\n      - name: Upload Build Artifact\n        uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b6 # v4.0.0\n        with:\n          path: gen-docs/build\n\n  deploy:\n    name: Deploy to GitHub Pages\n    needs: build\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n      pages: write\n      id-token: write\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5\n"
  },
  {
    "path": ".github/workflows/docs-link-check.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Check Docs Links\n\non:\n  pull_request:\n    branches:\n      - '*'\n    paths:\n      - 'docs/**'\n      - 'gen-docs/**'\n      - '.github/workflows/docs-link-check.yml'\n  push:\n    branches:\n      - develop\n    paths:\n      - 'docs/**'\n      - 'gen-docs/**'\n      - '.github/workflows/docs-link-check.yml'\n  schedule:\n    - cron: '50 7 * * 5'\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  link-check:\n    name: Verify external links in Markdown and MDX\n    runs-on: ubuntu-24.04\n    timeout-minutes: 20\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Run Lychee link checker\n        uses: lycheeverse/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411 # v2.8.0\n        with:\n          fail: false\n          args: >-\n            --verbose\n            --no-progress\n            --accept 200..204,300..304,307,308,404,429,999\n            --exclude '^file://'\n            --exclude '^https?://(localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|\\[::1\\]|\\[::\\])'\n            --exclude '^https?://support\\.discord\\.com'\n            './docs/**/*.md'\n            './docs/**/*.mdx'\n            './gen-docs/**/*.md'\n            './gen-docs/**/*.mdx'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Upload Lychee report\n        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2\n        with:\n          name: lychee-report\n          path: |\n            lychee/out.md\n            lychee/results.json\n          if-no-files-found: ignore\n"
  },
  {
    "path": ".github/workflows/helm.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Release Charts\n\non:\n  push:\n    branches:\n      - develop\n    paths:\n      - 'charts/**'\n      - '.github/workflows/release-charts.yml'\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  package-helm-chart:\n    name: Package helm chart\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n      packages: read\n    outputs:\n      has_artifacts: ${{ steps.check-artifacts.outputs.has_artifacts }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Install helm\n        uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1\n\n      - name: Install Oras\n        uses: oras-project/setup-oras@22ce207df3b08e061f537244349aac6ae1d214f6 # v1.2.4\n\n      - name: Login to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Package helm charts\n        run: |\n          mkdir -p ./.cr-release-packages\n          for chart_path in ./charts/*; do\n            if [ -d \"$chart_path\" ] && [ -f \"$chart_path/Chart.yaml\" ]; then\n              chart_name=$(grep '^name:' \"$chart_path/Chart.yaml\" | awk '{print $2}')\n              # get current version\n              current_version=$(grep '^version:' \"$chart_path/Chart.yaml\" | awk '{print $2}')\n              # try to get current release version\n              if oras manifest fetch \"ghcr.io/${{ github.repository }}/${chart_name}:${current_version}\" >/dev/null 2>&1; then\n                echo \"No version change for $chart_name. Skipping.\"\n              else\n                helm dependency build \"$chart_path\"\n                helm package \"$chart_path\" --destination ./.cr-release-packages\n              fi\n            else\n              echo \"Skipping $chart_name: Not a valid Helm chart\"\n            fi\n          done\n\n      - name: Check if artifacts exist\n        id: check-artifacts\n        run: |\n          if ls .cr-release-packages/*.tgz >/dev/null 2>&1; then\n            echo \"has_artifacts=true\" >> $GITHUB_OUTPUT\n          else\n            echo \"has_artifacts=false\" >> $GITHUB_OUTPUT\n          fi\n\n      - name: Upload artifacts\n        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2\n        if: steps.check-artifacts.outputs.has_artifacts == 'true'\n        with:\n          name: artifacts\n          include-hidden-files: true\n          path: .cr-release-packages/\n\n  publish:\n    name: Publish to ghcr.io\n    runs-on: ubuntu-24.04\n    permissions:\n      packages: write\n      id-token: write\n    needs: [package-helm-chart]\n    if: needs.package-helm-chart.outputs.has_artifacts == 'true'\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Install helm\n        uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1\n\n      - name: Install Oras\n        uses: oras-project/setup-oras@22ce207df3b08e061f537244349aac6ae1d214f6 # v1.2.4\n\n      - name: Install Cosign\n        uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0\n\n      - name: Downloads artifacts\n        uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0\n        with:\n          name: artifacts\n          path: .cr-release-packages/\n\n      - name: Login to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Push charts to GHCR\n        env:\n          COSIGN_YES: true\n        run: |\n          for chart_path in `find .cr-release-packages -name '*.tgz' -print`; do\n            # push chart to OCI\n            chart_release_file=$(basename \"$chart_path\")\n            chart_name=${chart_release_file%-*}\n            helm push ${chart_path} oci://ghcr.io/${{ github.repository }} |& tee helm-push-output.log\n            chart_digest=$(awk -F \"[, ]+\" '/Digest/{print $NF}' < helm-push-output.log)\n            # sign chart\n            cosign sign \"ghcr.io/${{ github.repository }}/${chart_name}@${chart_digest}\"\n            # push artifacthub-repo.yml to OCI\n            oras push \\\n              ghcr.io/${{ github.repository }}/${chart_name}:artifacthub.io \\\n              --config /dev/null:application/vnd.cncf.artifacthub.config.v1+yaml \\\n              charts/$chart_name/artifacthub-repo.yml:application/vnd.cncf.artifacthub.repository-metadata.layer.v1.yaml \\\n              |& tee oras-push-output.log\n            artifacthub_digest=$(grep \"Digest:\" oras-push-output.log | awk '{print $2}')\n            # sign artifacthub-repo.yml\n            cosign sign \"ghcr.io/${{ github.repository }}/${chart_name}:artifacthub.io@${artifacthub_digest}\"\n          done\n\n  verify:\n    name: Verify signatures for each chart tag\n    needs: [publish]\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Install Cosign\n        uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0\n\n      - name: Downloads artifacts\n        uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0\n        with:\n          name: artifacts\n          path: .cr-release-packages/\n\n      - name: Login to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Verify signatures for each chart tag\n        run: |\n          for chart_path in $(find .cr-release-packages -name '*.tgz' -print); do\n            chart_release_file=$(basename \"$chart_path\")\n            chart_name=${chart_release_file%-*}\n            version=${chart_release_file#$chart_name-}\n            version=${version%.tgz}\n\n            cosign verify \"ghcr.io/${{ github.repository }}/${chart_name}:${version}\" \\\n              --certificate-identity \"https://github.com/${{ github.workflow_ref }}\" \\\n              --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n          done\n"
  },
  {
    "path": ".github/workflows/lint-helm-charts.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Lint and Test Charts\n\non:\n  pull_request:\n    branches:\n      - develop\n    paths:\n      - '.github/workflows/lint-helm-charts.yml'\n      - 'charts/**'\n  push:\n    branches: [develop]\n    paths:\n      - 'charts/**'\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  lint-test:\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Set up Helm\n        uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1\n\n      - name: Set up chart-testing\n        uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f # v2.8.0\n\n      - name: Ensure documentation is updated\n        uses: docker://jnorwood/helm-docs:v1.14.2@sha256:7e562b49ab6b1dbc50c3da8f2dd6ffa8a5c6bba327b1c6335cc15ce29267979c\n\n      - name: Run chart-testing (list-changed)\n        id: list-changed\n        run: |\n          changed=$(ct list-changed --target-branch ${{ github.event.repository.default_branch }})\n          if [[ -n \"$changed\" ]]; then\n            echo \"changed=true\" >> \"$GITHUB_OUTPUT\"\n            echo \"$changed\"\n          fi\n\n      - name: Run chart-testing\n        if: steps.list-changed.outputs.changed == 'true'\n        run: ct lint --target-branch ${{ github.event.repository.default_branch }} --validate-maintainers=false\n"
  },
  {
    "path": ".github/workflows/preview.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Seerr Preview\n\non:\n  push:\n    tags:\n      - 'preview-*'\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nenv:\n  DOCKER_HUB: seerr/seerr\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  build:\n    name: Build (per-arch, native runners)\n    strategy:\n      matrix:\n        include:\n          - runner: ubuntu-24.04\n            platform: linux/amd64\n            arch: amd64\n          - runner: ubuntu-24.04-arm\n            platform: linux/arm64\n            arch: arm64\n    runs-on: ${{ matrix.runner }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Commit timestamp\n        id: ts\n        run: echo \"TIMESTAMP=$(git log -1 --pretty=%ct)\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0\n\n      - name: Derive preview version from tag\n        id: ver\n        shell: bash\n        run: |\n          TAG=\"${GITHUB_REF_NAME}\"\n          VER=\"${TAG#preview-}\"\n          VER=\"${VER#v}\"\n          echo \"version=${VER}\" >> \"$GITHUB_OUTPUT\"\n          echo \"Building preview version: ${VER}\"\n\n      - name: Warm cache (no push) — ${{ matrix.platform }}\n        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2\n        with:\n          context: .\n          file: ./Dockerfile\n          platforms: ${{ matrix.platform }}\n          push: false\n          build-args: |\n            COMMIT_TAG=${{ github.sha }}\n            BUILD_VERSION=${{ steps.ver.outputs.version }}\n            SOURCE_DATE_EPOCH=${{ steps.ts.outputs.TIMESTAMP }}\n          cache-from: type=gha,scope=${{ matrix.platform }}\n          cache-to: type=gha,mode=max,scope=${{ matrix.platform }}\n          provenance: false\n\n  publish:\n    name: Publish multi-arch image\n    needs: build\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n      packages: write\n      id-token: write\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Commit timestamp\n        id: ts\n        run: echo \"TIMESTAMP=$(git log -1 --pretty=%ct)\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0\n\n      - name: Log in to Docker Hub\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_TOKEN }}\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Derive preview version from tag\n        id: ver\n        shell: bash\n        run: |\n          TAG=\"${GITHUB_REF_NAME}\"\n          VER=\"${TAG#preview-}\"\n          VER=\"${VER#v}\"\n          echo \"version=${VER}\" >> \"$GITHUB_OUTPUT\"\n          echo \"Publishing preview version: ${VER}\"\n\n      - name: Extract metadata\n        id: meta\n        uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0\n        with:\n          images: |\n            ${{ env.DOCKER_HUB }}\n            ghcr.io/${{ github.repository }}\n          tags: |\n            type=raw,value=preview-${{ steps.ver.outputs.version }}\n          labels: |\n            org.opencontainers.image.version=preview-${{ steps.ver.outputs.version }}\n            org.opencontainers.image.created=${{ steps.ts.outputs.TIMESTAMP }}\n\n      - name: Build & Push (multi-arch, single tag)\n        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2\n        with:\n          context: .\n          file: ./Dockerfile\n          platforms: linux/amd64,linux/arm64\n          push: true\n          build-args: |\n            COMMIT_TAG=${{ github.sha }}\n            BUILD_VERSION=${{ steps.ver.outputs.version }}\n            SOURCE_DATE_EPOCH=${{ steps.ts.outputs.TIMESTAMP }}\n          labels: ${{ steps.meta.outputs.labels }}\n          tags: ${{ steps.meta.outputs.tags }}\n          cache-from: |\n            type=gha,scope=linux/amd64\n            type=gha,scope=linux/arm64\n          cache-to: type=gha,mode=max\n          provenance: false\n"
  },
  {
    "path": ".github/workflows/rebuild-issue-index.yml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Rebuild Issue Index\n\non:\n  schedule:\n    - cron: \"0 3 * * *\"\n  workflow_dispatch:\n\npermissions: {}\n\nenv:\n  EMBEDDING_MODEL: ${{ vars.EMBEDDING_MODEL }}\n\njobs:\n  build-index:\n    runs-on: ubuntu-24.04\n    permissions:\n      issues: read\n      actions: write\n      contents: read\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n\n      - name: Pnpm Setup\n        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0\n\n      - name: Set up Node.js\n        uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0\n        with:\n          node-version-file: 'package.json'\n\n      - name: Get pnpm store directory\n        shell: bash\n        run: echo \"STORE_PATH=$(pnpm store path --silent)\" >> $GITHUB_ENV\n\n      - name: Setup pnpm cache\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0\n        with:\n          path: ${{ env.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n\n      - name: Install dependencies\n        working-directory: bin/duplicate-detector\n        env:\n          CI: true\n        run: pnpm install --frozen-lockfile\n\n      - name: Build issue index\n        working-directory: bin/duplicate-detector\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          GITHUB_REPOSITORY: ${{ github.repository }}\n          INDEX_PATH: issue_index.json\n        run: node build-index.mjs\n\n      - name: Upload index artifact\n        uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0\n        with:\n          name: issue-index\n          path: bin/duplicate-detector/issue_index.json\n          retention-days: 7\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Seerr Release\n\non:\n  push:\n    tags:\n      - 'v*'\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\nenv:\n  DOCKER_HUB: seerr/seerr\n\njobs:\n  changelog:\n    name: Generate changelog\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n    outputs:\n      release_body: ${{ steps.git-cliff.outputs.content }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Generate changelog\n        id: git-cliff\n        uses: orhun/git-cliff-action@c93ef52f3d0ddcdcc9bd5447d98d458a11cd4f72 # v4.7.1\n        with:\n          config: .github/cliff.toml\n          args: -vv --current\n        env:\n          OUTPUT: CHANGELOG.md\n          GITHUB_REPO: ${{ github.repository }}\n\n  create-draft-release:\n    name: Create draft release\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: write\n    needs: changelog\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Draft Release\n        run: gh release create ${GITHUB_REF_NAME} -t \"Release ${GITHUB_REF_NAME}\" -n \"${RELEASE_BODY}\" --draft\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          RELEASE_BODY: ${{ needs.changelog.outputs.release_body }}\n\n  build:\n    name: Build (${{ matrix.arch }})\n    strategy:\n      matrix:\n        include:\n          - runner: ubuntu-24.04\n            platform: linux/amd64\n            arch: amd64\n          - runner: ubuntu-24.04-arm\n            platform: linux/arm64\n            arch: arm64\n    runs-on: ${{ matrix.runner }}\n    env:\n      VERSION: ${{ github.ref_name }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Commit timestamp\n        id: ts\n        run: echo \"TIMESTAMP=$(git log -1 --pretty=%ct)\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0\n\n      - name: Warm cache [${{ matrix.platform }}]\n        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2\n        with:\n          context: .\n          file: ./Dockerfile\n          platforms: ${{ matrix.platform }}\n          push: false\n          build-args: |\n            COMMIT_TAG=${{ github.sha }}\n            BUILD_VERSION=${{ env.VERSION }}\n            SOURCE_DATE_EPOCH=${{ steps.ts.outputs.TIMESTAMP }}\n          cache-from: type=gha,scope=${{ matrix.platform }}\n          cache-to: type=gha,mode=max,scope=${{ matrix.platform }}\n          provenance: false\n\n  publish:\n    name: Publish multi-arch manifests\n    needs: build\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n      packages: write\n    outputs:\n      image_digest: ${{ steps.digests.outputs.IMAGE_DIGEST }}\n    env:\n      VERSION: ${{ github.ref_name }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Commit timestamp\n        id: ts\n        run: echo \"TIMESTAMP=$(git log -1 --pretty=%ct)\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0\n\n      - name: Log in to Docker Hub\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_TOKEN }}\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Extract metadata\n        id: meta\n        uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0\n        with:\n          images: |\n            ${{ env.DOCKER_HUB }}\n            ghcr.io/${{ github.repository }}\n          tags: |\n            type=raw,value=${{ env.VERSION }}\n          labels: |\n            org.opencontainers.image.created=${{ steps.ts.outputs.TIMESTAMP }}\n\n      - name: Build & Push (multi-arch)\n        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2\n        with:\n          context: .\n          file: ./Dockerfile\n          platforms: linux/amd64,linux/arm64\n          push: true\n          build-args: |\n            COMMIT_TAG=${{ github.sha }}\n            BUILD_VERSION=${{ env.VERSION }}\n            SOURCE_DATE_EPOCH=${{ steps.ts.outputs.TIMESTAMP }}\n          labels: ${{ steps.meta.outputs.labels }}\n          tags: ${{ steps.meta.outputs.tags }}\n          cache-from: |\n            type=gha,scope=linux/amd64\n            type=gha,scope=linux/arm64\n          cache-to: type=gha,mode=max\n          provenance: false\n\n      - name: Resolve manifest digest\n        id: digests\n        run: |\n          DIGEST=$(docker buildx imagetools inspect \"${{ env.DOCKER_HUB }}:${{ env.VERSION }}\" --format '{{json .Manifest.Digest}}' | tr -d '\"')\n          echo \"IMAGE_DIGEST=$DIGEST\" >> $GITHUB_OUTPUT\n\n      - name: Also tag :latest (non-pre-release only)\n        shell: bash\n        if: ${{ !contains(env.VERSION, '-') }}\n        run: |\n          docker buildx imagetools create \\\n            -t ${{ env.DOCKER_HUB }}:latest \\\n            ${{ env.DOCKER_HUB }}:${{ env.VERSION }}\n\n          docker buildx imagetools create \\\n            -t ghcr.io/${{ github.repository }}:latest \\\n            ghcr.io/${{ github.repository }}:${{ env.VERSION }}\n\n  sign:\n    name: Sign images and create SBOM attestations\n    needs: publish\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n      id-token: write\n      packages: write\n    env:\n      VERSION: ${{ github.ref_name }}\n      COSIGN_YES: 'true'\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          persist-credentials: false\n\n      - name: Install Cosign\n        uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0\n\n      - name: Install Trivy\n        uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514 # v0.2.5\n\n      - name: Log in to Docker Hub\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_TOKEN }}\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Sign images\n        run: |\n          cosign sign --recursive \"ghcr.io/${{ github.repository }}@${{ needs.publish.outputs.image_digest }}\"\n          cosign sign --recursive \"${{ env.DOCKER_HUB }}@${{ needs.publish.outputs.image_digest }}\"\n\n      - name: Generate SBOMs\n        run: |\n          trivy image --format cyclonedx --output seerr-ghcr-image-${{ env.VERSION }}.sbom \\\n            \"ghcr.io/${{ github.repository }}@${{ needs.publish.outputs.image_digest }}\"\n\n          trivy image --format cyclonedx --output seerr-dockerhub-image-${{ env.VERSION }}.sbom \\\n            \"${{ env.DOCKER_HUB }}@${{ needs.publish.outputs.image_digest }}\"\n\n      - name: Attest SBOMs\n        run: |\n          cosign attest \\\n            --type cyclonedx \\\n            --predicate seerr-ghcr-image-${{ env.VERSION }}.sbom \\\n            \"ghcr.io/${{ github.repository }}@${{ needs.publish.outputs.image_digest }}\"\n\n          cosign attest \\\n            --type cyclonedx \\\n            --predicate seerr-dockerhub-image-${{ env.VERSION }}.sbom \\\n            \"${{ env.DOCKER_HUB }}@${{ needs.publish.outputs.image_digest }}\"\n\n      - name: Upload SBOMs\n        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2\n        with:\n          name: sboms-${{ env.VERSION }}\n          path: '*.sbom'\n          if-no-files-found: error\n          retention-days: 1\n\n  verify:\n    name: Verify signatures and attestations\n    needs: [publish, sign]\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n    env:\n      VERSION: ${{ github.ref_name }}\n    steps:\n      - name: Install Cosign\n        uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0\n\n      - name: Verify signatures\n        run: |\n          cosign verify \"ghcr.io/${{ github.repository }}@${{ needs.publish.outputs.image_digest }}\" \\\n            --certificate-identity \"https://github.com/${{ github.workflow_ref }}\" \\\n            --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n\n          cosign verify \"${{ env.DOCKER_HUB }}@${{ needs.publish.outputs.image_digest }}\" \\\n            --certificate-identity \"https://github.com/${{ github.workflow_ref }}\" \\\n            --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n\n      # - name: Verify attestations\n      #   run: |\n      #     cosign verify-attestation \"ghcr.io/${{ github.repository }}@${{ needs.publish.outputs.image_digest }}\" \\\n      #       --type cyclonedx \\\n      #       --certificate-identity \"https://github.com/${{ github.workflow_ref }}\" \\\n      #       --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\" > /dev/null\n\n      #     cosign verify-attestation \"${{ env.DOCKER_HUB }}@${{ needs.publish.outputs.image_digest }}\" \\\n      #       --type cyclonedx \\\n      #       --certificate-identity \"https://github.com/${{ github.workflow_ref }}\" \\\n      #       --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\" > /dev/null\n\n  publish-release:\n    name: Publish release\n    needs: [create-draft-release, verify]\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: write\n    env:\n      VERSION: ${{ github.ref_name }}\n    steps:\n      - name: Publish release\n        run: gh release edit \"${{ env.VERSION }}\" --draft=false --repo \"${{ github.repository }}\"\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/renovate-helm-custom-hooks.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Renovate Helm Hooks\n\non:\n  pull_request:\n    branches:\n      - develop\n    paths:\n      - 'charts/**'\n\npermissions: {}\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  renovate-post-run:\n    name: Renovate Bump Chart Version\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      pull-requests: write\n    if: github.actor == 'renovate[bot]'\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1\n        id: app-token\n        with:\n          app-id: 2138788\n          private-key: ${{ secrets.APP_SEERR_HELM_PRIVATE_KEY }}\n\n      - name: Set up chart-testing\n        uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f # v2.8.0\n\n      - name: Run chart-testing (list-changed)\n        id: list-changed\n        run: |\n          changed=\"$(ct list-changed --target-branch ${TARGET_BRANCH})\"\n          if [[ -n \"$changed\" ]]; then\n            echo \"changed=true\" >> \"$GITHUB_OUTPUT\"\n            echo \"changed_list=${changed//$'\\n'/ }\" >> \"$GITHUB_OUTPUT\"\n          fi\n        env:\n          TARGET_BRANCH: ${{ github.event.repository.default_branch }}\n\n      - name: Bump chart version\n        if: steps.list-changed.outputs.changed == 'true'\n        env:\n          CHART: ${{ steps.list-changed.outputs.changed_list }}\n        run: |\n          if [[ ! -d \"${CHART}\" ]]; then\n            echo \"${CHART} directory not found\"\n            exit 0\n          fi\n\n          # Extract current appVersion and chart version from Chart.yaml\n          APP_VERSION=$(grep -e \"^appVersion:\" \"$CHART/Chart.yaml\" | cut -d \":\" -f 2 | tr -d '[:space:]' | tr -d '\"')\n          CHART_VERSION=$(grep -e \"^version:\" \"$CHART/Chart.yaml\" | cut -d \":\" -f 2 | tr -d '[:space:]' | tr -d '\"')\n\n          # Extract major, minor and patch versions of appVersion\n          APP_MAJOR_VERSION=$(printf '%s' \"$APP_VERSION\" | cut -d \".\" -f 1)\n          APP_MINOR_VERSION=$(printf '%s' \"$APP_VERSION\" | cut -d \".\" -f 2)\n          APP_PATCH_VERSION=$(printf '%s' \"$APP_VERSION\" | cut -d \".\" -f 3)\n\n          # Extract major, minor and patch versions of chart version\n          CHART_MAJOR_VERSION=$(printf '%s' \"$CHART_VERSION\" | cut -d \".\" -f 1)\n          CHART_MINOR_VERSION=$(printf '%s' \"$CHART_VERSION\" | cut -d \".\" -f 2)\n          CHART_PATCH_VERSION=$(printf '%s' \"$CHART_VERSION\" | cut -d \".\" -f 3)\n\n          # Get previous appVersion from the base commit of the pull request\n          BASE_COMMIT=$(git merge-base origin/main HEAD)\n          PREV_APP_VERSION=$(git show \"$BASE_COMMIT\":\"$CHART/Chart.yaml\" | grep -e \"^appVersion:\" | cut -d \":\" -f 2 | tr -d '[:space:]' | tr -d '\"')\n\n          # Extract major, minor and patch versions of previous appVersion\n          PREV_APP_MAJOR_VERSION=$(printf '%s' \"$PREV_APP_VERSION\" | cut -d \".\" -f 1)\n          PREV_APP_MINOR_VERSION=$(printf '%s' \"$PREV_APP_VERSION\" | cut -d \".\" -f 2)\n          PREV_APP_PATCH_VERSION=$(printf '%s' \"$PREV_APP_VERSION\" | cut -d \".\" -f 3)\n\n          # Check if the major, minor, or patch version of appVersion has changed\n          if [[ \"$APP_MAJOR_VERSION\" != \"$PREV_APP_MAJOR_VERSION\" ]]; then\n            # Bump major version of the chart and reset minor and patch versions to 0\n            CHART_MAJOR_VERSION=$((CHART_MAJOR_VERSION+1))\n            CHART_MINOR_VERSION=0\n            CHART_PATCH_VERSION=0\n          elif [[ \"$APP_MINOR_VERSION\" != \"$PREV_APP_MINOR_VERSION\" ]]; then\n            # Bump minor version of the chart and reset patch version to 0\n            CHART_MINOR_VERSION=$((CHART_MINOR_VERSION+1))\n            CHART_PATCH_VERSION=0\n          elif [[ \"$APP_PATCH_VERSION\" != \"$PREV_APP_PATCH_VERSION\" ]]; then\n            # Bump patch version of the chart\n            CHART_PATCH_VERSION=$((CHART_PATCH_VERSION+1))\n          fi\n\n          # Update the chart version in Chart.yaml\n          CHART_NEW_VERSION=\"${CHART_MAJOR_VERSION}.${CHART_MINOR_VERSION}.${CHART_PATCH_VERSION}\"\n          sed -i \"s/^version:.*/version: ${CHART_NEW_VERSION}/\" \"$CHART/Chart.yaml\"\n\n      - name: Ensure documentation is updated\n        if: steps.list-changed.outputs.changed == 'true'\n        uses: docker://jnorwood/helm-docs:v1.14.2@sha256:7e562b49ab6b1dbc50c3da8f2dd6ffa8a5c6bba327b1c6335cc15ce29267979c\n\n      - name: Commit changes\n        if: steps.list-changed.outputs.changed == 'true'\n        env:\n          CHART: ${{ steps.list-changed.outputs.changed_list }}\n          GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n        run: |\n          # Define the target directory\n          TARGET_DIR=\"$CHART\"\n\n          # Fetch deleted files in the target directory\n          DELETED_FILES=$(git diff --diff-filter=D --name-only HEAD -- \"$TARGET_DIR\")\n\n          # Fetch added/modified files in the target directory\n          MODIFIED_FILES=$(git diff --diff-filter=ACM --name-only HEAD -- \"$TARGET_DIR\")\n\n          # Create a temporary file for JSON output\n          FILE_CHANGES_JSON_FILE=$(mktemp)\n\n          # Initialize JSON structure in the file\n          echo '{ \"deletions\": [], \"additions\": [] }' > \"$FILE_CHANGES_JSON_FILE\"\n\n          # Add deletions\n          for file in $DELETED_FILES; do\n            jq --arg path \"$file\" '.deletions += [{\"path\": $path}]' \"$FILE_CHANGES_JSON_FILE\" > \"$FILE_CHANGES_JSON_FILE.tmp\"\n            mv \"$FILE_CHANGES_JSON_FILE.tmp\" \"$FILE_CHANGES_JSON_FILE\"\n          done\n\n          # Add additions (new or modified files)\n          for file in $MODIFIED_FILES; do\n            BASE64_CONTENT=$(base64 -w 0 <\"$file\")  # Encode file content\n            jq --arg path \"$file\" --arg content \"$BASE64_CONTENT\" \\\n              '.additions += [{\"path\": $path, \"contents\": $content}]' \"$FILE_CHANGES_JSON_FILE\" > \"$FILE_CHANGES_JSON_FILE.tmp\"\n            mv \"$FILE_CHANGES_JSON_FILE.tmp\" \"$FILE_CHANGES_JSON_FILE\"\n          done\n\n          # Create a temporary file for the final JSON payload\n          JSON_PAYLOAD_FILE=$(mktemp)\n\n          # Construct the final JSON using jq and store it in a file\n          jq -n --arg repo \"$GITHUB_REPOSITORY\" \\\n                --arg branch \"$GITHUB_HEAD_REF\" \\\n                --arg message \"fix: post upgrade changes from renovate\" \\\n                --arg expectedOid \"$GITHUB_SHA\" \\\n                --slurpfile fileChanges \"$FILE_CHANGES_JSON_FILE\" \\\n                '{\n                  query: \"mutation ($input: CreateCommitOnBranchInput!) {\n                    createCommitOnBranch(input: $input) {\n                      commit {\n                        url\n                      }\n                    }\n                  }\",\n                  variables: {\n                    input: {\n                      branch: {\n                        repositoryNameWithOwner: $repo,\n                        branchName: $branch\n                      },\n                      message: { headline: $message },\n                      fileChanges: $fileChanges[0],\n                      expectedHeadOid: $expectedOid\n                    }\n                  }\n                }' > \"$JSON_PAYLOAD_FILE\"\n\n          # Call GitHub API\n          curl https://api.github.com/graphql -f \\\n               -sSf -H \"Authorization: Bearer $GITHUB_TOKEN\" \\\n               --data \"@$JSON_PAYLOAD_FILE\"\n\n          # Clean up temporary files\n          rm \"$FILE_CHANGES_JSON_FILE\" \"$JSON_PAYLOAD_FILE\"\n"
  },
  {
    "path": ".github/workflows/seerr-labeller.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: 'Seerr Labeller'\n\non:\n  pull_request_target:\n    types: [labeled, unlabeled, reopened]\n  issues:\n    types: [labeled, unlabeled, reopened]\n\npermissions: {}\n\njobs:\n  ai-generated-support:\n    if: >\n      github.event_name == 'pull_request_target' &&\n      (github.event.label.name == 'ai-generated' || (github.event.action == 'reopened' && contains(github.event.pull_request.labels.*.name, 'ai-generated')))\n    runs-on: ubuntu-24.04\n    concurrency:\n      group: ai-generated-${{ github.event.pull_request.number }}\n      cancel-in-progress: true\n    permissions:\n      pull-requests: write\n    env:\n      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      GH_REPO: ${{ github.repository }}\n      NUMBER: ${{ github.event.pull_request.number }}\n      PR_AUTHOR: ${{ github.event.pull_request.user.login }}\n    steps:\n      - name: Label added, comment and close pull request\n        if: github.event.action == 'labeled' && github.event.label.name == 'ai-generated'\n        shell: bash\n        env:\n          BODY: >\n            :wave: @${{ env.PR_AUTHOR }}, thank you for your contribution!\n\n            However, this pull request has been closed because it appears to contain a significant amount of AI-generated code without sufficient human review or supervision.\n\n            AI-generated code can often introduce subtle bugs, poor design patterns, or inconsistent styles that make long-term maintenance difficult and reduce overall code quality. For the sake of the project's future stability and readability, we require that all contributions meet our established coding standards and demonstrate clear developer oversight.\n\n            This pull request is also too large for effective human review. Please discuss with us on how to break down these changes into smaller, more focused PRs to ensure a thorough and efficient review process.\n            If you'd like to revise and resubmit your changes with careful review and cleanup, we'd be happy to take another look.\n        run: |\n          retry() { n=0; until \"$@\"; do n=$((n+1)); [ $n -ge 3 ] && break; echo \"retry $n: $*\" >&2; sleep 2; done; }\n          retry gh pr comment \"$NUMBER\" -R \"$GH_REPO\" -b \"$BODY\" || true\n          retry gh pr close \"$NUMBER\" -R \"$GH_REPO\" || true\n          gh pr lock \"$NUMBER\" -R \"$GH_REPO\" -r \"spam\" || true\n\n      - name: Label removed, reopen and unlock pull request\n        if: github.event.action == 'unlabeled' && github.event.label.name == 'ai-generated'\n        shell: bash\n        run: |\n          retry() { n=0; until \"$@\"; do n=$((n+1)); [ $n -ge 3 ] && break; echo \"retry $n: $*\" >&2; sleep 2; done; }\n          retry gh pr reopen \"$NUMBER\" -R \"$GH_REPO\" || true\n          gh pr unlock \"$NUMBER\" -R \"$GH_REPO\" || true\n\n      - name: Remove AI-generated label on manual reopen\n        if: github.event.action == 'reopened'\n        shell: bash\n        run: |\n          gh pr edit \"$NUMBER\" -R \"$GH_REPO\" --remove-label \"ai-generated\" || true\n          gh pr unlock \"$NUMBER\" -R \"$GH_REPO\" || true\n\n  support:\n    if: >\n      github.event_name == 'issues' &&\n      (github.event.label.name == 'support' ||\n      (github.event.action == 'reopened' && contains(github.event.issue.labels.*.name, 'support')))\n    runs-on: ubuntu-24.04\n    concurrency:\n      group: support-${{ github.event.issue.number }}\n      cancel-in-progress: true\n    permissions:\n      issues: write\n    env:\n      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      GH_REPO: ${{ github.repository }}\n      NUMBER: ${{ github.event.issue.number }}\n      ISSUE_AUTHOR: ${{ github.event.issue.user.login }}\n    steps:\n      - name: Label added, comment and close issue\n        if: github.event.action == 'labeled' && github.event.label.name == 'support'\n        shell: bash\n        env:\n          BODY: >\n            :wave: @${{ env.ISSUE_AUTHOR }}, we use the issue tracker exclusively\n            for bug reports and feature requests. However, this issue appears\n            to be a support request. Please use our support channels\n            to get help with Seerr.\n\n            - [Discord](https://discord.gg/seerr)\n        run: |\n          retry() { n=0; until \"$@\"; do n=$((n+1)); [ $n -ge 3 ] && break; echo \"retry $n: $*\" >&2; sleep 2; done; }\n          retry gh issue comment \"$NUMBER\" -R \"$GH_REPO\" -b \"$BODY\" || true\n          retry gh issue close \"$NUMBER\" -R \"$GH_REPO\" || true\n          gh issue lock \"$NUMBER\" -R \"$GH_REPO\" -r \"off_topic\" || true\n\n      - name: Label removed, reopen and unlock issue\n        if: github.event.action == 'unlabeled' && github.event.label.name == 'support'\n        shell: bash\n        run: |\n          retry() { n=0; until \"$@\"; do n=$((n+1)); [ $n -ge 3 ] && break; echo \"retry $n: $*\" >&2; sleep 2; done; }\n          retry gh issue reopen \"$NUMBER\" -R \"$GH_REPO\" || true\n          gh issue unlock \"$NUMBER\" -R \"$GH_REPO\" || true\n\n      - name: Remove support label on manual reopen\n        if: github.event.action == 'reopened'\n        shell: bash\n        run: |\n          gh issue edit \"$NUMBER\" -R \"$GH_REPO\" --remove-label \"support\" || true\n          gh issue unlock \"$NUMBER\" -R \"$GH_REPO\" || true\n"
  },
  {
    "path": ".github/workflows/semantic-pr.yml",
    "content": "name: \"Semantic PR\"\n\non:\n  pull_request_target:\n    types:\n      - opened\n      - reopened\n      - edited\n      - synchronize\n\npermissions: {}\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  main:\n    name: Validate PR Title\n    runs-on: ubuntu-slim\n    permissions:\n      contents: read\n      pull-requests: read\n      checks: write\n    steps:\n      - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Close Stale Issues and PRs\n\non:\n  schedule:\n    - cron: '0 7 * * *'\n\npermissions: {}\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  stale:\n    name: Close stale issues and PRs\n    runs-on: ubuntu-24.04\n    permissions:\n      actions: write\n      issues: write\n      pull-requests: write\n    steps:\n      - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0\n        with:\n          any-of-labels: \"pending author's response\"\n          exempt-issue-labels: 'confirmed'\n          days-before-stale: 30\n          days-before-close: 30\n          stale-issue-label: 'stale'\n          stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Please provide an update or the requested information to keep it open.'\n          close-issue-message: 'This issue was closed because it has been stalled for 30 days with no activity. Feel free to reopen it once you provide the required update or information.'\n          stale-pr-label: 'stale'\n          stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Please address the feedback or provide an update to keep it open.'\n          close-pr-message: 'This PR was closed because it has been stalled for 30 days with no activity. You can reopen it once you address the feedback or provide the requested changes.'\n"
  },
  {
    "path": ".github/workflows/test-docs-deploy.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Test Docs deployment\n\non:\n  pull_request:\n    branches:\n      - develop\n    paths:\n      - 'docs/**'\n      - 'gen-docs/**'\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  test-deploy:\n    name: Test deployment\n    runs-on: ubuntu-24.04\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Set up Node.js\n        uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0\n        with:\n          node-version-file: package.json\n          package-manager-cache: false\n\n      - name: Pnpm Setup\n        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0\n\n      - name: Get pnpm store directory\n        shell: sh\n        run: |\n          echo \"STORE_PATH=$(pnpm store path --silent)\" >> $GITHUB_ENV\n\n      - name: Setup pnpm cache\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0\n        with:\n          path: ${{ env.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n\n      - name: Install dependencies\n        run: |\n          cd gen-docs\n          pnpm install --frozen-lockfile\n\n      - name: Build website\n        run: |\n          cd gen-docs\n          pnpm build\n"
  },
  {
    "path": ".github/workflows/trivy-scan.yml",
    "content": "---\n# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Trivy Container Vulnerability Scan\n\non:\n  workflow_run:\n    workflows:\n      - Seerr Release\n    types:\n      - completed\n  schedule:\n    - cron: '50 7 * * 5'\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  trivy:\n    if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}\n    name: Scan latest container image\n    runs-on: ubuntu-24.04\n\n    permissions:\n      contents: read\n      security-events: write\n\n    env:\n      TRIVY_CACHE_DIR: .trivycache\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Cache Trivy DB\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0\n        with:\n          path: .trivycache\n          key: trivy-${{ runner.os }}-${{ hashFiles('**/Dockerfile') }}\n          restore-keys: |\n            trivy-${{ runner.os }}-\n\n      - name: Run Trivy image scan\n        uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0\n        with:\n          image-ref: ghcr.io/${{ github.repository }}:latest\n          format: sarif\n          output: trivy.sarif\n          ignore-unfixed: true\n\n      - name: Upload SARIF to code scanning\n        uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6\n        with:\n          sarif_file: trivy.sarif\n"
  },
  {
    "path": ".gitignore",
    "content": "# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\nlcov.info\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# local env files\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# vercel\n.vercel\n\n# database\nconfig/db/*.sqlite3*\nconfig/settings.json\nconfig/settings.old.json\n\n# logs\nconfig/logs/*.log*\nconfig/logs/*.json\nconfig/logs/*.log.gz\nconfig/logs/*.json.gz\nconfig/logs/*-audit.json\n\n# anidb mapping file\nconfig/anime-list.xml\n\n# dist files\ndist\n\n# sqlite journal\nconfig/db/db.sqlite3-journal\n\n# VS Code\n.vscode/launch.json\n\n# Cypress\ncypress.env.json\ncypress/videos\ncypress/screenshots\n\n# ESLint\n.eslintcache\n\n# TS Build Info\ntsconfig.tsbuildinfo\n\n# Webstorm\n.idea\n\n# Config Cache Directory\nconfig/cache\n\n# Docker compose\ncompose.override.yaml\n"
  },
  {
    "path": ".husky/commit-msg",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\n[ -n \"$HUSKY_BYPASS\" ] || npx commitlint --edit $1\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx lint-staged\n"
  },
  {
    "path": ".husky/prepare-commit-msg",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nexec < /dev/tty && npx cz --hook || true\n"
  },
  {
    "path": ".npmrc",
    "content": "engine-strict=true\n"
  },
  {
    "path": ".prettierignore",
    "content": "# Generated files which we would not like to format\n.next/\ndist/\nconfig/\ncache/config.json\npnpm-lock.yaml\ncypress/config/settings.cypress.json\n.github\n.vscode\n\n# assets\nsrc/assets/\ndocs/\npublic/*\n!public/sw.js\n\n# helm charts\n**/charts\n\n# Prettier breaks GitHub alert syntax in markdown\n*.md\n"
  },
  {
    "path": ".prettierrc.js",
    "content": "module.exports = {\n  plugins: ['prettier-plugin-organize-imports', 'prettier-plugin-tailwindcss'],\n  singleQuote: true,\n  trailingComma: 'es5',\n  overrides: [\n    {\n      files: 'pnpm-lock.yaml',\n      options: {\n        rangeEnd: 0, // default: Infinity\n      },\n    },\n    {\n      files: 'gen-docs/pnpm-lock.yaml',\n      options: {\n        rangeEnd: 0, // default: Infinity\n      },\n    },\n    {\n      files: 'charts/**',\n      options: {\n        rangeEnd: 0, // default: Infinity\n      },\n    },\n    {\n      files: 'cypress/config/settings.cypress.json',\n      options: {\n        rangeEnd: 0,\n      },\n    },\n    {\n      files: 'public/offline.html',\n      options: {\n        rangeEnd: 0,\n      },\n    },\n    {\n      files: 'cache/config.json',\n      options: {\n        rangeEnd: 0, // default: Infinity\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  // see\n  //  - https://code.visualstudio.com/docs/editor/extension-gallery#_workspace-recommended-extensions\n  \"recommendations\": [\n    // https://marketplace.visualstudio.com/items?itemName=EditorConfig.editorconfig\n    \"EditorConfig.editorconfig\",\n\n    // https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint\n    \"dbaeumer.vscode-eslint\",\n\n    // https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode\n    \"esbenp.prettier-vscode\",\n\n    // https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest\n    \"Orta.vscode-jest\",\n\n    \"stylelint.vscode-stylelint\",\n\n    \"bradlc.vscode-tailwindcss\",\n    \"firsttris.vscode-jest-runner\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"eslint.enable\": true,\n  \"eslint.validate\": [\n    \"javascript\",\n    \"javascriptreact\",\n    \"typescript\",\n    \"typescriptreact\"\n  ],\n  \"typescript.tsdk\": \"node_modules/typescript/lib\",\n  \"sqltools.connections\": [\n    {\n      \"previewLimit\": 50,\n      \"driver\": \"SQLite\",\n      \"name\": \"Local SQLite\",\n      \"database\": \"./config/db/db.sqlite3\"\n    }\n  ],\n  \"editor.formatOnSave\": true,\n  \"typescript.preferences.importModuleSpecifier\": \"non-relative\",\n  \"files.associations\": {\n    \"globals.css\": \"tailwindcss\"\n  },\n  \"i18n-ally.localesPaths\": [\n    \"src/i18n/locale\"\n  ],\n  \"yaml.format.singleQuote\": true,\n  \"jestrunner.enableTestExplorer\": true,\n  \"jestrunner.defaultTestPatterns\": [\n    \"server/**/*.{test,spec}.?(c|m)[jt]s?(x)\",\n  ],\n  \"jestrunner.nodeTestCommand\": \"pnpm test\",\n  \"jestrunner.changeDirectoryToWorkspaceRoot\": true,\n  \"jestrunner.projectPath\": \".\"\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n- Demonstrating empathy and kindness toward other people\n- Being respectful of differing opinions, viewpoints, and experiences\n- Giving and gracefully accepting constructive feedback\n- Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n- Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n- The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n- Trolling, insulting or derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n[ryan@sct.dev](mailto:ryan@sct.dev).\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\n[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][mozilla coc].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][faq]. Translations are available\nat [https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html\n[mozilla coc]: https://github.com/mozilla/diversity\n[faq]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Seerr\n\nAll help is welcome and greatly appreciated! If you would like to contribute to the project, the following instructions should get you started...\n\n## AI Assistance Notice\n\n> [!IMPORTANT]\n>\n> Automated AI-generated contributions without human review are not allowed and will be rejected.\n> This is an open-source project maintained by volunteers.\n> We do not have the resources to review pull requests that could have been avoided with proper human oversight.\n> While we have no issue with contributors using AI tools as an aid, it is your responsibility as a contributor to ensure that all submissions are carefully reviewed and meet our quality standards.\n> Submissions that appear to be unreviewed AI output will be considered low-effort and may result in a ban.\n>\n> If you are using **any kind of AI assistance** to contribute to Seerr,\n> it must be disclosed in the pull request.\n\nIf you are using any kind of AI assistance while contributing to Seerr,\n**this must be disclosed in the pull request**, along with the extent to\nwhich AI assistance was used (e.g. docs only vs. code generation).\nIf PR responses are being generated by an AI, disclose that as well.\nAs a small exception, trivial tab-completion doesn't need to be disclosed,\nso long as it is limited to single keywords or short phrases.\n\nAn example disclosure:\n\n> This PR was written primarily by Claude Code.\n\nOr a more detailed disclosure:\n\n> I consulted ChatGPT to understand the codebase but the solution\n> was fully authored manually by myself.\n\nFailure to disclose this is first and foremost rude to the human operators\non the other end of the pull request, but it also makes it difficult to\ndetermine how much scrutiny to apply to the contribution.\n\nIn a perfect world, AI assistance would produce equal or higher quality\nwork than any human. That isn't the world we live in today, and in most cases\nit's generating slop. I say this despite being a fan of and using them\nsuccessfully myself (with heavy supervision)!\n\nWhen using AI assistance, we expect contributors to understand the code\nthat is produced and be able to answer critical questions about it. It\nisn't a maintainers job to review a PR so broken that it requires\nsignificant rework to be acceptable.\n\nPlease be respectful to maintainers and disclose AI assistance.\n\n## Development\n\n### Tools Required\n\n- HTML/Typescript/Javascript editor\n- [VSCode](https://code.visualstudio.com/) is recommended. Upon opening the project, a few extensions will be automatically recommended for install.\n- [NodeJS](https://nodejs.org/en/download/) (Node 22.x)\n- [Pnpm](https://pnpm.io/cli/install)\n- [Git](https://git-scm.com/downloads)\n\n### Getting Started\n\n1. [Fork](https://help.github.com/articles/fork-a-repo/) the repository to your own GitHub account and [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device:\n\n   ```bash\n   git clone https://github.com/YOUR_USERNAME/seerr.git\n   cd seerr/\n   ```\n\n2. Add the remote `upstream`:\n\n   ```bash\n   git remote add upstream https://github.com/seerr-team/seerr.git\n   ```\n\n3. Create a new branch:\n\n   ```bash\n   git switch -c BRANCH_NAME develop\n   ```\n\n   - It is recommended to give your branch a meaningful name, relevant to the feature or fix you are working on.\n     - Good examples:\n       - `docs-docker`\n       - `feature-new-system`\n       - `fix-title-cards`\n     - Bad examples:\n       - `bug`\n       - `docs`\n       - `feature`\n       - `fix`\n       - `patch`\n\n4. Run the development environment:\n\n   ```bash\n   pnpm install\n   pnpm dev\n   ```\n\n   - Alternatively, you can use [Docker](https://www.docker.com/) with `docker compose up -d`. This method does not require installing NodeJS or Yarn on your machine directly.\n\n5. Create your patch and test your changes.\n\n   - Be sure to follow both the [code](#contributing-code) and [UI text](#ui-text-style) guidelines.\n   - Should you need to update your fork, you can do so by rebasing from `upstream`:\n\n     ```bash\n     git fetch upstream\n     git rebase upstream/develop\n     git push origin BRANCH_NAME -f\n     ```\n\n### Helm Chart\n\nTools Required:\n\n- [Helm](https://helm.sh/docs/intro/install/)\n- [helm-docs](https://github.com/norwoodj/helm-docs)\n\nSteps:\n\n1. Make the necessary changes.\n2. Test your changes.\n3. Update the `version` in `charts/seerr-chart/Chart.yaml` following [Semantic Versioning (SemVer)](https://semver.org/).\n4. Run the `helm-docs` command to regenerate the chart's README.\n\n### Contributing Code\n\n- If you are taking on an existing bug or feature ticket, please comment on the [issue](/../../issues) to avoid multiple people working on the same thing.\n- Pull requests with titles not following [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) will **not** be merged. PR titles are automatically checked for compliance.\n- Please make meaningful commits, or squash them prior to opening a pull request.\n  - Do not squash commits once people have begun reviewing your changes.\n- Always rebase your branch to the latest `develop` branch.\n- It is your responsibility to keep your branch up-to-date. Your work will **not** be merged unless it is rebased off the latest `develop` branch.\n- You can create a \"draft\" pull request early to get feedback on your work.\n- Your code **must** be formatted correctly, or the tests will fail.\n  - We use Prettier to format our code base. It should automatically run with a Git hook, but it is recommended to have the Prettier extension installed in your editor and format on save.\n- If you have questions or need help, you can reach out via [Discussions](/../../discussions) or our [Discord server](https://discord.gg/seerr).\n- Only open pull requests to `develop`, never `master`! Any pull requests opened to `master` will be closed.\n\n### UI Text Style\n\nWhen adding new UI text, please try to adhere to the following guidelines:\n\n1. Be concise and clear, and use as few words as possible to make your point.\n2. Use the Oxford comma where appropriate.\n3. Use the appropriate Unicode characters for ellipses, arrows, and other special characters/symbols.\n4. Capitalize proper nouns, such as Plex, Radarr, Sonarr, Telegram, Slack, Pushover, etc. Be sure to also use the official capitalization for any abbreviations; e.g., IMDb has a lowercase 'b', whereas TMDB and TheTVDB have a capital 'B'.\n5. Title case headings, button text, and form labels. Note that verbs such as \"is\" should be capitalized, whereas prepositions like \"from\" should be lowercase (unless as the first or last word of the string, in which case they are also capitalized).\n6. Capitalize the first word in validation error messages, dropdowns, and form \"tips.\" These strings should not end in punctuation.\n7. Ensure that toast notification strings are complete sentences ending in punctuation.\n8. If an additional description or \"tip\" is required for a form field, it should be styled using the global CSS class `label-tip`.\n9. In full sentences, abbreviations like \"info\" or \"auto\" should not be used in place of full words, unless referencing the name/label of a specific setting or option which has an abbreviation in its name.\n10. Do your best to check for spelling errors and grammatical mistakes.\n11. Do not misspell \"Seerr.\"\n\n## Translation\n\nWe use [Weblate](https://translate.seerr.dev/projects/seerr/seerr-frontend/) for our translations, and your help with localizing Seerr would be greatly appreciated! If your language is not listed below, please [open a feature request](/../../issues/new/choose).\n\n<a href=\"https://translate.seerr.dev/engage/seerr/\"><img src=\"https://translate.seerr.dev/widget/seerr/multi-auto.svg\" alt=\"Translation status\" /></a>\n\n## Migrations\n\nIf you are adding a new feature that requires a database migration, you will need to create 2 migrations: one for SQLite and one for PostgreSQL. Here is how you could do it:\n\n1. Create a PostgreSQL database or use an existing one:\n\n```bash\nsudo docker run --name postgres-seerr -e POSTGRES_PASSWORD=postgres -d -p 127.0.0.1:5432:5432/tcp postgres:latest\n```\n\n2. Reset the SQLite database and the PostgreSQL database:\n\n```bash\nrm config/db/db.*\nrm config/settings.*\nPGPASSWORD=postgres sudo docker exec -it postgres-seerr /usr/bin/psql -h 127.0.0.1 -U postgres -c \"DROP DATABASE IF EXISTS seerr;\"\nPGPASSWORD=postgres sudo docker exec -it postgres-seerr /usr/bin/psql -h 127.0.0.1 -U postgres -c \"CREATE DATABASE seerr;\"\n```\n\n3. Switch to the `develop` branch and create the original database for SQLite and PostgreSQL so that TypeORM can automatically generate the migrations:\n\n```bash\ngit switch develop\npnpm i\nrm -r .next dist; pnpm build\npnpm start\nDB_TYPE=\"postgres\" DB_USER=postgres DB_PASS=postgres pnpm start\n```\n\n(You can shutdown the server once the message \"Server ready on 5055\" appears)\n\n4. Let TypeORM generate the migrations:\n\n```bash\ngit switch -c your-feature-branch\npnpm i\npnpm migration:generate server/migration/sqlite/YourMigrationName\nDB_TYPE=\"postgres\" DB_USER=postgres DB_PASS=postgres pnpm migration:generate server/migration/postgres/YourMigrationName\n```\n\n## Attribution\n\nThis contribution guide was inspired by the [Next.js](https://github.com/vercel/next.js), [Radarr](https://github.com/Radarr/Radarr), and [Ghostty](https://github.com/ghostty-org/ghostty) contribution guides.\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM node:22.22.0-alpine3.22@sha256:7aa86fa052f6e4b101557ccb56717cb4311be1334381f526fe013418fe157384 AS base\nARG SOURCE_DATE_EPOCH\nARG TARGETPLATFORM\nENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}\n\nENV PNPM_HOME=\"/pnpm\"\nENV PATH=\"$PNPM_HOME:$PATH\"\nRUN corepack enable\n\nCOPY . ./app\nWORKDIR /app\n\nFROM base AS prod-deps\nRUN --mount=type=cache,id=pnpm,target=/pnpm/store CI=true pnpm install --prod --frozen-lockfile\n\nFROM base AS build\n\nARG COMMIT_TAG\nENV COMMIT_TAG=${COMMIT_TAG}\n\nRUN \\\n  case \"${TARGETPLATFORM}\" in \\\n  'linux/arm64' | 'linux/arm/v7') \\\n  apk update && \\\n  apk add --no-cache python3 make g++ gcc libc6-compat bash && \\\n  npm install --global node-gyp \\\n  ;; \\\n  esac\n\nRUN --mount=type=cache,id=pnpm,target=/pnpm/store CYPRESS_INSTALL_BINARY=0 pnpm install --frozen-lockfile\n\nRUN pnpm build\n\nRUN rm -rf .next/cache\n\nFROM node:22.22.0-alpine3.22@sha256:7aa86fa052f6e4b101557ccb56717cb4311be1334381f526fe013418fe157384\nARG SOURCE_DATE_EPOCH\nARG COMMIT_TAG\nENV NODE_ENV=production\nENV COMMIT_TAG=${COMMIT_TAG}\n\nRUN apk add --no-cache tzdata\n\nUSER node:node\n\nWORKDIR /app\n\nCOPY --chown=node:node . .\nCOPY --chown=node:node --from=prod-deps /app/node_modules ./node_modules\nCOPY --chown=node:node --from=build /app/.next ./.next\nCOPY --chown=node:node --from=build /app/dist ./dist\n\nRUN touch config/DOCKER && \\\n  echo \"{\\\"commitTag\\\": \\\"${COMMIT_TAG}\\\"}\" > committag.json\n\nEXPOSE 5055\n\nCMD [ \"npm\", \"start\" ]\n"
  },
  {
    "path": "Dockerfile.local",
    "content": "FROM node:22.22.0-alpine3.22@sha256:7aa86fa052f6e4b101557ccb56717cb4311be1334381f526fe013418fe157384\n\nENV PNPM_HOME=\"/pnpm\"\nENV PATH=\"$PNPM_HOME:$PATH\"\nRUN corepack enable\n\nCOPY . /app\nWORKDIR /app\n\nRUN pnpm install\n\nCMD pnpm dev\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 sct\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n<img src=\"./public/logo_full.svg\" alt=\"Seerr\" style=\"margin: 20px 0;\">\n</p>\n<p align=\"center\">\n<img src=\"https://github.com/seerr-team/seerr/actions/workflows/release.yml/badge.svg\" alt=\"Seerr Release\" />\n<img src=\"https://github.com/seerr-team/seerr/actions/workflows/ci.yml/badge.svg\" alt=\"Seerr CI\">\n</p>\n<p align=\"center\">\n<a href=\"https://discord.gg/seerr\"><img src=\"https://img.shields.io/discord/783137440809746482\" alt=\"Discord\"></a>\n<a href=\"https://hub.docker.com/r/seerr/seerr\"><img src=\"https://img.shields.io/docker/pulls/seerr/seerr\" alt=\"Docker pulls\"></a>\n<a href=\"https://translate.seerr.dev/engage/seerr/\"><img src=\"https://translate.seerr.dev/widget/seerr/svg-badge.svg\" alt=\"Translation status\" /></a>\n<a href=\"https://github.com/seerr-team/seerr/blob/develop/LICENSE\"><img alt=\"GitHub\" src=\"https://img.shields.io/github/license/seerr-team/seerr\"></a>\n\n**Seerr** is a free and open source software application for managing requests for your media library. It integrates with the media server of your choice: [Jellyfin](https://jellyfin.org), [Plex](https://plex.tv), and [Emby](https://emby.media/). In addition, it integrates with your existing services, such as **[Sonarr](https://sonarr.tv/)**, **[Radarr](https://radarr.video/)**.\n\n## Current Features\n\n- Full Jellyfin/Emby/Plex integration including authentication with user import & management.\n- Support for **PostgreSQL** and **SQLite** databases.\n- Supports Movies, Shows and Mixed Libraries.\n- Ability to change email addresses for SMTP purposes.\n- Easy integration with your existing services. Currently, Seerr supports Sonarr and Radarr. More to come!\n- Jellyfin/Emby/Plex library scan, to keep track of the titles which are already available.\n- Customizable request system, which allows users to request individual seasons or movies in a friendly, easy-to-use interface.\n- Incredibly simple request management UI. Don't dig through the app to simply approve recent requests!\n- Granular permission system.\n- Support for various notification agents.\n- Mobile-friendly design, for when you need to approve requests on the go!\n- Support for watchlisting & blocklisting media.\n\nWith more features on the way! Check out our [issue tracker](/../../issues) to see the features which have already been requested.\n\n## Getting Started\n\nCheck out our documentation for instructions on how to install and run Seerr:\n\nhttps://docs.seerr.dev/getting-started/\n\n## Preview\n\n<img src=\"./public/preview.jpg\" alt=\"Seerr application preview\" />\n\n## Migrating from Overseerr/Jellyseerr to Seerr\n\nRead our [release announcement](https://docs.seerr.dev/blog/seerr-release) to learn what Seerr means for Jellyseerr and Overseerr users.\n\nPlease follow our [migration guide](https://docs.seerr.dev/migration-guide) for detailed instructions on migrating from Overseerr or Jellyseerr.\n\n## Support\n\n- Check out the [Seerr Documentation](https://docs.seerr.dev) before asking for help. Your question might already be in the docs!\n- You can get support on [Discord](https://discord.gg/seerr).\n- You can ask questions in the Help category of our [GitHub Discussions](/../../discussions).\n- Bug reports and feature requests can be submitted via [GitHub Issues](/../../issues).\n\n## API Documentation\n\nYou can access the API documentation from your local Seerr install at http://localhost:5055/api-docs\n\n## Community\n\nYou can ask questions, share ideas, and more in [GitHub Discussions](/../../discussions).\n\nIf you would like to chat with other members of our growing community, [join the Seerr Discord server](https://discord.gg/seerr)!\n\nOur [Code of Conduct](./CODE_OF_CONDUCT.md) applies to all Seerr community channels.\n\n## Contributing\n\nYou can help improve Seerr too! Check out our [Contribution Guide](./CONTRIBUTING.md) to get started.\n\n## Contributors ✨\n\n[![Contributors](https://opencollective.com/seerr/contributors.svg?width=890)](https://opencollective.com/seerr/#backers)\n\n[![Become a Backer](https://opencollective.com/seerr/backers.svg)](https://opencollective.com/seerr/#backers)\n[![Become a Sponsor](https://opencollective.com/seerr/sponsors.svg)](https://opencollective.com/seerr/#sponsors)\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Reporting Security Issues\n\nMaintainers and community take security bugs seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.\n\nTo report a security issue, please use the GitHub Security Advisory [\"Report a Vulnerability\"](../../security/advisories/new) tab.\n\n**Please do not report security vulnerabilities through public GitHub issues, discussions, or Discord.**\n\n## AI Assistance Notice\n\n> [!IMPORTANT]\n>\n> Automated AI-generated contributions without human review are not allowed and will be rejected.\n> This is an open-source project maintained by volunteers.\n> We do not have the resources to review pull requests that could have been avoided with proper human oversight.\n> While we have no issue with contributors using AI tools as an aid, it is your responsibility as a contributor to ensure that all submissions are carefully reviewed and meet our quality standards.\n> Submissions that appear to be unreviewed AI output will be considered low-effort and may result in a ban.\n>\n> If you are using **any kind of AI assistance** to contribute to Seerr,\n> it must be disclosed in the pull request.\n\nIf you are using any kind of AI assistance while contributing to Seerr,\n**this must be disclosed in the pull request**, along with the extent to\nwhich AI assistance was used (e.g. docs only vs. code generation).\nIf security advisory responses are being generated by an AI, disclose that as well.\nAs a small exception, trivial tab-completion doesn't need to be disclosed,\nso long as it is limited to single keywords or short phrases.\n\nAn example disclosure:\n\n> This security advisory was written primarily by Claude Code.\n\nOr a more detailed disclosure:\n\n> I consulted ChatGPT to understand the codebase but the solution\n> was fully authored manually by myself.\n\nFailure to disclose this is first and foremost rude to the human operators\non the other end of the pull request, but it also makes it difficult to\ndetermine how much scrutiny to apply to the contribution.\n\nIn a perfect world, AI assistance would produce equal or higher quality\nwork than any human. That isn't the world we live in today, and in most cases\nit's generating slop. I say this despite being a fan of and using them\nsuccessfully myself (with heavy supervision)!\n\nWhen using AI assistance, we expect contributors to understand the code\nthat is produced and be able to answer critical questions about it. It\nisn't a maintainers job to review a PR so broken that it requires\nsignificant rework to be acceptable.\n\nPlease be respectful to maintainers and disclose AI assistance.\n\n## What to Include in Your Report\n\nTo help us better understand and resolve the issue, please include as much of the following information as possible:\n\n- Full paths of source file(s) related to the manifestation of the issue\n- The location of the affected source code (tag/branch/commit or direct URL)\n- Any special configuration required to reproduce the issue\n- Step-by-step instructions to reproduce the issue\n- Proof-of-concept or exploit code (if possible)\n- Impact of the issue\n\n## Response Timeline\n\nWe will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.\n\n## Disclosure Policy\n\n- Security issues will be disclosed in a coordinated manner\n- We will credit reporters in the security advisory unless anonymity is requested\n- We request that you do not publicly disclose the issue until we have released a fix\n\n## Third-Party Dependencies\n\nIf you discover a security vulnerability in a third-party dependency used by Seerr, please report it directly to the maintainers of that module. You can also notify us through our security advisory process so we can:\n\n- Track the issue and monitor for updates\n- Apply patches or workarounds if available\n- Coordinate with upstream maintainers when necessary\n- Communicate the impact to our users\n\nWe regularly monitor and update our dependencies to address known security vulnerabilities.\n\n## Security Updates\n\nSecurity updates and advisories will be published on our [GitHub Security Advisories page](../../security/advisories).\n\n## Community\n\nFor general questions and support (non-security related):\n\n- [GitHub Discussions](../../discussions)\n- [Discord](https://discord.gg/seerr)\n"
  },
  {
    "path": "bin/check-i18n.js",
    "content": "#!/usr/bin/env node\n\n/**\n * Check that i18n locale files are in sync with extracted messages.\n * Runs `pnpm i18n:extract` and compares en.json; exits 1 if they differ.\n */\nconst { execSync } = require('child_process');\nconst fs = require('fs');\nconst path = require('path');\n\nconst localePath = path.join(\n  __dirname,\n  '..',\n  'src',\n  'i18n',\n  'locale',\n  'en.json'\n);\nconst backupPath = `${localePath}.bak`;\n\ntry {\n  fs.copyFileSync(localePath, backupPath);\n  execSync('pnpm i18n:extract', { stdio: 'inherit' });\n  const original = fs.readFileSync(backupPath, 'utf8');\n  const extracted = fs.readFileSync(localePath, 'utf8');\n  fs.unlinkSync(backupPath);\n\n  if (original !== extracted) {\n    console.error(\n      \"i18n messages are out of sync. Please run 'pnpm i18n:extract' and commit the changes.\"\n    );\n    process.exit(1);\n  }\n} catch (err) {\n  if (fs.existsSync(backupPath)) {\n    fs.unlinkSync(backupPath);\n  }\n  throw err;\n}\n"
  },
  {
    "path": "bin/duplicate-detector/.gitignore",
    "content": "node_modules/\n"
  },
  {
    "path": "bin/duplicate-detector/build-index.mjs",
    "content": "#!/usr/bin/env node\n/**\n * Build Issue Embedding Index\n *\n * Fetches all open issues and recently closed ones,\n * generates embeddings using a local ONNX transformer model,\n * and saves them as a JSON artifact for the duplicate detector.\n */\n\nimport { pipeline } from '@huggingface/transformers';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport { fetchIssues, issueText } from './utils.mjs';\n\nconst MODEL_NAME = process.env.EMBEDDING_MODEL || 'Xenova/all-MiniLM-L6-v2';\nconst OUTPUT_PATH = 'issue_index.json';\nconst INCLUDE_CLOSED_DAYS = 90;\nconst MAX_ISSUES = 5000;\nconst BATCH_SIZE = 64;\n\nasync function main() {\n  console.log('Fetching open issues...');\n  const openIssues = await fetchIssues({\n    state: 'open',\n    maxIssues: MAX_ISSUES,\n  });\n  console.log(`Fetched ${openIssues.length} open issues`);\n\n  const since = new Date(\n    Date.now() - INCLUDE_CLOSED_DAYS * 24 * 60 * 60 * 1000\n  ).toISOString();\n  console.log(\n    `Fetching closed issues from last ${INCLUDE_CLOSED_DAYS} days...`\n  );\n\n  const closedIssues = await fetchIssues({\n    state: 'closed',\n    since,\n    maxIssues: MAX_ISSUES,\n  });\n  console.log(`Fetched ${closedIssues.length} closed issues`);\n  let allIssues = [...openIssues, ...closedIssues];\n\n  const seen = new Set();\n  allIssues = allIssues.filter((issue) => {\n    if (seen.has(issue.number)) return false;\n    seen.add(issue.number);\n    return true;\n  });\n\n  console.log(`Total unique issues to index: ${allIssues.length}`);\n\n  if (allIssues.length === 0) {\n    console.warn('No issues found - writing empty index');\n    writeFileSync(OUTPUT_PATH, JSON.stringify({ issues: [], embeddings: [] }));\n    return;\n  }\n\n  console.log(`Loading model: ${MODEL_NAME}`);\n  const extractor = await pipeline('feature-extraction', MODEL_NAME, {\n    dtype: 'fp32',\n  });\n\n  const texts = allIssues.map((issue) => issueText(issue.title, issue.body));\n  const allEmbeddings = [];\n\n  console.log(`Generating embeddings for ${texts.length} issues...`);\n  for (let i = 0; i < texts.length; i += BATCH_SIZE) {\n    const batch = texts.slice(i, i + BATCH_SIZE);\n    const output = await extractor(batch, {\n      pooling: 'mean',\n      normalize: true,\n    });\n\n    const vectors = output.tolist();\n    allEmbeddings.push(...vectors);\n\n    const progress = Math.min(i + BATCH_SIZE, texts.length);\n    console.log(`  ${progress}/${texts.length}`);\n  }\n\n  const issueMetadata = allIssues.map((issue) => {\n    const body = (issue.body || '').trim();\n    return {\n      number: issue.number,\n      title: issue.title,\n      state: issue.state,\n      url: issue.html_url,\n      body_preview: body.slice(0, 500) || '',\n      labels: (issue.labels || []).map((l) => l.name),\n      created_at: issue.created_at,\n      updated_at: issue.updated_at,\n    };\n  });\n\n  const indexData = {\n    issues: issueMetadata,\n    embeddings: allEmbeddings,\n    model: MODEL_NAME,\n    issue_count: issueMetadata.length,\n    built_at: new Date().toISOString(),\n  };\n\n  const dir = dirname(OUTPUT_PATH);\n  if (dir && dir !== '.') mkdirSync(dir, { recursive: true });\n  writeFileSync(OUTPUT_PATH, JSON.stringify(indexData));\n\n  const sizeMb = (\n    Buffer.byteLength(JSON.stringify(indexData)) /\n    (1024 * 1024)\n  ).toFixed(1);\n  console.log(\n    `Index saved to ${OUTPUT_PATH} (${sizeMb} MB, ${issueMetadata.length} issues)`\n  );\n}\n\nmain().catch((err) => {\n  console.error(err);\n  process.exit(1);\n});\n"
  },
  {
    "path": "bin/duplicate-detector/detect.mjs",
    "content": "#!/usr/bin/env node\n/**\n * Duplicate Issue Detector\n *\n * Triggered on new issue creation. Compares the new issue against an\n * existing embedding index, then uses an LLM to\n * confirm duplicates before posting a comment for maintainer review.\n */\n\nimport { pipeline } from '@huggingface/transformers';\nimport { existsSync, readFileSync } from 'node:fs';\nimport {\n  addLabel,\n  dotProduct,\n  fetchIssues,\n  getIssue,\n  issueText,\n  postComment,\n} from './utils.mjs';\n\nconst SIMILARITY_THRESHOLD = 0.55;\nconst TOP_K = 5;\nconst MAX_COMMENT_CANDIDATES = 3;\nconst MODEL_NAME = process.env.EMBEDDING_MODEL || 'Xenova/all-MiniLM-L6-v2';\nconst GROQ_MODEL = process.env.GROQ_MODEL || 'llama-3.3-70b-versatile';\nconst INDEX_PATH = 'issue_index.json';\nconst LABEL_NAME = 'possible-duplicate';\n\nconst GROQ_API_KEY = process.env.GROQ_API_KEY || '';\nconst ISSUE_NUMBER = parseInt(process.env.ISSUE_NUMBER, 10);\n\nfunction loadIndex(path) {\n  if (!existsSync(path)) {\n    console.error(\n      `Index file not found at ${path}. Run build-index.mjs first.`\n    );\n    process.exit(1);\n  }\n\n  const data = JSON.parse(readFileSync(path, 'utf-8'));\n  console.log(`Loaded index with ${data.issues.length} issues`);\n  return data;\n}\n\nfunction findSimilar(\n  queryEmbedding,\n  index,\n  { topK = TOP_K, threshold = SIMILARITY_THRESHOLD, excludeNumber } = {}\n) {\n  const { issues, embeddings } = index;\n  if (!issues.length) return [];\n\n  const scored = issues.map((issue, i) => ({\n    ...issue,\n    score: dotProduct(queryEmbedding, embeddings[i]),\n  }));\n\n  return scored\n    .sort((a, b) => b.score - a.score)\n    .filter(\n      (c) =>\n        c.score >= threshold && (!excludeNumber || c.number !== excludeNumber)\n    )\n    .slice(0, topK);\n}\n\nconst CONFIRM_SYSTEM_PROMPT = `You are a GitHub issue triage assistant. You will be given a NEW issue and one \\\nor more CANDIDATE issues that may be duplicates.\n\nFor each candidate, determine if the new issue is truly a duplicate (same root \\\nproblem/request) or merely related (similar area but different issue).\n\nRespond ONLY with a JSON array of objects, each with:\n- \"number\": the candidate issue number\n- \"duplicate\": true or false\n- \"reason\": one-sentence explanation\n\nExample:\n[{\"number\": 123, \"duplicate\": true, \"reason\": \"Both report the same crash when ...\"}]`;\n\nasync function confirmWithLlm(newIssue, candidates) {\n  if (!GROQ_API_KEY) {\n    console.warn('GROQ_API_KEY not set — skipping LLM confirmation');\n    return candidates;\n  }\n\n  const candidateText = candidates\n    .map(\n      (c) =>\n        `### Candidate #${c.number} (similarity: ${c.score.toFixed(2)})\\n` +\n        `**Title:** ${c.title}\\n` +\n        `**State:** ${c.state}\\n` +\n        `**Body preview:** ${(c.body_preview || 'N/A').slice(0, 500)}`\n    )\n    .join('\\n\\n');\n\n  const userPrompt =\n    `## NEW ISSUE #${newIssue.number}\\n` +\n    `**Title:** ${newIssue.title}\\n` +\n    `**Body:**\\n${(newIssue.body || 'No body').slice(0, 1500)}\\n\\n` +\n    `---\\n\\n` +\n    `## CANDIDATES\\n${candidateText}`;\n\n  try {\n    const resp = await fetch(\n      'https://api.groq.com/openai/v1/chat/completions',\n      {\n        method: 'POST',\n        headers: {\n          Authorization: `Bearer ${GROQ_API_KEY}`,\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({\n          model: GROQ_MODEL,\n          messages: [\n            { role: 'system', content: CONFIRM_SYSTEM_PROMPT },\n            { role: 'user', content: userPrompt },\n          ],\n          temperature: 0.1,\n          max_tokens: 1024,\n        }),\n        signal: AbortSignal.timeout(30_000),\n      }\n    );\n\n    if (!resp.ok) {\n      const text = await resp.text();\n      throw new Error(`Groq API error ${resp.status}: ${text}`);\n    }\n\n    let content = (await resp.json()).choices[0].message.content.trim();\n\n    if (content.startsWith('```')) {\n      content = content\n        .split('\\n')\n        .slice(1)\n        .join('\\n')\n        .replace(/```\\s*$/, '')\n        .trim();\n    }\n\n    const verdicts = JSON.parse(content);\n    if (!Array.isArray(verdicts)) {\n      throw new Error('Invalid LLM response format - expected array');\n    }\n\n    const verdictMap = new Map(verdicts.map((v) => [v.number, v]));\n\n    const confirmed = [];\n    for (const c of candidates) {\n      const verdict = verdictMap.get(c.number);\n      if (verdict?.duplicate) {\n        c.llm_reason = verdict.reason || '';\n        confirmed.push(c);\n      } else {\n        const reason = verdict?.reason || 'not evaluated';\n        console.log(`  #${c.number} ruled out by LLM: ${reason}`);\n      }\n    }\n\n    return confirmed;\n  } catch (err) {\n    console.warn(\n      `LLM confirmation failed: ${err.message} - falling back to all candidates`\n    );\n    return candidates;\n  }\n}\n\nfunction formatComment(candidates) {\n  const lines = [\n    '**Possible duplicate detected**',\n    '',\n    'This issue may be a duplicate of the following (detected via semantic similarity + LLM review):',\n    '',\n  ];\n\n  for (const c of candidates.slice(0, MAX_COMMENT_CANDIDATES)) {\n    const confidence = `${(c.score * 100).toFixed(0)}%`;\n    let line = `- #${c.number} (${confidence} match) — ${c.title}`;\n    if (c.llm_reason) {\n      line += `\\n  > *${c.llm_reason}*`;\n    }\n    lines.push(line);\n  }\n\n  lines.push(\n    '',\n    'A maintainer will review this. If this is **not** a duplicate, no action is needed.',\n    '',\n    `<!-- duplicate-bot: candidates=${candidates.map((c) => c.number).join(',')} -->`\n  );\n\n  return lines.join('\\n');\n}\n\nasync function main() {\n  if (!ISSUE_NUMBER) {\n    console.error('ISSUE_NUMBER not set');\n    process.exit(1);\n  }\n\n  console.log(`Processing issue #${ISSUE_NUMBER}`);\n  const issue = await getIssue(ISSUE_NUMBER);\n\n  const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString();\n  const recentIssues = await fetchIssues({\n    creator: issue.user.login,\n    since: oneHourAgo,\n    state: 'all',\n  });\n\n  if (recentIssues.length > 10) {\n    console.log(\n      `User ${issue.user.login} created ${recentIssues.length} issues in the last hour - skipping to prevent spam`\n    );\n    return;\n  }\n\n  if (issue.pull_request) {\n    console.log('Skipping - this is a pull request');\n    return;\n  }\n\n  if (issue.user.type === 'Bot') {\n    console.log('Skipping - issue created by bot');\n    return;\n  }\n\n  console.log(`Loading model: ${MODEL_NAME}`);\n  const extractor = await pipeline('feature-extraction', MODEL_NAME, {\n    dtype: 'fp32',\n  });\n  const index = loadIndex(INDEX_PATH);\n\n  const text = issueText(issue.title, issue.body);\n  const output = await extractor(text, { pooling: 'mean', normalize: true });\n  const queryEmbedding = output.tolist()[0];\n\n  let candidates = findSimilar(queryEmbedding, index, {\n    topK: TOP_K,\n    threshold: SIMILARITY_THRESHOLD,\n    excludeNumber: issue.number,\n  });\n\n  if (!candidates.length) {\n    console.log('No similar issues found above threshold - done');\n    return;\n  }\n\n  console.log(`Found ${candidates.length} candidates above threshold:`);\n  for (const c of candidates) {\n    console.log(`  #${c.number} (${c.score.toFixed(3)}) - ${c.title}`);\n  }\n\n  console.log('Running LLM confirmation via Groq...');\n  candidates = await confirmWithLlm(issue, candidates);\n\n  if (!candidates.length) {\n    console.log('LLM ruled out all candidates - done');\n    return;\n  }\n\n  const comment = formatComment(candidates);\n  await postComment(ISSUE_NUMBER, comment);\n  await addLabel(ISSUE_NUMBER, LABEL_NAME);\n\n  console.log('Done!');\n}\n\nmain().catch((err) => {\n  console.error(err);\n  process.exit(1);\n});\n"
  },
  {
    "path": "bin/duplicate-detector/package.json",
    "content": "{\n  \"name\": \"duplicate-detector\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"packageManager\": \"pnpm@10.17.1\",\n  \"scripts\": {\n    \"build-index\": \"node build-index.mjs\",\n    \"detect\": \"node detect.mjs\"\n  },\n  \"dependencies\": {\n    \"@huggingface/transformers\": \"^3.8.1\"\n  },\n  \"engines\": {\n    \"node\": \">=22.0\"\n  }\n}\n"
  },
  {
    "path": "bin/duplicate-detector/utils.mjs",
    "content": "const GITHUB_API = 'https://api.github.com';\nconst GITHUB_TOKEN = process.env.GITHUB_TOKEN;\nconst GITHUB_REPOSITORY = process.env.GITHUB_REPOSITORY;\n\nfunction ghHeaders() {\n  return {\n    Authorization: `token ${GITHUB_TOKEN}`,\n    Accept: 'application/vnd.github+json',\n  };\n}\n\nexport async function fetchIssues({\n  state = 'open',\n  since,\n  maxIssues = 5000,\n} = {}) {\n  const issues = [];\n  let page = 1;\n  const perPage = 100;\n\n  while (issues.length < maxIssues) {\n    const params = new URLSearchParams({\n      state,\n      per_page: String(perPage),\n      page: String(page),\n      sort: 'updated',\n      direction: 'desc',\n    });\n    if (since) params.set('since', since);\n\n    const url = `${GITHUB_API}/repos/${GITHUB_REPOSITORY}/issues?${params}`;\n    const resp = await fetch(url, { headers: ghHeaders() });\n\n    if (!resp.ok) {\n      throw new Error(`GitHub API error: ${resp.status} ${resp.statusText}`);\n    }\n\n    const batch = await resp.json();\n    if (!batch.length) break;\n\n    for (const item of batch) {\n      if (!item.pull_request) {\n        issues.push(item);\n      }\n    }\n\n    page++;\n    if (batch.length < perPage) break;\n  }\n\n  return issues.slice(0, maxIssues);\n}\n\nexport async function getIssue(issueNumber) {\n  const url = `${GITHUB_API}/repos/${GITHUB_REPOSITORY}/issues/${issueNumber}`;\n  const resp = await fetch(url, { headers: ghHeaders() });\n\n  if (!resp.ok) {\n    throw new Error(`GitHub API error: ${resp.status} ${resp.statusText}`);\n  }\n\n  return resp.json();\n}\n\nexport async function postComment(issueNumber, body) {\n  const url = `${GITHUB_API}/repos/${GITHUB_REPOSITORY}/issues/${issueNumber}/comments`;\n  const resp = await fetch(url, {\n    method: 'POST',\n    headers: { ...ghHeaders(), 'Content-Type': 'application/json' },\n    body: JSON.stringify({ body }),\n  });\n\n  if (!resp.ok) {\n    throw new Error(\n      `Failed to post comment: ${resp.status} ${resp.statusText}`\n    );\n  }\n\n  console.log(`Posted comment on #${issueNumber}`);\n}\n\nexport async function addLabel(issueNumber, label) {\n  const url = `${GITHUB_API}/repos/${GITHUB_REPOSITORY}/issues/${issueNumber}/labels`;\n  const resp = await fetch(url, {\n    method: 'POST',\n    headers: { ...ghHeaders(), 'Content-Type': 'application/json' },\n    body: JSON.stringify({ labels: [label] }),\n  });\n\n  if (resp.status === 404) {\n    console.warn(\n      `Label '${label}' does not exist - skipping. Create it manually.`\n    );\n    return;\n  }\n\n  if (!resp.ok) {\n    throw new Error(`Failed to add label: ${resp.status} ${resp.statusText}`);\n  }\n\n  console.log(`Added label '${label}' to #${issueNumber}`);\n}\n\nexport function issueText(title, body) {\n  body = (body || '').trim();\n  if (body.length > 2000) body = body.slice(0, 2000) + '...';\n  return body ? `${title}\\n\\n${body}` : title;\n}\n\nexport function dotProduct(a, b) {\n  let sum = 0;\n  for (let i = 0; i < a.length; i++) {\n    sum += a[i] * b[i];\n  }\n  return sum;\n}\n"
  },
  {
    "path": "bin/prepare.js",
    "content": "#!/usr/bin/env node\n\n/**\n * Do not run husky in CI environments\n */\nconst isCi = process.env.CI !== undefined;\nif (!isCi) {\n  require('husky').install();\n}\n"
  },
  {
    "path": "charts/seerr-chart/.helmignore",
    "content": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation (prefixed with !). Only one pattern per line.\n.DS_Store\n# Common VCS dirs\n.git/\n.gitignore\n.bzr/\n.bzrignore\n.hg/\n.hgignore\n.svn/\n# Common backup files\n*.swp\n*.bak\n*.tmp\n*.orig\n*~\n# Various IDEs\n.project\n.idea/\n*.tmproj\n.vscode/\n# go template\n*.gotmpl\n"
  },
  {
    "path": "charts/seerr-chart/Chart.yaml",
    "content": "apiVersion: v2\nkubeVersion: '>=1.23.0-0'\nname: seerr-chart\ndescription: Seerr helm chart for Kubernetes\ntype: application\nversion: 3.3.0\n# renovate: image=ghcr.io/seerr-team/seerr\nappVersion: 'v3.1.0'\nmaintainers:\n  - name: Seerr Team\n    url: https://github.com/orgs/seerr-team/people\nsources:\n  - https://github.com/seerr-team/seerr/tree/main/charts/seerr\nhome: https://github.com/seerr-team/seerr\n"
  },
  {
    "path": "charts/seerr-chart/README.md",
    "content": "# seerr-chart\n\n![Version: 3.3.0](https://img.shields.io/badge/Version-3.3.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v3.1.0](https://img.shields.io/badge/AppVersion-v3.1.0-informational?style=flat-square)\n\nSeerr helm chart for Kubernetes\n\n**Homepage:** <https://github.com/seerr-team/seerr>\n\n## Maintainers\n\n| Name | Email | Url |\n| ---- | ------ | --- |\n| Seerr Team |  | <https://github.com/orgs/seerr-team/people> |\n\n## Source Code\n\n* <https://github.com/seerr-team/seerr/tree/main/charts/seerr>\n\n## Requirements\n\nKubernetes: `>=1.23.0-0`\n\n## Installation\n\nRefer to [Seerr kubernetes documentation](https://docs.seerr.dev/getting-started/kubernetes)\n\n## Update Notes\n\n### Updating to 3.0.0\n\nNothing has changed; we just rebranded the `jellyseerr` Helm chart to `seerr` 🥳 refer to our [Migration guide](https://docs.seerr.dev/migration-guide).\n\n### Updating to 2.7.0\n\nSeerr is a stateful application and it is not designed to have multiple replicas. In version 2.7.0 we address this by:\n\n- replacing `Deployment` with `StatefulSet`\n- removing `replicaCount` value\n\nIf `replicaCount` value was used - remove it. Helm update should work fine after that.\n\n## Values\n\n| Key | Type | Default | Description |\n|-----|------|---------|-------------|\n| affinity | object | `{}` |  |\n| config | object | `{\"persistence\":{\"accessModes\":[\"ReadWriteOnce\"],\"annotations\":{},\"existingClaim\":\"\",\"name\":\"\",\"size\":\"5Gi\",\"volumeName\":\"\"}}` | Creating PVC to store configuration |\n| config.persistence.accessModes | list | `[\"ReadWriteOnce\"]` | Access modes of persistent disk |\n| config.persistence.annotations | object | `{}` | Annotations for PVCs |\n| config.persistence.existingClaim | string | `\"\"` | Specify an existing `PersistentVolumeClaim` to use. If this value is provided, the default PVC will not be created |\n| config.persistence.name | string | `\"\"` | Config name |\n| config.persistence.size | string | `\"5Gi\"` | Size of persistent disk |\n| config.persistence.volumeName | string | `\"\"` | Name of the permanent volume to reference in the claim. Can be used to bind to existing volumes. |\n| extraEnv | list | `[]` | Environment variables to add to the seerr pods |\n| extraEnvFrom | list | `[]` | Environment variables from secrets or configmaps to add to the seerr pods |\n| fullnameOverride | string | `\"\"` |  |\n| image.pullPolicy | string | `\"IfNotPresent\"` |  |\n| image.registry | string | `\"ghcr.io\"` |  |\n| image.repository | string | `\"seerr-team/seerr\"` |  |\n| image.sha | string | `\"\"` |  |\n| image.tag | string | `\"\"` | Overrides the image tag whose default is the chart appVersion. |\n| imagePullSecrets | list | `[]` |  |\n| ingress.annotations | object | `{}` |  |\n| ingress.enabled | bool | `false` |  |\n| ingress.hosts[0].host | string | `\"chart-example.local\"` |  |\n| ingress.hosts[0].paths[0].path | string | `\"/\"` |  |\n| ingress.hosts[0].paths[0].pathType | string | `\"ImplementationSpecific\"` |  |\n| ingress.ingressClassName | string | `\"\"` |  |\n| ingress.tls | list | `[]` |  |\n| nameOverride | string | `\"\"` |  |\n| nodeSelector | object | `{}` |  |\n| podAnnotations | object | `{}` |  |\n| podLabels | object | `{}` |  |\n| podSecurityContext.fsGroup | int | `1000` |  |\n| podSecurityContext.fsGroupChangePolicy | string | `\"OnRootMismatch\"` |  |\n| probes.livenessProbe | object | `{}` | Configure liveness probe |\n| probes.readinessProbe | object | `{}` | Configure readiness probe |\n| probes.startupProbe | string | `nil` | Configure startup probe |\n| resources | object | `{}` |  |\n| route.main.additionalRules | list | `[]` |  |\n| route.main.annotations | object | `{}` |  |\n| route.main.apiVersion | string | `\"gateway.networking.k8s.io/v1\"` | Set the route apiVersion, e.g. gateway.networking.k8s.io/v1 or gateway.networking.k8s.io/v1alpha2 |\n| route.main.enabled | bool | `false` | Enables or disables the Gateway API route |\n| route.main.filters | list | `[]` |  |\n| route.main.hostnames | list | `[]` |  |\n| route.main.httpsRedirect | bool | `false` | To redirect to HTTPS, create a new route object under the main route and enable this option. This should only be used with HTTP-like routes, such as HTTPRoute or GRPCRoute. [Reference]( https://gateway-api.sigs.k8s.io/guides/http-redirect-rewrite/ ) |\n| route.main.kind | string | `\"HTTPRoute\"` | Set the route kind. Note that experimental kinds require changing `apiVersion` |\n| route.main.labels | object | `{}` |  |\n| route.main.matches[0].path.type | string | `\"PathPrefix\"` |  |\n| route.main.matches[0].path.value | string | `\"/\"` |  |\n| route.main.parentRefs | list | `[]` |  |\n| securityContext.allowPrivilegeEscalation | bool | `false` |  |\n| securityContext.capabilities.drop[0] | string | `\"ALL\"` |  |\n| securityContext.privileged | bool | `false` |  |\n| securityContext.readOnlyRootFilesystem | bool | `false` |  |\n| securityContext.runAsGroup | int | `1000` |  |\n| securityContext.runAsNonRoot | bool | `true` |  |\n| securityContext.runAsUser | int | `1000` |  |\n| securityContext.seccompProfile.type | string | `\"RuntimeDefault\"` |  |\n| service.port | int | `80` |  |\n| service.type | string | `\"ClusterIP\"` |  |\n| serviceAccount.annotations | object | `{}` | Annotations to add to the service account |\n| serviceAccount.automount | bool | `true` | Automatically mount a ServiceAccount's API credentials? |\n| serviceAccount.create | bool | `true` | Specifies whether a service account should be created |\n| serviceAccount.name | string | `\"\"` | If not set and create is true, a name is generated using the fullname template |\n| tolerations | list | `[]` |  |\n| volumeMounts | list | `[]` | Additional volumeMounts on the output StatefulSet definition. |\n| volumes | list | `[]` | Additional volumes on the output StatefulSet definition. |\n"
  },
  {
    "path": "charts/seerr-chart/README.md.gotmpl",
    "content": "{{ template \"chart.header\" . }}\n\n{{ template \"chart.deprecationWarning\" . }}\n\n{{ template \"chart.badgesSection\" . }}\n\n{{ template \"chart.description\" . }}\n\n{{ template \"chart.homepageLine\" . }}\n\n{{ template \"chart.maintainersSection\" . }}\n\n{{ template \"chart.sourcesSection\" . }}\n\n{{ template \"chart.requirementsSection\" . }}\n\n## Installation\n\nRefer to [Seerr kubernetes documentation](https://docs.seerr.dev/getting-started/kubernetes)\n\n## Update Notes\n\n### Updating to 3.0.0\n\nNothing has changed; we just rebranded the `jellyseerr` Helm chart to `seerr` 🥳 refer to our [Migration guide](https://docs.seerr.dev/migration-guide).\n\n### Updating to 2.7.0\n\nSeerr is a stateful application and it is not designed to have multiple replicas. In version 2.7.0 we address this by:\n\n- replacing `Deployment` with `StatefulSet`\n- removing `replicaCount` value\n\nIf `replicaCount` value was used - remove it. Helm update should work fine after that.\n\n{{ template \"chart.valuesSection\" . }}\n"
  },
  {
    "path": "charts/seerr-chart/artifacthub-repo.yml",
    "content": "repositoryID: 249547ec-2a30-48de-a5bc-07bfd5aa2e8f\n"
  },
  {
    "path": "charts/seerr-chart/templates/NOTES.txt",
    "content": "***********************************************************************\n Welcome to {{ .Chart.Name }}\n Chart version: {{ .Chart.Version }}\n App   version: {{ .Chart.AppVersion }}\n***********************************************************************"
  },
  {
    "path": "charts/seerr-chart/templates/_helpers.tpl",
    "content": "{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"seerr.name\" -}}\n{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n\n{{/*\nCreate a default fully qualified app name.\nWe truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).\nIf release name contains chart name it will be used as a full name.\n*/}}\n{{- define \"seerr.fullname\" -}}\n{{- if .Values.fullnameOverride }}\n{{- .Values.fullnameOverride | trunc 63 | trimSuffix \"-\" }}\n{{- else }}\n{{- $name := default .Chart.Name .Values.nameOverride }}\n{{- if contains $name .Release.Name }}\n{{- .Release.Name | trunc 63 | trimSuffix \"-\" }}\n{{- else }}\n{{- printf \"%s-%s\" .Release.Name $name | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n{{- end }}\n{{- end }}\n\n{{/*\nCreate chart name and version as used by the chart label.\n*/}}\n{{- define \"seerr.chart\" -}}\n{{- printf \"%s-%s\" .Chart.Name .Chart.Version | replace \"+\" \"_\" | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n\n{{/*\nCommon labels\n*/}}\n{{- define \"seerr.labels\" -}}\nhelm.sh/chart: {{ include \"seerr.chart\" . }}\n{{ include \"seerr.selectorLabels\" . }}\n{{- if .Chart.AppVersion }}\napp.kubernetes.io/version: {{ .Chart.AppVersion | quote }}\n{{- end }}\napp.kubernetes.io/part-of: {{ .Chart.Name }}\napp.kubernetes.io/managed-by: {{ .Release.Service }}\n{{- end }}\n\n{{/*\nSelector labels\n*/}}\n{{- define \"seerr.selectorLabels\" -}}\napp.kubernetes.io/name: {{ include \"seerr.name\" . }}\napp.kubernetes.io/instance: {{ .Release.Name }}\n{{- end }}\n\n{{/*\nCreate the name of the service account to use\n*/}}\n{{- define \"seerr.serviceAccountName\" -}}\n{{- if .Values.serviceAccount.create }}\n{{- default (include \"seerr.fullname\" .) .Values.serviceAccount.name }}\n{{- else }}\n{{- default \"default\" .Values.serviceAccount.name }}\n{{- end }}\n{{- end }}\n\n{{/*\nCreate the name of the pvc config to use\n*/}}\n{{- define \"seerr.configPersistenceName\" -}}\n{{- default (printf \"%s-config\" (include \"seerr.fullname\" .)) .Values.config.persistence.name }}\n{{- end }}\n"
  },
  {
    "path": "charts/seerr-chart/templates/ingress.yaml",
    "content": "{{- if .Values.ingress.enabled -}}\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: {{ include \"seerr.fullname\" . }}\n  labels:\n    {{- include \"seerr.labels\" . | nindent 4 }}\n  {{- with .Values.ingress.annotations }}\n  annotations:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\nspec:\n  {{- if .Values.ingress.ingressClassName }}\n  ingressClassName: {{ .Values.ingress.ingressClassName }}\n  {{- end }}\n  {{- if .Values.ingress.tls }}\n  tls:\n    {{- range .Values.ingress.tls }}\n    - hosts:\n        {{- range .hosts }}\n        - {{ . | quote }}\n        {{- end }}\n      secretName: {{ .secretName }}\n    {{- end }}\n  {{- end }}\n  rules:\n    {{- range .Values.ingress.hosts }}\n    - host: {{ .host | quote }}\n      http:\n        paths:\n          {{- range .paths }}\n          - path: {{ .path }}\n            pathType: {{ .pathType }}\n            backend:\n              service:\n                name: {{ include \"seerr.fullname\" $ }}\n                port:\n                  number: {{ $.Values.service.port }}\n          {{- end }}\n    {{- end }}\n{{- end }}\n"
  },
  {
    "path": "charts/seerr-chart/templates/persistentvolumeclaim.yaml",
    "content": "{{- if not .Values.config.persistence.existingClaim -}}\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: {{ include \"seerr.configPersistenceName\" . }}\n  labels:\n    {{- include \"seerr.labels\" . | nindent 4 }}\n  {{- with .Values.config.persistence.annotations }}\n  annotations:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\nspec:\n  {{- with .Values.config.persistence.accessModes }}\n  accessModes:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\n  {{- if .Values.config.persistence.volumeName }}\n  volumeName: {{ .Values.config.persistence.volumeName }}\n  {{- end }}\n  {{- with .Values.config.persistence.storageClass }}\n  storageClassName: {{ if (eq \"-\" .) }}\"\"{{ else }}{{ . }}{{ end }}\n  {{- end }}\n  resources:\n    requests:\n      storage: \"{{ .Values.config.persistence.size }}\"\n{{- end -}}"
  },
  {
    "path": "charts/seerr-chart/templates/route.yaml",
    "content": "{{- range $name, $route := .Values.route }}\n{{- if $route.enabled }}\n---\napiVersion: {{ $route.apiVersion | default \"gateway.networking.k8s.io/v1\" }}\nkind: {{ $route.kind | default \"HTTPRoute\" }}\nmetadata:\n  name: {{ template \"seerr.fullname\" $ }}{{ if ne $name \"main\" }}-{{ $name }}{{ end }}\n  labels:\n    {{- include \"seerr.labels\" $ | nindent 4 }}\n    {{- with $route.labels }}\n    {{- toYaml . | nindent 4 }}\n    {{- end }}\n  {{- with $route.annotations }}\n  annotations:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\nspec:\n  {{- with $route.parentRefs }}\n  parentRefs:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\n  {{- with $route.hostnames }}\n  hostnames:\n    {{- tpl (toYaml .) $ | nindent 4 }}\n  {{- end }}\n  rules:\n    {{- with $route.additionalRules }}\n    {{- tpl (toYaml .) $ | nindent 4 }}\n    {{- end }}\n    {{- if $route.httpsRedirect }}\n    - filters:\n        - type: RequestRedirect\n          requestRedirect:\n            scheme: https\n            statusCode: 301\n    {{- else }}\n    - backendRefs:\n        - name: {{ include \"seerr.fullname\" $ }}\n          port: {{ $.Values.service.port }}\n      {{- with $route.filters }}\n      filters:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      {{- with $route.matches }}\n      matches:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n    {{- end }}\n{{- end }}\n{{- end }}"
  },
  {
    "path": "charts/seerr-chart/templates/service.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: {{ include \"seerr.fullname\" . }}\n  labels:\n    {{- include \"seerr.labels\" . | nindent 4 }}\nspec:\n  type: {{ .Values.service.type }}\n  ports:\n    - port: {{ .Values.service.port }}\n      targetPort: http\n      protocol: TCP\n      name: http\n  selector:\n    {{- include \"seerr.selectorLabels\" . | nindent 4 }}\n  ipFamilyPolicy: PreferDualStack\n"
  },
  {
    "path": "charts/seerr-chart/templates/serviceaccount.yaml",
    "content": "{{- if .Values.serviceAccount.create -}}\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: {{ include \"seerr.serviceAccountName\" . }}\n  labels:\n    {{- include \"seerr.labels\" . | nindent 4 }}\n  {{- with .Values.serviceAccount.annotations }}\n  annotations:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\nautomountServiceAccountToken: {{ .Values.serviceAccount.automount }}\n{{- end }}\n"
  },
  {
    "path": "charts/seerr-chart/templates/statefulset.yaml",
    "content": "apiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: {{ include \"seerr.fullname\" . }}\n  labels:\n    {{- include \"seerr.labels\" . | nindent 4 }}\nspec:\n  serviceName: {{ include \"seerr.fullname\" . }}\n  selector:\n    matchLabels:\n      {{- include \"seerr.selectorLabels\" . | nindent 6 }}\n  template:\n    metadata:\n      {{- with .Values.podAnnotations }}\n      annotations:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      labels:\n        {{- include \"seerr.labels\" . | nindent 8 }}\n        {{- with .Values.podLabels }}\n        {{- toYaml . | nindent 8 }}\n        {{- end }}\n    spec:\n      {{- with .Values.imagePullSecrets }}\n      imagePullSecrets:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      serviceAccountName: {{ include \"seerr.serviceAccountName\" . }}\n      securityContext:\n        {{- toYaml .Values.podSecurityContext | nindent 8 }}\n      containers:\n        - name: {{ .Chart.Name }}\n          securityContext:\n            {{- toYaml .Values.securityContext | nindent 12 }}\n          {{- if .Values.image.sha }}\n          image: \"{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}@sha256:{{ .Values.image.sha }}\"\n          {{- else }}\n          image: \"{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}\"\n          {{- end }}\n          imagePullPolicy: {{ .Values.image.pullPolicy }}\n          ports:\n            - name: http\n              containerPort: 5055\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /\n              port: http\n            {{- if .Values.probes.livenessProbe.initialDelaySeconds }}\n            initialDelaySeconds: {{ .Values.probes.livenessProbe.initialDelaySeconds }}\n            {{- end }}\n            {{- if .Values.probes.livenessProbe.periodSeconds }}\n            periodSeconds: {{ .Values.probes.livenessProbe.periodSeconds }}\n            {{- end }}\n            {{- if .Values.probes.livenessProbe.timeoutSeconds }}\n            timeoutSeconds: {{ .Values.probes.livenessProbe.timeoutSeconds }}\n            {{- end }}\n            {{- if .Values.probes.livenessProbe.successThreshold }}\n            successThreshold: {{ .Values.probes.livenessProbe.successThreshold }}\n            {{- end }}\n            {{- if .Values.probes.livenessProbe.failureThreshold }}\n            failureThreshold: {{ .Values.probes.livenessProbe.failureThreshold }}\n            {{- end }}\n          readinessProbe:\n            httpGet:\n              path: /\n              port: http\n            {{- if .Values.probes.readinessProbe.initialDelaySeconds }}\n            initialDelaySeconds: {{ .Values.probes.readinessProbe.initialDelaySeconds }}\n            {{- end }}\n            {{- if .Values.probes.readinessProbe.periodSeconds }}\n            periodSeconds: {{ .Values.probes.readinessProbe.periodSeconds }}\n            {{- end }}\n            {{- if .Values.probes.readinessProbe.timeoutSeconds }}\n            timeoutSeconds: {{ .Values.probes.readinessProbe.timeoutSeconds }}\n            {{- end }}\n            {{- if .Values.probes.readinessProbe.successThreshold }}\n            successThreshold: {{ .Values.probes.readinessProbe.successThreshold }}\n            {{- end }}\n            {{- if .Values.probes.readinessProbe.failureThreshold }}\n            failureThreshold: {{ .Values.probes.readinessProbe.failureThreshold }}\n            {{- end }}\n          {{- if .Values.probes.startupProbe }}\n          startupProbe:\n            {{- toYaml .Values.probes.startupProbe | nindent 12 }}\n          {{- end }}\n          resources:\n            {{- toYaml .Values.resources | nindent 12 }}\n          {{- with .Values.extraEnv }}\n          env:\n            {{- toYaml . | nindent 12 }}\n          {{- end }}\n          {{- with .Values.extraEnvFrom }}\n          envFrom:\n            {{- toYaml . | nindent 12 }}\n          {{- end }}\n          volumeMounts:\n            - name: config\n              mountPath: /app/config\n          {{- with .Values.volumeMounts }}\n            {{- toYaml . | nindent 12 }}\n          {{- end }}\n      volumes:\n        - name: config\n          persistentVolumeClaim:\n            claimName: {{ if .Values.config.persistence.existingClaim }}{{ .Values.config.persistence.existingClaim }}{{- else }}{{ include \"seerr.configPersistenceName\" . }}{{- end }}\n      {{- with .Values.volumes }}\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      {{- with .Values.nodeSelector }}\n      nodeSelector:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      {{- with .Values.affinity }}\n      affinity:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      {{- with .Values.tolerations }}\n      tolerations:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n"
  },
  {
    "path": "charts/seerr-chart/templates/tests/test-connection.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: \"{{ include \"seerr.fullname\" . }}-test-connection\"\n  labels:\n    {{- include \"seerr.labels\" . | nindent 4 }}\n  annotations:\n    \"helm.sh/hook\": test\nspec:\n  containers:\n    - name: wget\n      image: busybox\n      command: ['wget']\n      args: ['{{ include \"seerr.fullname\" . }}:{{ .Values.service.port }}']\n  restartPolicy: Never\n"
  },
  {
    "path": "charts/seerr-chart/values.yaml",
    "content": "image:\n  registry: ghcr.io\n  repository: seerr-team/seerr\n  pullPolicy: IfNotPresent\n  # -- Overrides the image tag whose default is the chart appVersion.\n  tag: ''\n  sha: ''\n\nimagePullSecrets: []\nnameOverride: ''\nfullnameOverride: ''\n\n# Liveness / Readiness / Startup Probes\nprobes:\n  # -- Configure liveness probe\n  livenessProbe: {}\n  # initialDelaySeconds: 60\n  # periodSeconds: 30\n  # timeoutSeconds: 5\n  # successThreshold: 1\n  # failureThreshold: 5\n  # -- Configure readiness probe\n  readinessProbe: {}\n  # initialDelaySeconds: 60\n  # periodSeconds: 30\n  # timeoutSeconds: 5\n  # successThreshold: 1\n  # failureThreshold: 5\n  # -- Configure startup probe\n  startupProbe: null\n  #  tcpSocket:\n  #    port: http\n\n# -- Environment variables to add to the seerr pods\nextraEnv: []\n# -- Environment variables from secrets or configmaps to add to the seerr pods\nextraEnvFrom: []\n\nserviceAccount:\n  # -- Specifies whether a service account should be created\n  create: true\n  # -- Automatically mount a ServiceAccount's API credentials?\n  automount: true\n  # -- Annotations to add to the service account\n  annotations: {}\n  # -- The name of the service account to use.\n  # -- If not set and create is true, a name is generated using the fullname template\n  name: ''\n\npodAnnotations: {}\npodLabels: {}\n\npodSecurityContext:\n  fsGroup: 1000\n  fsGroupChangePolicy: OnRootMismatch\n\nsecurityContext:\n  allowPrivilegeEscalation: false\n  capabilities:\n    drop:\n      - ALL\n  readOnlyRootFilesystem: false\n  runAsNonRoot: true\n  privileged: false\n  runAsUser: 1000\n  runAsGroup: 1000\n  seccompProfile:\n    type: RuntimeDefault\n\nservice:\n  type: ClusterIP\n  port: 80\n\n# -- Creating PVC to store configuration\nconfig:\n  persistence:\n    # -- Size of persistent disk\n    size: 5Gi\n    # -- Annotations for PVCs\n    annotations: {}\n    # -- Access modes of persistent disk\n    accessModes:\n      - ReadWriteOnce\n    # -- Config name\n    name: ''\n    # -- Name of the permanent volume to reference in the claim.\n    # Can be used to bind to existing volumes.\n    volumeName: ''\n    # -- Specify an existing `PersistentVolumeClaim` to use. If this value is provided, the default PVC will not be created\n    existingClaim: ''\n\ningress:\n  enabled: false\n  ingressClassName: ''\n  annotations: {}\n  #  kubernetes.io/ingress.class: nginx\n  #  kubernetes.io/tls-acme: \"true\"\n  hosts:\n    - host: chart-example.local\n      paths:\n        - path: /\n          pathType: ImplementationSpecific\n  tls: []\n  #  - secretName: chart-example-tls\n  #    hosts:\n  #      - chart-example.local\n\nroute:\n  main:\n    # -- Enables or disables the Gateway API route\n    enabled: false\n\n    # -- Set the route apiVersion, e.g. gateway.networking.k8s.io/v1 or gateway.networking.k8s.io/v1alpha2\n    apiVersion: gateway.networking.k8s.io/v1\n\n    # -- Set the route kind.\n    # Note that experimental kinds require changing `apiVersion`\n    kind: HTTPRoute\n\n    annotations: {}\n\n    labels: {}\n\n    parentRefs: []\n    # - name: my-gateway\n    #   namespace: gateway\n    #   sectionName: https\n\n    hostnames: []\n    # - seerr.example.com\n\n    additionalRules: []\n\n    filters: []\n\n    matches:\n      - path:\n          type: PathPrefix\n          value: /\n\n    # -- To redirect to HTTPS, create a new route object under the main route and enable this option.\n    # This should only be used with HTTP-like routes, such as HTTPRoute or GRPCRoute.\n    # [Reference]( https://gateway-api.sigs.k8s.io/guides/http-redirect-rewrite/ )\n    httpsRedirect: false\n\nresources: {}\n# We usually recommend not to specify default resources and to leave this as a conscious\n# choice for the user. This also increases chances charts run on environments with little\n# resources, such as Minikube. If you do want to specify resources, uncomment the following\n# lines, adjust them as necessary, and remove the curly braces after 'resources:'.\n# limits:\n#   cpu: 100m\n#   memory: 128Mi\n# requests:\n#   cpu: 100m\n#   memory: 128Mi\n\n# -- Additional volumes on the output StatefulSet definition.\nvolumes: []\n# - name: foo\n#   secret:\n#     secretName: mysecret\n#     optional: false\n\n# -- Additional volumeMounts on the output StatefulSet definition.\nvolumeMounts: []\n# - name: foo\n#   mountPath: \"/etc/foo\"\n#   readOnly: true\n\nnodeSelector: {}\n\ntolerations: []\n\naffinity: {}\n"
  },
  {
    "path": "compose.postgres.yaml",
    "content": "services:\n  seerr:\n    build:\n      context: .\n      dockerfile: Dockerfile.local\n    ports:\n      - '5055:5055'\n    environment:\n      DB_TYPE: 'postgres' # Which DB engine to use. The default is \"sqlite\". To use postgres, this needs to be set to \"postgres\"\n      DB_HOST: 'postgres' # The host (url) of the database\n      DB_PORT: '5432' # The port to connect to\n      DB_USER: 'seerr' # Username used to connect to the database\n      DB_PASS: 'seerr' # Password of the user used to connect to the database\n      DB_NAME: 'seerr' # The name of the database to connect to\n      DB_LOG_QUERIES: 'false' # Whether to log the DB queries for debugging\n      DB_USE_SSL: 'false' # Whether to enable ssl for database connection\n    volumes:\n      - .:/app:rw,cached\n      - /app/node_modules\n      - /app/.next\n    depends_on:\n      - postgres\n    links:\n      - postgres\n  postgres:\n    image: postgres:18\n    environment:\n      POSTGRES_USER: seerr\n      POSTGRES_PASSWORD: seerr\n      POSTGRES_DB: seerr\n    ports:\n      - '5432:5432'\n    volumes:\n      - postgres:/var/lib/postgresql\nvolumes:\n  postgres:\n"
  },
  {
    "path": "compose.yaml",
    "content": "services:\n  seerr:\n    build:\n      context: .\n      dockerfile: Dockerfile.local\n    ports:\n      - 5055:5055\n    volumes:\n      - .:/app:rw,cached\n      - /app/node_modules\n      - /app/.next\n"
  },
  {
    "path": "config/.gitkeep",
    "content": ""
  },
  {
    "path": "config/db/.gitkeep",
    "content": ""
  },
  {
    "path": "config/logs/.gitkeep",
    "content": ""
  },
  {
    "path": "cypress/config/settings.cypress.json",
    "content": "{\n  \"clientId\": \"6919275e-142a-48d8-be6b-93594cbd4626\",\n  \"vapidPrivate\": \"tmnslaO8ZWN6bNbSEv_rolPeBTlNxOwCCAHrM9oZz3M\",\n  \"vapidPublic\": \"BK_EpP8NDm9waor2zn6_S28o3ZYv4kCkJOfYpO3pt3W6jnPmxrgTLANUBNbbyaNatPnSQ12De9CeqSYQrqWzHTs\",\n  \"main\": {\n    \"apiKey\": \"testkey\",\n    \"applicationTitle\": \"Seerr\",\n    \"applicationUrl\": \"\",\n    \"cacheImages\": false,\n    \"defaultPermissions\": 32,\n    \"defaultQuotas\": {\n      \"movie\": {},\n      \"tv\": {}\n    },\n    \"hideAvailable\": false,\n    \"localLogin\": true,\n    \"newPlexLogin\": true,\n    \"discoverRegion\": \"\",\n    \"streamingRegion\": \"\",\n    \"originalLanguage\": \"\",\n    \"blocklistedTags\": \"\",\n    \"blocklistedTagsLimit\": 50,\n    \"trustProxy\": false,\n    \"mediaServerType\": 1,\n    \"partialRequestsEnabled\": true,\n    \"enableSpecialEpisodes\": false,\n    \"locale\": \"en\"\n  },\n  \"plex\": {\n    \"name\": \"Seerr\",\n    \"ip\": \"192.168.1.1\",\n    \"port\": 32400,\n    \"useSsl\": false,\n    \"libraries\": [\n      {\n        \"id\": \"1\",\n        \"name\": \"Movies\",\n        \"enabled\": true,\n        \"type\": \"movie\"\n      }\n    ],\n    \"machineId\": \"test\"\n  },\n  \"jellyfin\": {\n    \"name\": \"\",\n    \"ip\": \"\",\n    \"port\": 8096,\n    \"useSsl\": false,\n    \"urlBase\": \"\",\n    \"externalHostname\": \"\",\n    \"jellyfinForgotPasswordUrl\": \"\",\n    \"libraries\": [],\n    \"serverId\": \"\"\n  },\n  \"tautulli\": {},\n  \"radarr\": [],\n  \"sonarr\": [],\n  \"public\": {\n    \"initialized\": true\n  },\n  \"notifications\": {\n    \"agents\": {\n      \"email\": {\n        \"enabled\": false,\n        \"options\": {\n          \"emailFrom\": \"\",\n          \"smtpHost\": \"\",\n          \"smtpPort\": 587,\n          \"secure\": false,\n          \"ignoreTls\": false,\n          \"requireTls\": false,\n          \"allowSelfSigned\": false,\n          \"senderName\": \"Seerr\"\n        }\n      },\n      \"discord\": {\n        \"enabled\": false,\n        \"types\": 0,\n        \"options\": {\n          \"webhookUrl\": \"\",\n          \"webhookRoleId\": \"\",\n          \"enableMentions\": true\n        }\n      },\n      \"slack\": {\n        \"enabled\": false,\n        \"types\": 0,\n        \"options\": {\n          \"webhookUrl\": \"\"\n        }\n      },\n      \"telegram\": {\n        \"enabled\": false,\n        \"types\": 0,\n        \"options\": {\n          \"botAPI\": \"\",\n          \"chatId\": \"\",\n          \"messageThreadId\": \"\",\n          \"sendSilently\": false\n        }\n      },\n      \"pushbullet\": {\n        \"enabled\": false,\n        \"types\": 0,\n        \"options\": {\n          \"accessToken\": \"\"\n        }\n      },\n      \"pushover\": {\n        \"enabled\": false,\n        \"types\": 0,\n        \"options\": {\n          \"accessToken\": \"\",\n          \"userToken\": \"\"\n        }\n      },\n      \"webhook\": {\n        \"enabled\": false,\n        \"types\": 0,\n        \"options\": {\n          \"webhookUrl\": \"\",\n          \"jsonPayload\": \"IntcbiAgICBcIm5vdGlmaWNhdGlvbl90eXBlXCI6IFwie3tub3RpZmljYXRpb25fdHlwZX19XCIsXG4gICAgXCJldmVudFwiOiBcInt7ZXZlbnR9fVwiLFxuICAgIFwic3ViamVjdFwiOiBcInt7c3ViamVjdH19XCIsXG4gICAgXCJtZXNzYWdlXCI6IFwie3ttZXNzYWdlfX1cIixcbiAgICBcImltYWdlXCI6IFwie3tpbWFnZX19XCIsXG4gICAgXCJ7e21lZGlhfX1cIjoge1xuICAgICAgICBcIm1lZGlhX3R5cGVcIjogXCJ7e21lZGlhX3R5cGV9fVwiLFxuICAgICAgICBcInRtZGJJZFwiOiBcInt7bWVkaWFfdG1kYmlkfX1cIixcbiAgICAgICAgXCJ0dmRiSWRcIjogXCJ7e21lZGlhX3R2ZGJpZH19XCIsXG4gICAgICAgIFwic3RhdHVzXCI6IFwie3ttZWRpYV9zdGF0dXN9fVwiLFxuICAgICAgICBcInN0YXR1czRrXCI6IFwie3ttZWRpYV9zdGF0dXM0a319XCJcbiAgICB9LFxuICAgIFwie3tyZXF1ZXN0fX1cIjoge1xuICAgICAgICBcInJlcXVlc3RfaWRcIjogXCJ7e3JlcXVlc3RfaWR9fVwiLFxuICAgICAgICBcInJlcXVlc3RlZEJ5X2VtYWlsXCI6IFwie3tyZXF1ZXN0ZWRCeV9lbWFpbH19XCIsXG4gICAgICAgIFwicmVxdWVzdGVkQnlfdXNlcm5hbWVcIjogXCJ7e3JlcXVlc3RlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXF1ZXN0ZWRCeV9hdmF0YXJcIjogXCJ7e3JlcXVlc3RlZEJ5X2F2YXRhcn19XCJcbiAgICB9LFxuICAgIFwie3tpc3N1ZX19XCI6IHtcbiAgICAgICAgXCJpc3N1ZV9pZFwiOiBcInt7aXNzdWVfaWR9fVwiLFxuICAgICAgICBcImlzc3VlX3R5cGVcIjogXCJ7e2lzc3VlX3R5cGV9fVwiLFxuICAgICAgICBcImlzc3VlX3N0YXR1c1wiOiBcInt7aXNzdWVfc3RhdHVzfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2VtYWlsXCI6IFwie3tyZXBvcnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X3VzZXJuYW1lXCI6IFwie3tyZXBvcnRlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2F2YXRhclwiOiBcInt7cmVwb3J0ZWRCeV9hdmF0YXJ9fVwiXG4gICAgfSxcbiAgICBcInt7Y29tbWVudH19XCI6IHtcbiAgICAgICAgXCJjb21tZW50X21lc3NhZ2VcIjogXCJ7e2NvbW1lbnRfbWVzc2FnZX19XCIsXG4gICAgICAgIFwiY29tbWVudGVkQnlfZW1haWxcIjogXCJ7e2NvbW1lbnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJjb21tZW50ZWRCeV91c2VybmFtZVwiOiBcInt7Y29tbWVudGVkQnlfdXNlcm5hbWV9fVwiLFxuICAgICAgICBcImNvbW1lbnRlZEJ5X2F2YXRhclwiOiBcInt7Y29tbWVudGVkQnlfYXZhdGFyfX1cIlxuICAgIH0sXG4gICAgXCJ7e2V4dHJhfX1cIjogW11cbn0i\"\n        }\n      },\n      \"webpush\": {\n        \"enabled\": false,\n        \"options\": {}\n      },\n      \"gotify\": {\n        \"enabled\": false,\n        \"types\": 0,\n        \"options\": {\n          \"url\": \"\",\n          \"token\": \"\",\n          \"priority\": 0\n        }\n      },\n      \"ntfy\": {\n        \"enabled\": false,\n        \"types\": 0,\n        \"options\": {\n          \"url\": \"\",\n          \"topic\": \"\"\n        }\n      }\n    }\n  },\n  \"jobs\": {\n    \"plex-recently-added-scan\": {\n      \"schedule\": \"0 */5 * * * *\"\n    },\n    \"plex-full-scan\": {\n      \"schedule\": \"0 0 3 * * *\"\n    },\n    \"radarr-scan\": {\n      \"schedule\": \"0 0 4 * * *\"\n    },\n    \"sonarr-scan\": {\n      \"schedule\": \"0 30 4 * * *\"\n    },\n    \"plex-watchlist-sync\": {\n      \"schedule\": \"0 */10 * * * *\"\n    },\n    \"availability-sync\": {\n      \"schedule\": \"0 0 5 * * *\"\n    },\n    \"download-sync\": {\n      \"schedule\": \"0 * * * * *\"\n    },\n    \"download-sync-reset\": {\n      \"schedule\": \"0 0 1 * * *\"\n    },\n    \"jellyfin-recently-added-scan\": {\n      \"schedule\": \"0 */5 * * * *\"\n    },\n    \"jellyfin-full-scan\": {\n      \"schedule\": \"0 0 3 * * *\"\n    },\n    \"image-cache-cleanup\": {\n      \"schedule\": \"0 0 5 * * *\"\n    }\n  },\n  \"network\": {\n    \"csrfProtection\": false,\n    \"trustProxy\": false,\n    \"forceIpv4First\": false,\n    \"dnsServers\": \"\",\n    \"proxy\": {\n      \"enabled\": false,\n      \"hostname\": \"\",\n      \"port\": 8080,\n      \"useSsl\": false,\n      \"user\": \"\",\n      \"password\": \"\",\n      \"bypassFilter\": \"\",\n      \"bypassLocalAddresses\": true\n    },\n    \"dnsCache\": {\n      \"enabled\": false,\n      \"forceMinTtl\": 0,\n      \"forceMaxTtl\": -1\n    }\n  }\n}\n"
  },
  {
    "path": "cypress/e2e/discover.cy.ts",
    "content": "const clickFirstTitleCardInSlider = (sliderTitle: string): void => {\n  cy.contains('.slider-header', sliderTitle)\n    .next('[data-testid=media-slider]')\n    .find('[data-testid=title-card]')\n    .first()\n    .trigger('mouseover')\n    .find('[data-testid=title-card-title]')\n    .invoke('text')\n    .then((text) => {\n      cy.contains('.slider-header', sliderTitle)\n        .next('[data-testid=media-slider]')\n        .find('[data-testid=title-card]')\n        .first()\n        .click();\n      cy.get('[data-testid=media-title]').should('contain', text);\n    });\n};\n\ndescribe('Discover', () => {\n  beforeEach(() => {\n    cy.loginAsAdmin();\n  });\n\n  it('loads a trending item', () => {\n    cy.intercept('/api/v1/discover/trending*').as('getTrending');\n    cy.visit('/');\n    cy.wait('@getTrending');\n    clickFirstTitleCardInSlider('Trending');\n  });\n\n  it('loads popular movies', () => {\n    cy.intercept('/api/v1/discover/movies*').as('getPopularMovies');\n    cy.visit('/');\n    cy.wait('@getPopularMovies');\n    clickFirstTitleCardInSlider('Popular Movies');\n  });\n\n  it('loads upcoming movies', () => {\n    cy.intercept('/api/v1/discover/movies?page=1&primaryReleaseDateGte*').as(\n      'getUpcomingMovies'\n    );\n    cy.visit('/');\n    cy.wait('@getUpcomingMovies');\n    clickFirstTitleCardInSlider('Upcoming Movies');\n  });\n\n  it('loads popular series', () => {\n    cy.intercept('/api/v1/discover/tv*').as('getPopularTv');\n    cy.visit('/');\n    cy.wait('@getPopularTv');\n    clickFirstTitleCardInSlider('Popular Series');\n  });\n\n  it('loads upcoming series', () => {\n    cy.intercept('/api/v1/discover/tv?page=1&firstAirDateGte=*').as(\n      'getUpcomingSeries'\n    );\n    cy.visit('/');\n    cy.wait('@getUpcomingSeries');\n    clickFirstTitleCardInSlider('Upcoming Series');\n  });\n\n  it('displays error for media with invalid TMDB ID', () => {\n    cy.intercept('GET', '/api/v1/media?*', {\n      pageInfo: { pages: 1, pageSize: 20, results: 1, page: 1 },\n      results: [\n        {\n          downloadStatus: [],\n          downloadStatus4k: [],\n          id: 1922,\n          mediaType: 'movie',\n          tmdbId: 998814,\n          tvdbId: null,\n          imdbId: null,\n          status: 5,\n          status4k: 1,\n          createdAt: '2022-08-18T18:11:13.000Z',\n          updatedAt: '2022-08-18T19:56:41.000Z',\n          lastSeasonChange: '2022-08-18T19:56:41.000Z',\n          mediaAddedAt: '2022-08-18T19:56:41.000Z',\n          serviceId: null,\n          serviceId4k: null,\n          externalServiceId: null,\n          externalServiceId4k: null,\n          externalServiceSlug: null,\n          externalServiceSlug4k: null,\n          ratingKey: null,\n          ratingKey4k: null,\n          seasons: [],\n        },\n      ],\n    }).as('getMedia');\n\n    cy.visit('/');\n    cy.wait('@getMedia');\n    cy.contains('.slider-header', 'Recently Added')\n      .next('[data-testid=media-slider]')\n      .find('[data-testid=title-card]')\n      .first()\n      .find('[data-testid=title-card-title]')\n      .contains('Movie Not Found');\n  });\n\n  it('displays error for request with invalid TMDB ID', () => {\n    cy.intercept('GET', '/api/v1/request?*', {\n      pageInfo: { pages: 1, pageSize: 10, results: 1, page: 1 },\n      results: [\n        {\n          id: 582,\n          status: 1,\n          createdAt: '2022-08-18T18:11:13.000Z',\n          updatedAt: '2022-08-18T18:11:13.000Z',\n          type: 'movie',\n          is4k: false,\n          serverId: null,\n          profileId: null,\n          rootFolder: null,\n          languageProfileId: null,\n          tags: null,\n          media: {\n            downloadStatus: [],\n            downloadStatus4k: [],\n            id: 1922,\n            mediaType: 'movie',\n            tmdbId: 998814,\n            tvdbId: null,\n            imdbId: null,\n            status: 2,\n            status4k: 1,\n            createdAt: '2022-08-18T18:11:13.000Z',\n            updatedAt: '2022-08-18T18:11:13.000Z',\n            lastSeasonChange: '2022-08-18T18:11:13.000Z',\n            mediaAddedAt: null,\n            serviceId: null,\n            serviceId4k: null,\n            externalServiceId: null,\n            externalServiceId4k: null,\n            externalServiceSlug: null,\n            externalServiceSlug4k: null,\n            ratingKey: null,\n            ratingKey4k: null,\n          },\n          seasons: [],\n          modifiedBy: null,\n          requestedBy: {\n            permissions: 4194336,\n            id: 18,\n            email: 'friend@seerr.dev',\n            plexUsername: null,\n            username: '',\n            recoveryLinkExpirationDate: null,\n            userType: 2,\n            avatar:\n              'https://gravatar.com/avatar/c77fdc27cab83732b8623d2ea873d330?default=mm&size=200',\n            movieQuotaLimit: null,\n            movieQuotaDays: null,\n            tvQuotaLimit: null,\n            tvQuotaDays: null,\n            createdAt: '2022-08-17T04:55:28.000Z',\n            updatedAt: '2022-08-17T04:55:28.000Z',\n            requestCount: 1,\n            displayName: 'friend@seerr.dev',\n          },\n          seasonCount: 0,\n        },\n      ],\n    }).as('getRequests');\n\n    cy.visit('/');\n    cy.wait('@getRequests');\n    cy.contains('.slider-header', 'Recent Requests')\n      .next('[data-testid=media-slider]')\n      .find('[data-testid=request-card]')\n      .first()\n      .find('[data-testid=request-card-title]')\n      .contains('Movie Not Found');\n  });\n\n  it('loads plex watchlist', () => {\n    cy.intercept('/api/v1/discover/watchlist', {\n      fixture: 'watchlist.json',\n    }).as('getWatchlist');\n    // Wait for one of the watchlist movies to resolve\n    cy.intercept('/api/v1/movie/361743').as('getTmdbMovie');\n\n    cy.visit('/');\n\n    cy.wait('@getWatchlist');\n\n    const sliderHeader = cy.contains('.slider-header', 'Watchlist');\n\n    sliderHeader.scrollIntoView();\n\n    cy.wait('@getTmdbMovie');\n    // Wait a little longer to make sure the movie component reloaded\n    cy.wait(500);\n\n    sliderHeader\n      .next('[data-testid=media-slider]')\n      .find('[data-testid=title-card]')\n      .first()\n      .trigger('mouseover')\n      .find('[data-testid=title-card-title]')\n      .invoke('text')\n      .then((text) => {\n        cy.contains('.slider-header', 'Watchlist')\n          .next('[data-testid=media-slider]')\n          .find('[data-testid=title-card]')\n          .first()\n          .click();\n        cy.get('[data-testid=media-title]').should('contain', text);\n      });\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/login.cy.ts",
    "content": "describe('Login Page', () => {\n  it('succesfully logs in as an admin', () => {\n    cy.loginAsAdmin();\n    cy.visit('/');\n    cy.contains('Trending');\n  });\n\n  it('succesfully logs in as a local user', () => {\n    cy.loginAsUser();\n    cy.visit('/');\n    cy.contains('Trending');\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/movie-details.cy.ts",
    "content": "describe('Movie Details', () => {\n  it('loads a movie page', () => {\n    cy.loginAsAdmin();\n    // Try to load minions: rise of gru\n    cy.visit('/movie/438148');\n\n    cy.get('[data-testid=media-title]').should(\n      'contain',\n      'Minions: The Rise of Gru (2022)'\n    );\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/providers/tvdb.cy.ts",
    "content": "describe('TVDB Integration', () => {\n  // Constants for routes and selectors\n  const ROUTES = {\n    home: '/',\n    metadataSettings: '/settings/metadata',\n    tomorrowIsOursTvShow: '/tv/72879',\n    monsterTvShow: '/tv/225634',\n    dragonnBallZKaiAnime: '/tv/61709',\n  };\n\n  const SELECTORS = {\n    sidebarToggle: '[data-testid=sidebar-toggle]',\n    sidebarSettingsMobile: '[data-testid=sidebar-menu-settings-mobile]',\n    settingsNavDesktop: 'nav[data-testid=\"settings-nav-desktop\"]',\n    metadataTestButton: 'button[type=\"button\"]:contains(\"Test\")',\n    metadataSaveButton: '[data-testid=\"metadata-save-button\"]',\n    tmdbStatus: '[data-testid=\"tmdb-status\"]',\n    tvdbStatus: '[data-testid=\"tvdb-status\"]',\n    tvMetadataProviderSelector: '[data-testid=\"tv-metadata-provider-selector\"]',\n    animeMetadataProviderSelector:\n      '[data-testid=\"anime-metadata-provider-selector\"]',\n    seasonSelector: '[data-testid=\"season-selector\"]',\n    season1: 'Season 1',\n    season2: 'Season 2',\n    season3: 'Season 3',\n    episodeList: '[data-testid=\"episode-list\"]',\n    episode9: '9 - Hang Men',\n  };\n\n  // Reusable commands\n  const navigateToMetadataSettings = () => {\n    cy.visit(ROUTES.home);\n    cy.get(SELECTORS.sidebarToggle).click();\n    cy.get(SELECTORS.sidebarSettingsMobile).click();\n    cy.get(\n      `${SELECTORS.settingsNavDesktop} a[href=\"${ROUTES.metadataSettings}\"]`\n    ).click();\n  };\n\n  const testAndVerifyMetadataConnection = () => {\n    cy.intercept('POST', '/api/v1/settings/metadatas/test').as(\n      'testConnection'\n    );\n    cy.get(SELECTORS.metadataTestButton).click();\n    return cy.wait('@testConnection');\n  };\n\n  const saveMetadataSettings = (customBody = null) => {\n    if (customBody) {\n      cy.intercept('PUT', '/api/v1/settings/metadatas', (req) => {\n        req.body = customBody;\n      }).as('saveMetadata');\n    } else {\n      // Else just intercept without modifying body\n      cy.intercept('PUT', '/api/v1/settings/metadatas').as('saveMetadata');\n    }\n\n    cy.get(SELECTORS.metadataSaveButton).click();\n    return cy.wait('@saveMetadata');\n  };\n\n  beforeEach(() => {\n    // Perform login\n    cy.login(Cypress.env('ADMIN_EMAIL'), Cypress.env('ADMIN_PASSWORD'));\n\n    // Navigate to Metadata settings\n    navigateToMetadataSettings();\n\n    // Verify we're on the correct settings page\n    cy.contains('h3', 'Metadata Providers').should('be.visible');\n\n    // Configure TVDB as TV provider and test connection\n    cy.get(SELECTORS.tvMetadataProviderSelector).click();\n\n    // get id react-select-4-option-1\n    cy.get('[class*=\"react-select__option\"]').contains('TheTVDB').click();\n\n    // Test the connection\n    testAndVerifyMetadataConnection().then(({ response }) => {\n      expect(response.statusCode).to.equal(200);\n      // Check TVDB connection status\n      cy.get(SELECTORS.tvdbStatus).should('contain', 'Operational');\n    });\n\n    // Save settings\n    saveMetadataSettings({\n      anime: 'tvdb',\n      tv: 'tvdb',\n    }).then(({ response }) => {\n      expect(response.statusCode).to.equal(200);\n      expect(response.body.tv).to.equal('tvdb');\n    });\n  });\n\n  it('should display \"Tomorrow is Ours\" show information with multiple seasons from TVDB', () => {\n    // Navigate to the TV show\n    cy.visit(ROUTES.tomorrowIsOursTvShow);\n\n    // Verify that multiple seasons are displayed (TMDB has only 1 season, TVDB has multiple)\n    // cy.get(SELECTORS.seasonSelector).should('exist');\n    cy.intercept('/api/v1/tv/225634/season/1').as('season1');\n    // Select Season 2 and verify it loads\n    cy.contains(SELECTORS.season2)\n      .should('be.visible')\n      .scrollIntoView()\n      .click();\n\n    // Verify that episodes are displayed for Season 2\n    cy.contains('260 - Episode 506').should('be.visible');\n  });\n\n  it('Should display \"Monster\" show information correctly when not existing on TVDB', () => {\n    // Navigate to the TV show\n    cy.visit(ROUTES.monsterTvShow);\n\n    // Intercept season 1 request\n    cy.intercept('/api/v1/tv/225634/season/1').as('season1');\n\n    // Select Season 1\n    cy.contains(SELECTORS.season1)\n      .should('be.visible')\n      .scrollIntoView()\n      .click();\n\n    // Wait for the season data to load\n    cy.wait('@season1');\n\n    // Verify specific episode exists\n    cy.contains(SELECTORS.episode9).should('be.visible');\n  });\n\n  it('should display \"Dragon Ball Z Kai\" show information with multiple only 2 seasons from TVDB', () => {\n    // Navigate to the TV show\n    cy.visit(ROUTES.dragonnBallZKaiAnime);\n\n    // Intercept season 1 request\n    cy.intercept('/api/v1/tv/61709/season/1').as('season1');\n\n    // Select Season 2 and verify it visible\n    cy.contains(SELECTORS.season2)\n      .should('be.visible')\n      .scrollIntoView()\n      .click();\n\n    // select season 3 and verify it not visible\n    cy.contains(SELECTORS.season3).should('not.exist');\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/pull-to-refresh.cy.ts",
    "content": "describe('Pull To Refresh', () => {\n  beforeEach(() => {\n    cy.login(Cypress.env('ADMIN_EMAIL'), Cypress.env('ADMIN_PASSWORD'));\n    cy.viewport(390, 844);\n    cy.visitMobile('/');\n  });\n\n  it('reloads the current page', () => {\n    cy.wait(500);\n\n    cy.intercept({\n      method: 'GET',\n      url: '/api/v1/*',\n    }).as('apiCall');\n\n    cy.get('.searchbar').swipe('bottom', [190, 500]);\n\n    cy.wait('@apiCall').then((interception) => {\n      assert.isNotNull(\n        interception.response.body,\n        'API was called and received data'\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/settings/discover-customization.cy.ts",
    "content": "describe('Discover Customization', () => {\n  beforeEach(() => {\n    cy.loginAsAdmin();\n    cy.intercept('/api/v1/settings/discover').as('getDiscoverSliders');\n  });\n\n  it('show the discover customization settings', () => {\n    cy.visit('/');\n\n    cy.get('[data-testid=discover-start-editing]').click();\n\n    cy.get('[data-testid=create-slider-header')\n      .should('contain', 'Create New Slider')\n      .scrollIntoView();\n\n    // There should be some built in options\n    cy.get('[data-testid=discover-slider-edit-mode]').should(\n      'contain',\n      'Recently Added'\n    );\n    cy.get('[data-testid=discover-slider-edit-mode]').should(\n      'contain',\n      'Recent Requests'\n    );\n  });\n\n  it('can drag to re-order elements and save to persist the changes', () => {\n    let dataTransfer = new DataTransfer();\n    cy.visit('/');\n\n    cy.get('[data-testid=discover-start-editing]').click();\n\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .first()\n      .trigger('dragstart', { dataTransfer });\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .eq(1)\n      .trigger('drop', { dataTransfer });\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .eq(1)\n      .trigger('dragend', { dataTransfer });\n\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .eq(1)\n      .should('contain', 'Recently Added');\n\n    cy.get('[data-testid=discover-customize-submit').click();\n    cy.wait('@getDiscoverSliders');\n\n    cy.reload();\n\n    cy.get('[data-testid=discover-start-editing]').click();\n\n    dataTransfer = new DataTransfer();\n\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .eq(1)\n      .should('contain', 'Recently Added');\n\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .first()\n      .trigger('dragstart', { dataTransfer });\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .eq(1)\n      .trigger('drop', { dataTransfer });\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .eq(1)\n      .trigger('dragend', { dataTransfer });\n\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .eq(1)\n      .should('contain', 'Recent Requests');\n\n    cy.get('[data-testid=discover-customize-submit').click();\n    cy.wait('@getDiscoverSliders');\n  });\n\n  it('can create a new discover option and remove it', () => {\n    cy.visit('/');\n    cy.intercept('/api/v1/settings/discover/*').as('discoverSlider');\n    cy.intercept('/api/v1/search/keyword*').as('searchKeyword');\n\n    cy.get('[data-testid=discover-start-editing]').click();\n\n    const sliderTitle = 'Custom Keyword Slider';\n\n    cy.get('#sliderType').select('TMDB Movie Keyword');\n\n    cy.get('#title').type(sliderTitle);\n    // First confirm that an invalid keyword doesn't allow us to submit anything\n    cy.get('#data').type('invalidkeyword{enter}', { delay: 100 });\n    cy.wait('@searchKeyword');\n\n    cy.get('[data-testid=create-discover-option-form]')\n      .find('button')\n      .should('be.disabled');\n\n    cy.get('#data').clear();\n    cy.get('#data').type('christmas{enter}', { delay: 100 });\n\n    // Confirming we have some results\n    cy.contains('.slider-header', sliderTitle)\n      .next('[data-testid=media-slider]')\n      .find('[data-testid=title-card]');\n\n    cy.get('[data-testid=create-discover-option-form]').submit();\n\n    cy.wait('@discoverSlider');\n    cy.wait('@getDiscoverSliders');\n    cy.wait(1000);\n\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .first()\n      .should('contain', sliderTitle);\n\n    // Make sure its still there even if we reload\n    cy.reload();\n\n    cy.get('[data-testid=discover-start-editing]').click();\n\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .first()\n      .should('contain', sliderTitle);\n\n    // Verify it's not rendering on our discover page (its still disabled!)\n    cy.visit('/');\n\n    cy.get('.slider-header').should('not.contain', sliderTitle);\n\n    cy.get('[data-testid=discover-start-editing]').click();\n\n    // Enable it, and check again\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .first()\n      .find('[role=\"checkbox\"]')\n      .click();\n\n    cy.get('[data-testid=discover-customize-submit').click();\n    cy.wait('@getDiscoverSliders');\n\n    cy.visit('/');\n\n    cy.contains('.slider-header', sliderTitle)\n      .next('[data-testid=media-slider]')\n      .find('[data-testid=title-card]');\n\n    cy.get('[data-testid=discover-start-editing]').click();\n\n    // let's delete it and confirm its deleted.\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .first()\n      .find('[data-testid=discover-slider-remove-button]')\n      .click();\n\n    cy.wait('@discoverSlider');\n    cy.wait('@getDiscoverSliders');\n    cy.wait(1000);\n\n    cy.get('[data-testid=discover-slider-edit-mode]')\n      .first()\n      .should('not.contain', sliderTitle);\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/settings/general-settings.cy.ts",
    "content": "describe('General Settings', () => {\n  beforeEach(() => {\n    cy.loginAsAdmin();\n  });\n\n  it('opens the settings page from the home page', () => {\n    cy.visit('/');\n\n    cy.get('[data-testid=sidebar-toggle]').click();\n    cy.get('[data-testid=sidebar-menu-settings-mobile]').click();\n\n    cy.get('.heading').should('contain', 'General Settings');\n  });\n\n  it('modifies setting that requires restart', () => {\n    cy.visit('/settings/network');\n\n    cy.get('#trustProxy').click();\n    cy.get('[data-testid=settings-network-form]').submit();\n    cy.get('[data-testid=modal-title]').should(\n      'contain',\n      'Server Restart Required'\n    );\n\n    cy.get('[data-testid=modal-ok-button]').click();\n    cy.get('[data-testid=modal-title]').should('not.exist');\n\n    cy.get('[type=checkbox]#trustProxy').click();\n    cy.get('[data-testid=settings-network-form]').submit();\n    cy.get('[data-testid=modal-title]').should('not.exist');\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/tv-details.cy.ts",
    "content": "describe('TV Details', () => {\n  it('loads a tv details page', () => {\n    cy.loginAsAdmin();\n    // Try to load stranger things\n    cy.visit('/tv/66732');\n\n    cy.get('[data-testid=media-title]').should(\n      'contain',\n      'Stranger Things (2016)'\n    );\n  });\n\n  it('shows seasons and expands episodes', () => {\n    cy.loginAsAdmin();\n\n    // Try to load stranger things\n    cy.visit('/tv/66732');\n\n    // intercept request for season info\n    cy.intercept('/api/v1/tv/66732/season/4').as('season4');\n\n    cy.contains('Season 4').should('be.visible').scrollIntoView().click();\n\n    cy.wait('@season4');\n\n    cy.contains('Chapter Nine').should('be.visible');\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/user/auto-request-settings.cy.ts",
    "content": "const visitUserEditPage = (email: string): void => {\n  cy.visit('/users');\n\n  cy.contains('[data-testid=user-list-row]', email).contains('Edit').click();\n};\n\ndescribe('Auto Request Settings', () => {\n  beforeEach(() => {\n    cy.loginAsAdmin();\n  });\n\n  it('should not see watchlist sync settings on an account without permissions', () => {\n    visitUserEditPage(Cypress.env('USER_EMAIL'));\n\n    cy.contains('Auto-Request Movies').should('not.exist');\n    cy.contains('Auto-Request Series').should('not.exist');\n  });\n\n  it('should see watchlist sync settings on an admin account', () => {\n    visitUserEditPage(Cypress.env('ADMIN_EMAIL'));\n\n    cy.contains('Auto-Request Movies').should('exist');\n    cy.contains('Auto-Request Series').should('exist');\n  });\n\n  it('should see auto-request settings after being given permission', () => {\n    visitUserEditPage(Cypress.env('USER_EMAIL'));\n\n    cy.get('[data-testid=settings-nav-desktop').contains('Permissions').click();\n\n    cy.get('#autorequest').should('not.be.checked').click();\n\n    cy.intercept('/api/v1/user/*/settings/permissions').as('userPermissions');\n\n    cy.contains('Save Changes').click();\n\n    cy.wait('@userPermissions');\n\n    cy.reload();\n\n    cy.get('#autorequest').should('be.checked');\n    cy.get('#autorequestmovies').should('be.checked');\n    cy.get('#autorequesttv').should('be.checked');\n\n    cy.get('[data-testid=settings-nav-desktop').contains('General').click();\n\n    cy.contains('Auto-Request Movies').should('exist');\n    cy.contains('Auto-Request Series').should('exist');\n\n    cy.get('#watchlistSyncMovies').should('not.be.checked').click();\n    cy.get('#watchlistSyncTv').should('not.be.checked').click();\n\n    cy.intercept('/api/v1/user/*/settings/main').as('userMain');\n\n    cy.contains('Save Changes').click();\n\n    cy.wait('@userMain');\n\n    cy.reload();\n\n    cy.get('#watchlistSyncMovies').should('be.checked').click();\n    cy.get('#watchlistSyncTv').should('be.checked').click();\n\n    cy.contains('Save Changes').click();\n\n    cy.wait('@userMain');\n\n    cy.get('[data-testid=settings-nav-desktop').contains('Permissions').click();\n\n    cy.get('#autorequest').should('be.checked').click();\n\n    cy.contains('Save Changes').click();\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/user/profile.cy.ts",
    "content": "describe('User Profile', () => {\n  beforeEach(() => {\n    cy.loginAsAdmin();\n  });\n\n  it('opens user profile page from the home page', () => {\n    cy.visit('/');\n\n    cy.get('[data-testid=user-menu]').click();\n    cy.get('[data-testid=user-menu-profile]').click();\n\n    cy.get('h1').should('contain', Cypress.env('ADMIN_EMAIL'));\n  });\n\n  it('loads plex watchlist', () => {\n    cy.intercept('/api/v1/user/[0-9]*/watchlist', {\n      fixture: 'watchlist.json',\n    }).as('getWatchlist');\n    // Wait for one of the watchlist movies to resolve\n    cy.intercept('/api/v1/movie/361743').as('getTmdbMovie');\n\n    cy.visit('/profile');\n\n    cy.wait('@getWatchlist');\n\n    const sliderHeader = cy.contains('.slider-header', 'Plex Watchlist');\n\n    sliderHeader.scrollIntoView();\n\n    cy.wait('@getTmdbMovie');\n    // Wait a little longer to make sure the movie component reloaded\n    cy.wait(500);\n\n    sliderHeader\n      .next('[data-testid=media-slider]')\n      .find('[data-testid=title-card]')\n      .first()\n      .trigger('mouseover')\n      .find('[data-testid=title-card-title]')\n      .invoke('text')\n      .then((text) => {\n        cy.contains('.slider-header', 'Plex Watchlist')\n          .next('[data-testid=media-slider]')\n          .find('[data-testid=title-card]')\n          .first()\n          .click();\n        cy.get('[data-testid=media-title]').should('contain', text);\n      });\n  });\n});\n"
  },
  {
    "path": "cypress/e2e/user/user-list.cy.ts",
    "content": "const testUser = {\n  username: 'Test User',\n  emailAddress: 'test@seeerr.dev',\n  password: 'test1234',\n};\n\ndescribe('User List', () => {\n  beforeEach(() => {\n    cy.loginAsAdmin();\n  });\n\n  it('opens the user list from the home page', () => {\n    cy.visit('/');\n\n    cy.get('[data-testid=sidebar-toggle]').click();\n    cy.get('[data-testid=sidebar-menu-users-mobile]').click();\n\n    cy.get('[data-testid=page-header]').should('contain', 'User List');\n  });\n\n  it('can find the admin user and friend user in the user list', () => {\n    cy.visit('/users');\n\n    cy.get('[data-testid=user-list-row]').contains(Cypress.env('ADMIN_EMAIL'));\n    cy.get('[data-testid=user-list-row]').contains(Cypress.env('USER_EMAIL'));\n  });\n\n  it('can create a local user', () => {\n    cy.visit('/users');\n\n    cy.contains('Create Local User').click();\n\n    cy.get('[data-testid=modal-title]').should('contain', 'Create Local User');\n\n    cy.get('#username').type(testUser.username);\n    cy.get('#email').type(testUser.emailAddress);\n    cy.get('#password').type(testUser.password);\n\n    cy.intercept('/api/v1/user?take=10&skip=0&sort=displayname').as('user');\n\n    cy.get('[data-testid=modal-ok-button]').click();\n\n    cy.wait('@user');\n    // Wait a little longer for the user list to fully re-render\n    cy.wait(1000);\n\n    cy.get('[data-testid=user-list-row]').contains(testUser.emailAddress);\n  });\n\n  it('can delete the created local test user', () => {\n    cy.visit('/users');\n\n    cy.contains('[data-testid=user-list-row]', testUser.emailAddress)\n      .contains('Delete')\n      .click();\n\n    cy.get('[data-testid=modal-title]').should('contain', `Delete User`);\n\n    cy.intercept('/api/v1/user?take=10&skip=0&sort=displayname').as('user');\n\n    cy.get('[data-testid=modal-ok-button]').should('contain', 'Delete').click();\n\n    cy.wait('@user');\n    cy.wait(1000);\n\n    cy.get('[data-testid=user-list-row]')\n      .contains(testUser.emailAddress)\n      .should('not.exist');\n  });\n});\n"
  },
  {
    "path": "cypress/fixtures/watchlist.json",
    "content": "{\n  \"page\": 1,\n  \"totalPages\": 1,\n  \"totalResults\": 3,\n  \"results\": [\n    {\n      \"ratingKey\": \"5d776be17a53e9001e732ab9\",\n      \"title\": \"Top Gun: Maverick\",\n      \"mediaType\": \"movie\",\n      \"tmdbId\": 361743\n    },\n    {\n      \"ratingKey\": \"5e16338fbc1372003ea68ab3\",\n      \"title\": \"Nope\",\n      \"mediaType\": \"movie\",\n      \"tmdbId\": 762504\n    },\n    {\n      \"ratingKey\": \"5f409b8452f200004161e126\",\n      \"title\": \"Hocus Pocus 2\",\n      \"mediaType\": \"movie\",\n      \"tmdbId\": 642885\n    }\n  ]\n}\n"
  },
  {
    "path": "cypress/support/commands.ts",
    "content": "/// <reference types=\"cypress\" />\nimport 'cy-mobile-commands';\n\nCypress.Commands.add('login', (email, password) => {\n  cy.session(\n    [email, password],\n    () => {\n      cy.visit('/login');\n\n      cy.get('[data-testid=email]').type(email);\n      cy.get('[data-testid=password]').type(password);\n\n      cy.intercept('/api/v1/auth/local').as('localLogin');\n      cy.get('[data-testid=local-signin-button]').click();\n\n      cy.wait('@localLogin');\n\n      cy.url().should('contain', '/');\n    },\n    {\n      validate() {\n        cy.request('/api/v1/auth/me').its('status').should('eq', 200);\n      },\n    }\n  );\n});\n\nCypress.Commands.add('loginAsAdmin', () => {\n  cy.login(Cypress.env('ADMIN_EMAIL'), Cypress.env('ADMIN_PASSWORD'));\n});\n\nCypress.Commands.add('loginAsUser', () => {\n  cy.login(Cypress.env('USER_EMAIL'), Cypress.env('USER_PASSWORD'));\n});\n"
  },
  {
    "path": "cypress/support/e2e.ts",
    "content": "import './commands';\n\nbefore(() => {\n  if (Cypress.env('SEED_DATABASE')) {\n    cy.exec('pnpm cypress:prepare');\n  }\n});\n"
  },
  {
    "path": "cypress/support/index.ts",
    "content": "/* eslint-disable @typescript-eslint/no-namespace */\n/// <reference types=\"cypress\" />\n\ndeclare global {\n  namespace Cypress {\n    interface Chainable {\n      login(email?: string, password?: string): Chainable<Element>;\n      loginAsAdmin(): Chainable<Element>;\n      loginAsUser(): Chainable<Element>;\n    }\n  }\n}\n\nexport {};\n"
  },
  {
    "path": "cypress/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"es5\", \"dom\"],\n    \"types\": [\"cypress\", \"node\"],\n    \"resolveJsonModule\": true,\n    \"esModuleInterop\": true\n  },\n  \"include\": [\"**/*.ts\"]\n}\n"
  },
  {
    "path": "cypress.config.ts",
    "content": "import { defineConfig } from 'cypress';\n\nexport default defineConfig({\n  projectId: 'onnqy3',\n  e2e: {\n    baseUrl: 'http://localhost:5055',\n    video: true,\n  },\n  env: {\n    ADMIN_EMAIL: 'admin@seerr.dev',\n    ADMIN_PASSWORD: 'test1234',\n    USER_EMAIL: 'friend@seerr.dev',\n    USER_PASSWORD: 'test1234',\n  },\n  retries: {\n    runMode: 2,\n    openMode: 0,\n  },\n});\n"
  },
  {
    "path": "docs/README.md",
    "content": "---\nslug: /\nsidebar_position: 1\n---\n\n# Introduction\n\nWelcome to the Seerr Documentation.\n\n**Seerr** is a free and open source software application for managing requests for your media library. It integrates with the media server of your choice: [Jellyfin](https://jellyfin.org), [Plex](https://plex.tv), and [Emby](https://emby.media/). In addition, it integrates with your existing services, such as **[Sonarr](https://sonarr.tv/)**, **[Radarr](https://radarr.video/)**.\n\n## Features\n\n- **Full Jellyfin/Emby/Plex integration**. Login and manage user access with Jellyfin/Emby/Plex.\n- **Syncs to your Jellyfin/Emby/Plex library** to show what titles you already have.\n- Supports Movies, Shows and Mixed Libraries.\n- **Integrates with Sonarr and Radarr**. With more services to come in the future.\n- Optionally set **Override rules** for requests to match with your defined conditions.\n- **Easy to use request system** allowing users to request individual seasons or movies in a friendly, clean UI.\n- **Simple request management UI**. Don't dig through the app to approve recent requests.\n- **Mobile-friendly design**, for when you need to approve requests on the go.\n- Granular permission system.\n- Localization into other languages.\n- Support for **PostgreSQL** and **SQLite** databases.\n- Support for various notification agents.\n- Easily **Watchlist** or **Blocklist** media.\n- More features to come!\n\n## We need your help!\n\n[Seerr](https://github.com/seerr-team/seerr) is an ambitious project developers/contributors poured a lot of work into, and we still have a lot more to do. Seerr is the result of a collaborative effort between the original Overseerr project and the Jellyseerr fork, created to deliver an excellent request management solution for Plex, Jellyfin and Emby users.\n\nWe value your feedback and support in identifying and fixing bugs to make Seerr even better. As an open-source project, we welcome contributions from everyone. Contribution includes building new features, patching bugs, translating the application, or even just writing documentation.\n\nIf you would like to contribute, please be sure to review our [contribution guidelines](https://github.com/seerr-team/seerr/blob/develop/CONTRIBUTING.md).\n"
  },
  {
    "path": "docs/extending-seerr/_category_.json",
    "content": "{\n  \"label\": \"Extending Seerr\",\n  \"position\": 3,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"title\": \"Extending Seerr\",\n    \"description\": \"Extend Seerr to your liking\"\n  }\n}\n"
  },
  {
    "path": "docs/extending-seerr/database-config.mdx",
    "content": "---\ntitle: Configuring the Database (Advanced)\ndescription: Configure the database for Seerr\nsidebar_position: 2\n---\n# Configuring the Database\n\nSeerr supports SQLite and PostgreSQL. The database connection can be configured using the following environment variables:\n\n## SQLite Options\n\nIf you want to use SQLite, you can simply set the `DB_TYPE` environment variable to `sqlite`. This is the default configuration so even if you don't set any other options, SQLite will be used.\n\n```dotenv\nDB_TYPE=sqlite # Which DB engine to use, either sqlite or postgres. The default is sqlite.\nCONFIG_DIRECTORY=\"config\" # (optional) The path to the config directory where the db file is stored. The default is \"config\".\nDB_LOG_QUERIES=\"false\" # (optional) Whether to log the DB queries for debugging. The default is \"false\".\n```\n\n## PostgreSQL Options\n\n:::caution\nWhen migrating Postgres from version 17 to 18 in Docker, note that the data mount point has changed. Instead of using `/var/lib/postgresql/data`, the correct mount path is now `/var/lib/postgresql`.\nRefer to the [PostgreSQL Docker documentation](https://hub.docker.com/_/postgres/#pgdata) to learn how to migrate or opt out of this change.\n:::\n\n### TCP Connection\n\nIf your PostgreSQL server is configured to accept TCP connections, you can specify the host and port using the `DB_HOST` and `DB_PORT` environment variables. This is useful for remote connections where the server uses a network host and port.\n\n```dotenv\nDB_TYPE=postgres # Which DB engine to use, either sqlite or postgres. The default is sqlite.\nDB_HOST=localhost # (optional) The host (URL) of the database. The default is \"localhost\".\nDB_PORT=\"5432\" # (optional) The port to connect to. The default is \"5432\".\nDB_USER= # (required) Username used to connect to the database.\nDB_PASS= # (required) Password of the user used to connect to the database.\nDB_NAME=\"seerr\" # (optional) The name of the database to connect to. The default is \"seerr\".\nDB_LOG_QUERIES=\"false\" # (optional) Whether to log the DB queries for debugging. The default is \"false\".\n```\n\n### Unix Socket Connection\n\nIf your PostgreSQL server is configured to accept Unix socket connections, you can specify the path to the socket directory using the `DB_SOCKET_PATH` environment variable. This is useful for local connections where the server uses a Unix socket.\n\n```dotenv\nDB_TYPE=postgres # Which DB engine to use, either sqlite or postgres. The default is sqlite.\nDB_SOCKET_PATH=\"/var/run/postgresql\" # (required) The path to the PostgreSQL Unix socket directory.\nDB_USER= # (required) Username used to connect to the database.\nDB_PASS= # (optional) Password of the user used to connect to the database, depending on the server's authentication configuration.\nDB_NAME=\"seerr\" # (optional) The name of the database to connect to. The default is \"seerr\".\nDB_LOG_QUERIES=\"false\" # (optional) Whether to log the DB queries for debugging. The default is \"false\".\n```\n\n:::info\n**Finding Your PostgreSQL Socket Path**\n\nThe PostgreSQL socket path varies by operating system and installation method:\n\n- **Ubuntu/Debian**: `/var/run/postgresql`\n- **CentOS/RHEL/Fedora**: `/var/run/postgresql`\n- **macOS (Homebrew)**: `/tmp` or `/opt/homebrew/var/postgresql`\n- **macOS (Postgres.app)**: `/tmp`\n- **Windows**: Not applicable (uses TCP connections)\n\nYou can find your socket path by running:\n```bash\n# Find PostgreSQL socket directory\nfind /tmp /var/run /run -name \".s.PGSQL.*\" 2>/dev/null | head -1 | xargs dirname\n\n# Or check PostgreSQL configuration\nsudo -u postgres psql -c \"SHOW unix_socket_directories;\"\n```\n:::\n\n### SSL configuration\n\nThe following options can be used to further configure ssl. Certificates can be provided as a string or a file path, with the string version taking precedence.\n\n```dotenv\nDB_USE_SSL=\"false\" # (optional) Whether to enable ssl for database connection. This must be \"true\" to use the other ssl options. The default is \"false\".\nDB_SSL_REJECT_UNAUTHORIZED=\"true\" # (optional) Whether to reject ssl connections with unverifiable certificates i.e. self-signed certificates without providing the below settings. The default is \"true\".\nDB_SSL_CA= # (optional) The CA certificate to verify the connection, provided as a string. The default is \"\".\nDB_SSL_CA_FILE= # (optional) The path to a CA certificate to verify the connection. The default is \"\".\nDB_SSL_KEY= # (optional) The private key for the connection in PEM format, provided as a string. The default is \"\".\nDB_SSL_KEY_FILE= # (optional) Path to the private key for the connection in PEM format. The default is \"\".\nDB_SSL_CERT= # (optional) Certificate chain in pem format for the private key, provided as a string. The default is \"\".\nDB_SSL_CERT_FILE= # (optional) Path to certificate chain in pem format for the private key. The default is \"\".\n```\n\n---\n\n### Migrating from SQLite to PostgreSQL\n\n1. Set up your PostgreSQL database and configure Seerr to use it\n2. Run Seerr to create the tables in the PostgreSQL database\n3. Stop Seerr\n4. Run the following command to export the data from the SQLite database and import it into the PostgreSQL database:\n\n:::info\nEdit the postgres connection string (without the \\{\\{ and \\}\\} brackets) to match your setup.\n\nIf you don't have or don't want to use docker, you can build the working pgloader version [in this PR](https://github.com/dimitri/pgloader/pull/1531) from source and use the same options as below.\n:::\n\n:::caution\nThe most recent release of pgloader has an issue quoting the table columns. Use the version in the docker container to avoid this issue.\n:::\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n<Tabs>\n<TabItem value=\"docker\" label=\"Using pgloader Container (Recommended)\" default>\n\n**Recommended method**: Use the pgloader container even for standalone Seerr installations. This avoids building from source and ensures compatibility.\n\n```bash\n# For standalone installations (no Docker network needed)\ndocker run --rm \\\n  -v /path/to/your/config/db.sqlite3:/db.sqlite3:ro \\\n  ghcr.io/ralgar/pgloader:pr-1531 \\\n  pgloader --with \"quote identifiers\" --with \"data only\" \\\n  /db.sqlite3 postgresql://{{DB_USER}}:{{DB_PASS}}@{{DB_HOST}}:{{DB_PORT}}/{{DB_NAME}}\n```\n\n**For Docker Compose setups**: Add the network parameter if your PostgreSQL is also in a container:\n```bash\ndocker run --rm \\\n  --network your-seerr-network \\\n  -v /path/to/your/config/db.sqlite3:/db.sqlite3:ro \\\n  ghcr.io/ralgar/pgloader:pr-1531 \\\n  pgloader --with \"quote identifiers\" --with \"data only\" \\\n  /db.sqlite3 postgresql://{{DB_USER}}:{{DB_PASS}}@{{DB_HOST}}:{{DB_PORT}}/{{DB_NAME}}\n```\n\n</TabItem>\n<TabItem value=\"standalone\" label=\"Building pgloader from Source\">\n\nFor users who prefer not to use Docker or need a custom build:\n\n```bash\n# Clone the repository and checkout the working version\ngit clone https://github.com/dimitri/pgloader.git\ncd pgloader\ngit fetch origin pull/1531/head:pr-1531\ngit checkout pr-1531\n\n# Follow the official installation instructions\n# See: https://github.com/dimitri/pgloader/blob/master/INSTALL.md\n```\n\n:::info\n**Building pgloader from source requires following the complete installation process outlined in the [official pgloader INSTALL.md](https://github.com/dimitri/pgloader/blob/master/INSTALL.md).**\n\nPlease refer to the official documentation for detailed, up-to-date installation instructions.\n:::\n\nOnce pgloader is built, run the migration:\n\n```bash\n# Run migration (adjust path to your config directory)\n./pgloader --with \"quote identifiers\" --with \"data only\" \\\n  /path/to/your/config/db.sqlite3 \\\n  postgresql://{{DB_USER}}:{{DB_PASS}}@{{DB_HOST}}:{{DB_PORT}}/{{DB_NAME}}\n```\n\n</TabItem>\n</Tabs>\n\n5. Start Seerr\n"
  },
  {
    "path": "docs/extending-seerr/reverse-proxy.mdx",
    "content": "---\ntitle: Reverse Proxy\ndescription: Configure a reverse proxy for Seerr.\nsidebar_position: 1\n---\n\n# Reverse Proxy\n\n:::warning\nBase URLs cannot be configured in Seerr. With this limitation, only subdomain configurations are supported.\n\nA Nginx subfolder workaround configuration is provided below, but it is not officially supported.\n:::\n\n## Nginx\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n<Tabs groupId=\"nginx-reverse-proxy\" queryString>\n    <TabItem value=\"subdomain\" label=\"Subdomain\">\nAdd the following configuration to a new file `/etc/nginx/sites-available/seerr.example.com.conf`:\n\n```nginx\nserver {\n    listen 80;\n    server_name seerr.example.com;\n    return 301 https://$server_name$request_uri;\n}\n\nserver {\n    listen 443 ssl http2;\n    server_name seerr.example.com;\n\n    ssl_certificate /etc/letsencrypt/live/seerr.example.com/fullchain.pem;\n    ssl_certificate_key /etc/letsencrypt/live/seerr.example.com/privkey.pem;\n\n    proxy_set_header Referer $http_referer;\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Real-Port $remote_port;\n    proxy_set_header X-Forwarded-Host $host:$remote_port;\n    proxy_set_header X-Forwarded-Server $host;\n    proxy_set_header X-Forwarded-Port $remote_port;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_set_header X-Forwarded-Proto $scheme;\n    proxy_set_header X-Forwarded-Ssl on;\n\n    location / {\n        proxy_pass http://127.0.0.1:5055;\n    }\n}\n```\n\nThen, create a symlink to `/etc/nginx/sites-enabled`:\n\n```bash\nsudo ln -s /etc/nginx/sites-available/seerr.example.com.conf /etc/nginx/sites-enabled/seerr.example.com.conf\n```\n\n    </TabItem>\n\n    <TabItem value=\"subfolder\" label=\"Subfolder\">\n\n:::warning\nThis Nginx subfolder reverse proxy is an unsupported workaround, and only provided as an example. The filters may stop working when Seerr is updated.\n\nIf you encounter any issues with Seerr while using this workaround, we may ask you to try to reproduce the problem without the Nginx proxy.\n:::\n\nAdd the following location block to your existing `nginx.conf` file.\n\n```nginx\nlocation ^~ /seerr {\n    set $app 'seerr';\n\n    # Remove /seerr path to pass to the app\n    rewrite ^/seerr/?(.*)$ /$1 break;\n    proxy_pass http://127.0.0.1:5055; # NO TRAILING SLASH\n\n    # Redirect location headers\n    proxy_redirect ^ /$app;\n    proxy_redirect /setup /$app/setup;\n    proxy_redirect /login /$app/login;\n\n    # Sub filters to replace hardcoded paths\n    proxy_set_header Accept-Encoding \"\";\n    sub_filter_once off;\n    sub_filter_types *;\n    sub_filter 'href=\"/\"' 'href=\"/$app\"';\n    sub_filter 'href=\"/login\"' 'href=\"/$app/login\"';\n    sub_filter 'href:\"/\"' 'href:\"/$app\"';\n    sub_filter '\\/_next' '\\/$app\\/_next';\n    sub_filter '/_next' '/$app/_next';\n    sub_filter '/api/v1' '/$app/api/v1';\n    sub_filter '/login/plex/loading' '/$app/login/plex/loading';\n    sub_filter '/images/' '/$app/images/';\n    sub_filter '/imageproxy/' '/$app/imageproxy/';\n    sub_filter '/avatarproxy/' '/$app/avatarproxy/';\n    sub_filter '/android-' '/$app/android-';\n    sub_filter '/apple-' '/$app/apple-';\n    sub_filter '/favicon' '/$app/favicon';\n    sub_filter '/logo_' '/$app/logo_';\n    sub_filter '/site.webmanifest' '/$app/site.webmanifest';\n}\n```\n\n    </TabItem>\n\n    <TabItem value=\"swag\" label=\"SWAG\">\n\nA sample proxy configuration is included in [SWAG (Secure Web Application Gateway)](https://github.com/linuxserver/docker-swag).\n\nHowever, 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).\n\nTo use the bundled configuration file, simply rename `seerr.subdomain.conf.sample` in the `proxy-confs` folder to `seerr.subdomain.conf`.\n\nAlternatively, you can create a new file `seerr.subdomain.conf` in `proxy-confs` with the following configuration:\n\n```nginx\nserver {\n    listen 443 ssl http2;\n    listen [::]:443 ssl http2;\n\n    server_name seerr.*;\n\n    include /config/nginx/ssl.conf;\n\n    client_max_body_size 0;\n\n    location / {\n        include /config/nginx/proxy.conf;\n        resolver 127.0.0.11 valid=30s;\n        set $upstream_app seerr;\n        set $upstream_port 5055;\n        set $upstream_proto http;\n        proxy_pass $upstream_proto://$upstream_app:$upstream_port;\n    }\n\n}\n```\n\n</TabItem>\n\n    <TabItem value=\"nginx-proxy-manager\" label=\"Nginx Proxy Manager\">\n\nAdd a new proxy host with the following settings:\n\n### Details\n\n- **Domain Names:** Your desired external Seerr hostname; e.g., `seerr.example.com`\n- **Scheme:** `http`\n- **Forward Hostname / IP:** Internal Seerr hostname or IP\n- **Forward Port:** `5055`\n- **Cache Assets:** yes\n- **Block Common Exploits:** yes\n\n### SSL\n\n- **SSL Certificate:** Select one of the options; if you are not sure, pick “Request a new SSL Certificate”\n- **Force SSL:** yes\n- **HTTP/2 Support:** yes\n\nThen, click “Save” and “Apply Changes”.\n\n      </TabItem>\n\n  </Tabs>\n\n## Caddy (v2)\n\nCreate a Caddyfile with the following content:\n\n```caddyfile\nseerr.example.com {\n    reverse_proxy http://127.0.0.1:5055\n}\n```\n\nDeploy the Caddyfile by running:\n\n```bash\n\nsudo caddy run --config /path/to/Caddyfile\n```\n\nVerify by visiting https://seerr.example.com in your browser.\n\n:::note\nCaddy will automatically obtain and renew SSL certificates for your domain.\n:::\n\n## Traefik (v2)\n\nAdd the following labels to the Seerr service in your `compose.yaml` file:\n\n```yaml\nlabels:\n  - 'traefik.enable=true'\n  ## HTTP Routers\n  - 'traefik.http.routers.seerr-rtr.entrypoints=https'\n  - 'traefik.http.routers.seerr-rtr.rule=Host(`seerr.domain.com`)'\n  - 'traefik.http.routers.seerr-rtr.tls=true'\n  ## HTTP Services\n  - 'traefik.http.routers.seerr-rtr.service=seerr-svc'\n  - 'traefik.http.services.seerr-svc.loadbalancer.server.port=5055'\n```\n\nFor more information, please refer to the [Traefik documentation](https://doc.traefik.io/traefik/user-guides/docker-compose/basic-example/).\n\n## Apache2 HTTP Server\n\n<Tabs groupId=\"apache2-reverse-proxy\" queryString>\n    <TabItem value=\"subdomain\" label=\"Subdomain\">\n\nAdd the following Location block to your existing Server configuration.\n\n```apache\n# Seerr\n\t\tProxyPreserveHost On\n\t\tProxyPass / http://localhost:5055 retry=0 connectiontimeout=5 timeout=30 keepalive=on\n\t\tProxyPassReverse http://localhost:5055 /\n\t\tRequestHeader set Connection \"\"\n```\n\n</TabItem>\n\n<TabItem value=\"subfolder\" label=\"Subfolder\">\n\n:::warning\nThis Apache2 subfolder reverse proxy is an unsupported workaround, and only provided as an example. The filters may stop working when Seerr is updated.\n\nIf you encounter any issues with Seerr while using this workaround, we may ask you to try to reproduce the problem without the Apache2 proxy.\n:::\n\nAdd the following Location block to your existing Server configuration.\n\n```apache\n# Seerr\n# We will use \"/seerr\" as subfolder\n# You can replace it with any that you like\n\t<Location /seerr>\n\t\tProxyPreserveHost On\n\t\tProxyPass http://localhost:5055 retry=0 connectiontimeout=5 timeout=30 keepalive=on\n\t\tProxyPassReverse http://localhost:5055\n\t\tRequestHeader set Connection \"\"\n\n\t\t# Header update, to support subfolder\n\t\t# Please Replace \"FQDN\" with your domain\n\t\tHeader edit location ^/login https://FQDN/seerr/login\n\t\tHeader edit location ^/setup https://FQDN/seerr/setup\n\n\t\tAddOutputFilterByType INFLATE;SUBSTITUTE text/html application/javascript application/json\n\t\tSubstituteMaxLineLength 2000K\n\t\t# This is HTML and JS update\n\t\t# Please update \"/seerr\" if needed\n\t\tSubstitute \"s|href=\\\"|href=\\\"/seerr|inq\"\n\t\tSubstitute \"s|src=\\\"|src=\\\"/seerr|inq\"\n\t\tSubstitute \"s|/api/|/seerr/api/|inq\"\n\t\tSubstitute \"s|\\\"/_next/|\\\"/seerr/_next/|inq\"\n\t\t# This is JSON update\n\t\tSubstitute \"s|\\\"/avatarproxy/|\\\"/seerr/avatarproxy/|inq\"\n\t</Location>\n```\n\n</TabItem>\n\n</Tabs>\n\n## HAProxy (v3)\n\n:::warning\nThis is a third-party documentation maintained by the community. We can't provide support for this setup and are unable to test it.\n:::\n\n    Add the following frontend and backend configurations for your seerr instance:\n    ```haproxy\n    frontend seerr-frontend\n      bind 0.0.0.0:80\n      bind 0.0.0.0:443 ssl crt /etc/ssl/private/seerr.example.com.pem\n      mode http\n      log global\n      option httplog\n      option http-keep-alive\n      http-request set-header X-Real-IP %[src]\n      option forwardfor\n      acl seerr hdr(host) -i seerr.example.com\n      redirect scheme https code 301 if !{ ssl_fc }\n      use_backend seerr-backend if seerr\n\n    backend seerr-backend\n      mode http\n      log global\n      option httplog\n      http-response set-header Strict-Transport-Security max-age=15552000\n      option httpchk GET /api/v1/status\n      timeout connect 30000\n      timeout server 30000\n      retries 3\n      server seerr 127.0.0.1:5055 check inter 1000\n    ```\n"
  },
  {
    "path": "docs/getting-started/_category_.json",
    "content": "{\n  \"label\": \"Getting Started\",\n  \"position\": 2\n}\n"
  },
  {
    "path": "docs/getting-started/buildfromsource.mdx",
    "content": "---\ntitle: Build From Source (Advanced)\ndescription: Install Seerr by building from source\nsidebar_position: 2\n---\n# Build from Source (Advanced)\n:::warning\nThis method is not recommended for most users. It is intended for advanced users who are familiar with managing their own server infrastructure.\n\nRefer to [Configuring Databases](/extending-seerr/database-config#postgresql-options) for details on how to configure your database.\n:::\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n### Prerequisites\n    - [Node.js 22.x](https://nodejs.org/en/download/)\n    - [Pnpm 10.x](https://pnpm.io/installation)\n    - [Git](https://git-scm.com/downloads)\n\n## Unix (Linux, macOS)\n### Installation\n1. Assuming you want the working directory to be `/opt/seerr`, create the directory and navigate to it:\n```bash\nsudo mkdir -p /opt/seerr && cd /opt/seerr\n```\n2. Clone the Seerr repository and checkout the main branch:\n```bash\ngit clone https://github.com/seerr-team/seerr.git .\ngit checkout main\n```\n3. Install the dependencies:\n```bash\nCYPRESS_INSTALL_BINARY=0 pnpm install --frozen-lockfile\n```\n4. Build the project:\n```bash\npnpm build\n```\n5. Start Seerr:\n```bash\npnpm start\n```\n\n:::info\nYou can now access Seerr by visiting `http://localhost:5055` in your web browser.\n:::\n\n#### Extending the installation\n<Tabs groupId=\"unix-extensions\" queryString>\n  <TabItem value=\"linux\" label=\"Linux\">\nTo run seerr as a systemd service:\n1. create the environment file at `/etc/seerr/seerr.conf`:\n```bash\n## Seerr's default port is 5055, if you want to use both, change this.\n## specify on which port to listen\nPORT=5055\n\n## specify on which interface to listen, by default seerr listens on all interfaces\n#HOST=127.0.0.1\n\n## Uncomment if you want to force Node.js to resolve IPv4 before IPv6 (advanced users only)\n# FORCE_IPV4_FIRST=true\n```\n2. Then run the following commands:\n```bash\nwhich node\n```\nCopy the path to node, it should be something like `/usr/bin/node`.\n\n3. Create the systemd service file at `/etc/systemd/system/seerr.service`, using either `sudo systemctl edit seerr` or `sudo nano /etc/systemd/system/seerr.service`:\n```bash\n[Unit]\nDescription=Seerr Service\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nEnvironmentFile=/etc/seerr/seerr.conf\nEnvironment=NODE_ENV=production\nType=exec\nRestart=on-failure\nWorkingDirectory=/opt/seerr\nExecStart=/usr/bin/node dist/index.js\n\n[Install]\nWantedBy=multi-user.target\n```\n:::note\nIf you are using a different path to node, replace `/usr/bin/node` with the path to node.\n:::\n\n4. Enable and start the service:\n```bash\nsudo systemctl enable seerr\nsudo systemctl start seerr\n```\n  </TabItem>\n  <TabItem value=\"macos\" label=\"macOS\">\nTo run seerr as a launchd service:\n1. Find the path to node:\n```bash\nwhich node\n```\nCopy the path to node, it should be something like `/usr/local/bin/node`.\n\n2. Create a launchd plist file at `~/Library/LaunchAgents/com.seerr.plist`:\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n  <key>Label</key>\n  <string>com.seerr</string>\n  <key>ProgramArguments</key>\n  <array>\n    <string>/usr/local/bin/node</string>\n    <string>/opt/seerr/dist/index.js</string>\n  </array>\n  <key>WorkingDirectory</key>\n  <string>/opt/seerr</string>\n  <key>EnvironmentVariables</key>\n  <dict>\n    <key>NODE_ENV</key>\n    <string>production</string>\n    <key>PORT</key>\n    <string>5055</string>\n  </dict>\n  <key>RunAtLoad</key>\n  <true/>\n  <key>KeepAlive</key>\n  <true/>\n</dict>\n</plist>\n```\n:::note\nIf you are using a different path to node, replace `/usr/local/bin/node` with the path to node.\n:::\n3. Load the service:\n```bash\nsudo launchctl load ~/Library/LaunchAgents/com.seerr.plist\n```\n3. Start the service:\n```bash\nsudo launchctl start com.seerr\n```\n4. To ensure the service starts on boot, run the following command:\n```bash\nsudo lauchctl load\n```\n  </TabItem>\n  <TabItem value=\"pm2\" label=\"PM2\">\nTo run seerr as a PM2 service:\n1. Install PM2:\n```bash\nnpm install -g pm2\n```\n2. Start seerr with PM2:\n```bash\npm2 start dist/index.js --name seerr --node-args=\"--NODE_ENV=production\"\n```\n3. Save the process list:\n```bash\npm2 save\n```\n4. Ensure PM2 starts on boot:\n```bash\npm2 startup\n```\n**Managing the service**\n- To start the service:\n```powershell\npm2 start seerr\n```\n- To stop the service:\n```powershell\npm2 stop seerr\n```\n- To restart the service:\n```powershell\npm2 restart seerr\n```\n- To view the logs:\n```powershell\npm2 logs seerr\n```\n- To view the status:\n```powershell\npm2 status seerr\n```\n  </TabItem>\n</Tabs>\n\n## Windows\n### Installation\n1. Assuming you want the working directory to be `C:\\seerr`, create the directory and navigate to it:\n```powershell\nmkdir C:\\seerr\ncd C:\\seerr\n```\n2. Clone the Seerr repository and checkout the main branch:\n```powershell\ngit clone https://github.com/seerr-team/seerr.git .\ngit checkout main\n```\n3. Install the dependencies:\n```powershell\nnpm install -g win-node-env\nset CYPRESS_INSTALL_BINARY=0 && pnpm install --frozen-lockfile\n```\n4. Build the project:\n```powershell\npnpm build\n```\n5. Start Seerr:\n```powershell\npnpm start\n```\n\n:::tip\nYou can add the environment variables to a `.env` file in the Seerr directory.\n:::\n\n:::info\nYou can now access Seerr by visiting `http://localhost:5055` in your web browser.\n:::\n\n#### Extending the installation\n<Tabs groupId=\"windows-extensions\" queryString>\n  <TabItem value=\"task-scheduler\" label=\"Task Scheduler\">\nTo run seerr as a bat script:\n1. Create a file named `start-seerr.bat` in the seerr directory:\n```batch\n@echo off\nset PORT=5055\nset NODE_ENV=production\nnode dist/index.js\n```\n2. Create a task in Task Scheduler:\n- Open Task Scheduler\n- Click on \"Create Basic Task\"\n- Name the task \"Seerr\"\n- Set the trigger to \"When the computer starts\"\n- Set the action to \"Start a program\"\n- Set the program/script to the path of the `start-seerr.bat` file\n- Set the \"Start in\" to the seerr directory.\n- Click \"Finish\"\n\nNow, Seerr will start when the computer boots up in the background.\n  </TabItem>\n\n  <TabItem value=\"nssm\" label=\"NSSM\">\nTo run seerr as a service:\n1. Download the [Non-Sucking Service Manager](https://nssm.cc/download)\n2. Install NSSM:\n```powershell\nnssm install Seerr \"C:\\Program Files\\nodejs\\node.exe\" \"C:\\seerr\\dist\\index.js\"\nnssm set Seerr AppDirectory \"C:\\seerr\"\nnssm set Seerr AppEnvironmentExtra NODE_ENV=production\n```\n3. Start the service:\n```powershell\nnssm start Seerr\n```\n4. To ensure the service starts on boot, run the following command:\n```powershell\nnssm set Seerr Start SERVICE_AUTO_START\n```\n  </TabItem>\n  <TabItem value=\"pm2\" label=\"PM2\">\nTo run seerr as a PM2 service:\n1. Install PM2:\n```powershell\nnpm install -g pm2\n```\n2. Start seerr with PM2:\n```powershell\npm2 start dist/index.js --name seerr  --node-args=\"--NODE_ENV=production\"\n```\n3. Save the process list:\n```powershell\npm2 save\n```\n4. Ensure PM2 starts on boot:\n```powershell\npm2 startup\n```\n##### Managing the service\n- To start the service:\n```powershell\npm2 start seerr\n```\n- To stop the service:\n```powershell\npm2 stop seerr\n```\n- To restart the service:\n```powershell\npm2 restart seerr\n```\n- To view the logs:\n```powershell\npm2 logs seerr\n```\n- To view the status:\n```powershell\npm2 status seerr\n```\n  </TabItem>\n</Tabs>\n\n### Updating\nTo update Seerr, navigate to the Seerr directory and run the following commands:\n```bash\ngit pull\n```\nThen, follow the steps in the installation section to rebuild and restart Seerr.\n\n"
  },
  {
    "path": "docs/getting-started/docker.mdx",
    "content": "---\ntitle: Docker (Recommended)\ndescription: Install Seerr using Docker\nsidebar_position: 1\n---\n# Docker\n:::info\nThis is the recommended method for most users.\nDetails on how to install Docker can be found on the [official Docker website](https://docs.docker.com/get-docker/).\n\nRefer to [Configuring Databases](/extending-seerr/database-config#postgresql-options) for details on how to configure your database.\n:::\n\n:::info\nAn alternative Docker image is available on Docker Hub for this project. You can find it at [Docker Hub Repository Link](https://hub.docker.com/r/seerr/seerr)\n\nOur Docker images are available with the following tags:\n\n- `latest`: Always points to the most recent stable release.\n- Version tags (e.g., `v3.0.0`): For specific stable versions.\n- `develop`: Rolling release/nightly builds for using the latest changes (use with caution).\n:::\n\n:::info\nAll official Seerr images are cryptographically signed and include a verified [Software Bill of Materials (SBOM)](https://cyclonedx.org/).\n\nTo confirm that the container image you are using is authentic and unmodified, please refer to the [Verifying Signed Artifacts](/using-seerr/advanced/verifying-signed-artifacts#verifying-signed-images) guide.\n:::\n\n## Unix (Linux, macOS)\n:::warning\nBe sure to replace `/path/to/appdata/config` in the below examples with a valid host directory path. If this volume mount is not configured correctly, your Seerr settings/data will not be persisted when the container is recreated (e.g., when updating the image or rebooting your machine).\n\n    The `TZ` environment variable value should also be set to the [TZ database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) of your time zone!\n\n:::\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n<Tabs groupId=\"docker-methods\" queryString>\n  <TabItem value=\"docker-cli\" label=\"Docker CLI\">\nFor details on the Docker CLI, please [review the official `docker run` documentation](https://docs.docker.com/engine/reference/run/).\n\n#### Installation:\n\n```bash\n# Create the appdata folder\nmkdir /path/to/appdata/config\n# Chown the folder as the container runs as the `node` user (UID 1000).\nchown -R 1000:1000 /path/to/appdata/config\n```\n\n```bash\ndocker run -d \\\n  --name seerr \\\n  --init \\\n  -e LOG_LEVEL=debug \\\n  -e TZ=Asia/Tashkent \\\n  -e PORT=5055 \\\n  -p 5055:5055 \\\n  -v /path/to/appdata/config:/app/config \\\n  --restart unless-stopped \\\n  --health-cmd \"wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status || exit 1\" \\\n  --health-start-period 20s \\\n  --health-timeout 3s \\\n  --health-interval 15s \\\n  --health-retries 3 \\\n  ghcr.io/seerr-team/seerr:latest\n```\n\nThe argument `-e PORT=5055` is optional.\n\nTo run the container as a specific user/group, you may optionally add `--user=[ user | user:group | uid | uid:gid | user:gid | uid:group ]` to the above command.\n\n#### Updating:\n\nStop and remove the existing container:\n```bash\ndocker stop seerr && docker rm seerr\n```\nPull the latest image:\n```bash\ndocker pull ghcr.io/seerr-team/seerr:latest\n```\nFinally, run the container with the same parameters originally used to create the container:\n```bash\ndocker run -d ...\n```\n\n:::tip\nYou may alternatively use a third-party updating mechanism, such as [Watchtower](https://github.com/containrrr/watchtower) or [Ouroboros](https://github.com/pyouroboros/ouroboros), to keep Seerr up-to-date automatically.\n\nYou could also use [diun](https://github.com/crazy-max/diun) to receive notifications when a new image is available.\n:::\n  </TabItem>\n\n  <TabItem value=\"docker-compose\" label=\"Docker Compose\">\nFor details on how to use Docker Compose, please [review the official Compose documentation](https://docs.docker.com/compose/reference/).\n\n#### Installation:\nDefine the `seerr` service in your `compose.yaml` as follows:\n```yaml\n---\nservices:\n  seerr:\n    image: ghcr.io/seerr-team/seerr:latest\n    init: true\n    container_name: seerr\n    environment:\n      - LOG_LEVEL=debug\n      - TZ=Asia/Tashkent\n      - PORT=5055 #optional\n    ports:\n      - 5055:5055\n    volumes:\n      - /path/to/appdata/config:/app/config\n    healthcheck:\n      test: wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status || exit 1\n      start_period: 20s\n      timeout: 3s\n      interval: 15s\n      retries: 3\n    restart: unless-stopped\n```\n\n```bash\n# Create the appdata folder\nmkdir /path/to/appdata/config\n# Chown the folder as the container runs as the `node` user (UID 1000).\nchown -R 1000:1000 /path/to/appdata/config\n```\n\nThen, start all services defined in the Compose file:\n```bash\ndocker compose up -d\n```\n\n#### Updating:\nPull the latest image:\n```bash\ndocker compose pull seerr\n```\nThen, restart all services defined in the Compose file:\n```bash\ndocker compose up -d\n```\n  </TabItem>\n</Tabs>\n\n## Windows\n\nPlease refer to the [Docker Desktop for Windows user manual](https://docs.docker.com/docker-for-windows/) for details on how to install Docker on Windows. There is no need to install a Linux distro if using named volumes like in the example below.\n:::warning\n**WSL2 will need to be installed to prevent DB corruption!** Please see the [Docker Desktop WSL 2 backend documentation](https://docs.docker.com/docker-for-windows/wsl/) for instructions on how to enable WSL2. The commands below will only work with WSL2 installed!\n:::\n\nFirst, create a volume to store the configuration data for Seerr using using either the Docker CLI:\n```bash\ndocker volume create seerr-data\n```\n\nor the Docker Desktop app:\n1. Open the Docker Desktop app\n2. Head to the Volumes tab\n3. Click on the \"New Volume\" button near the top right\n4. Enter a name for the volume (example: `seerr-data`) and hit \"Create\"\n\nThen, create and start the Seerr container:\n<Tabs groupId=\"docker-methods\" queryString>\n  <TabItem value=\"docker-cli\" label=\"Docker CLI (PowerShell)\">\n```powershell\ndocker run -d `\n  --name seerr `\n  --init `\n  -e LOG_LEVEL=debug `\n  -e TZ=Asia/Tashkent `\n  -e PORT=5055 `\n  -p 5055:5055 `\n  -v seerr-data:/app/config `\n  --restart unless-stopped `\n  --health-cmd \"wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status || exit 1\" `\n  --health-start-period 20s `\n  --health-timeout 3s `\n  --health-interval 15s `\n  --health-retries 3 `\n  ghcr.io/seerr-team/seerr:latest\n```\n\nThe argument `-e PORT=5055` is optional.\n\n#### Updating:\n\nStop and remove the existing container:\n```powershell\ndocker stop seerr; docker rm seerr\n```\nPull the latest image:\n```powershell\ndocker pull ghcr.io/seerr-team/seerr:latest\n```\nFinally, run the container with the same parameters originally used to create the container:\n```powershell\ndocker run -d ...\n```\n\n  </TabItem>\n\n  <TabItem value=\"docker-cli-cmd\" label=\"Docker CLI (CMD)\">\n```batch\ndocker run -d ^\n  --name seerr ^\n  --init ^\n  -e LOG_LEVEL=debug ^\n  -e TZ=Asia/Tashkent ^\n  -e PORT=5055 ^\n  -p 5055:5055 ^\n  -v seerr-data:/app/config ^\n  --restart unless-stopped ^\n  --health-cmd \"wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status || exit 1\" ^\n  --health-start-period 20s ^\n  --health-timeout 3s ^\n  --health-interval 15s ^\n  --health-retries 3 ^\n  ghcr.io/seerr-team/seerr:latest\n```\n\nThe argument `-e PORT=5055` is optional.\n\n#### Updating:\n\nStop and remove the existing container:\n```batch\ndocker stop seerr && docker rm seerr\n```\nPull the latest image:\n```batch\ndocker pull ghcr.io/seerr-team/seerr:latest\n```\nFinally, run the container with the same parameters originally used to create the container:\n```batch\ndocker run -d ...\n```\n\n  </TabItem>\n\n  <TabItem value=\"docker-compose\" label=\"Docker Compose\">\n```yaml\n---\nservices:\n  seerr:\n    image: ghcr.io/seerr-team/seerr:latest\n    init: true\n    container_name: seerr\n    environment:\n      - LOG_LEVEL=debug\n      - TZ=Asia/Tashkent\n    ports:\n      - 5055:5055\n    volumes:\n      - seerr-data:/app/config\n    healthcheck:\n      test: wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status || exit 1\n      start_period: 20s\n      timeout: 3s\n      interval: 15s\n      retries: 3\n    restart: unless-stopped\n\nvolumes:\n  seerr-data:\n    external: true\n```\n\n#### Updating:\nPull the latest image:\n```bash\ndocker compose pull seerr\n```\nThen, restart all services defined in the Compose file:\n```bash\ndocker compose up -d\n```\n  </TabItem>\n</Tabs>\n\nTo access the files inside the volume created above, navigate to `\\\\wsl$\\docker-desktop-data\\version-pack-data\\community\\docker\\volumes\\seerr-data\\_data` using File Explorer.\n\n:::info\nDocker on Windows works differently than it does on Linux; it runs Docker inside of a stripped-down Linux VM. Volume mounts are exposed to Docker inside this VM via SMB mounts. While this is fine for media, it is unacceptable for the `/app/config` directory because SMB does not support file locking. This will eventually corrupt your database, which can lead to slow behavior and crashes.\n\n**If you must run Docker on Windows, you should put the `/app/config` directory mount inside the VM and not on the Windows host.** (This also applies to other containers with SQLite databases.)\n\nNamed volumes, like in the example commands above, are automatically mounted inside the VM. Therefore the warning on the setup about the `/app/config` folder being incorrectly mounted page should be ignored.\n:::\n\n\n"
  },
  {
    "path": "docs/getting-started/index.mdx",
    "content": "---\ntitle: Getting Started\n---\nimport DocCardList from '@theme/DocCardList';\n\n:::info\nAfter running Seerr for the first time, configure it by visiting the web UI at `http://[address]:5055` and completing the setup steps.\n:::\n\n<DocCardList />\n"
  },
  {
    "path": "docs/getting-started/kubernetes.mdx",
    "content": "---\ntitle: Kubernetes (Advanced)\ndescription: Install Seerr in Kubernetes\nsidebar_position: 3\n---\n# Kubernetes\n:::warning\nThis method is not recommended for most users. It is intended for advanced users who are using Kubernetes.\n:::\n\n:::info\nAll official Seerr charts are cryptographically signed and include a verified [Software Bill of Materials (SBOM)](https://cyclonedx.org/).\n\nTo confirm that the chart you are using is authentic and unmodified, please refer to the [Verifying Signed Artifacts](/using-seerr/advanced/verifying-signed-artifacts#verifying-signed-helm-charts) guide.\n:::\n\n## Installation\n```console\nhelm install seerr oci://ghcr.io/seerr-team/seerr/seerr-chart\n```\nHelm values can be found in the Seerr repository under [charts/seerr-chart/README.md](https://github.com/seerr-team/seerr/tree/develop/charts/seerr-chart).\n\nVerify the signature with [cosign](https://docs.sigstore.dev/cosign/system_config/installation/) (replace [tag], with the TAG you want to verify) :\n```console\ncosign verify ghcr.io/seerr-team/seerr/seerr-chart:[tag] --certificate-identity=https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main --certificate-oidc-issuer=https://token.actions.githubusercontent.com\n```\n"
  },
  {
    "path": "docs/getting-started/third-parties/aur.mdx",
    "content": "---\ntitle: AUR (Advanced)\ndescription: Install Seerr using the Arch User Repository\nsidebar_position: 2\n---\n\n# AUR\n:::warning\nThird-party installation methods are maintained by the community. The Seerr team is not responsible for these packages.\n:::\n\n:::warning\nThis method is not recommended for most users. It is intended for advanced users who are using Arch Linux or an Arch-based distribution.\n:::\n\n## Installation\n\nTo install Seerr from the AUR, you can use an AUR helper like `yay` or `paru`:\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n<Tabs groupId=\"aur-methods\" queryString>\n  <TabItem value=\"yay\" label=\"yay\">\n    ```bash\n    yay -S seerr\n    ```\n  </TabItem>\n  <TabItem value=\"paru\" label=\"paru\">\n    ```bash\n    paru -S seerr\n    ```\n  </TabItem>\n</Tabs>\n\n:::info\nAfter installing Seerr, configure it by visiting the web UI at `http://[address]:5055` and completing the setup steps.\n:::\n\n:::tip\nYou can find the environment file at `/etc/conf.d/seerr` and the service file at `/etc/systemd/system/seerr.service`.\n:::\n"
  },
  {
    "path": "docs/getting-started/third-parties/index.mdx",
    "content": "---\ntitle: Third-party Installation Methods\n---\nimport DocCardList from '@theme/DocCardList';\n\n:::warning\nThird-party installation methods are maintained by the community. The Seerr team is not responsible for these packages.\n:::\n\n:::info\nWant to add a third-party installation method? Contributions are welcome! Feel free to open a pull request.\n:::\n\n\n<DocCardList />\n"
  },
  {
    "path": "docs/getting-started/third-parties/nixpkg.mdx",
    "content": "---\ntitle: Nix Package Manager (Advanced)\ndescription: Install Seerr using Nixpkgs\nsidebar_position: 1\n---\n\nimport { SeerrVersion, NixpkgVersion } from '@site/src/components/SeerrVersion';\nimport Admonition from '@theme/Admonition';\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n# Nix Package Manager\n:::danger\nThis method has not yet been updated for Seerr and is currently a work in progress.\nYou can follow the ongoing work on these pull requests:\n  - https://github.com/NixOS/nixpkgs/pull/450096\n  - https://github.com/NixOS/nixpkgs/pull/450093\n:::\n\n<!--\n:::warning\nThird-party installation methods are maintained by the community. The Seerr team is not responsible for these packages.\n:::\n\n:::warning\nThis method is not recommended for most users. It is intended for advanced users who are using NixOS distribution.\n:::\n\nRefer to [NixOS documentation](https://search.nixos.org/options?channel=25.05&query=seerr)\n-->\n"
  },
  {
    "path": "docs/getting-started/third-parties/synology.mdx",
    "content": "---\ntitle: Synology (Advanced)\ndescription: Install Seerr on Synology NAS using SynoCommunity\nsidebar_position: 5\n---\n\n# Synology\n\n:::warning\nThird-party installation methods are maintained by the community. The Seerr team is not responsible for these packages.\n:::\n\n:::warning\nThis method is not recommended for most users. It is intended for advanced users who are using Synology NAS.\n:::\n\n## Prerequisites\n\n- Synology NAS running **DSM 7.2** or later\n- 64-bit architecture (x86_64 or ARMv8)\n- [SynoCommunity package source](https://synocommunity.com/) added to Package Center\n\n## Adding the SynoCommunity Package Source\n\nIf you haven't already added SynoCommunity to your Package Center:\n\n1. Open **Package Center** in DSM\n2. Click **Settings** in the top-right corner\n3. Go to the **Package Sources** tab\n4. Click **Add**\n5. Enter the following:\n   - **Name**: `SynoCommunity`\n   - **Location**: `https://packages.synocommunity.com`\n6. Click **OK**\n\n## Installation\n\n1. In **Package Center**, search for **Seerr**\n2. Click **Install**\n3. Follow the installation wizard prompts\n4. Package Center will automatically install any required dependencies (Node.js v22)\n\n### Access Seerr\n\nOnce installed, access Seerr at:\n\n```\nhttp://<your-synology-ip>:5055\n```\n\nYou can also click the **Open** button in Package Center or find Seerr in the DSM main menu.\n\n## Configuration\n\nSeerr's configuration files are stored at:\n\n```\n/var/packages/seerr/var/config\n```\n\n:::info\nThe Seerr package runs as a dedicated service user managed by DSM. No manual permission configuration is required.\n:::\n\n## Managing the Service\n\nYou can start, stop, and restart Seerr from **Package Center** → Find Seerr → Use the action buttons.\n\n## Updating\n\nWhen a new version is available:\n\n1. Open **Package Center**\n2. Go to **Installed** packages\n3. Find **Seerr** and click **Update** if available\n\n:::tip\nEnable automatic updates in Package Center settings to keep Seerr up to date.\n:::\n\n## Troubleshooting\n\n### Viewing Logs\n\nSeerr logs are located at `/var/packages/seerr/var/config/logs` and can be accessed using:\n\n- **File Browser** package (recommended for most users)\n- SSH (advanced users)\n\n### Port Conflicts\n\nSeerr uses port 5055. If this port is already in use:\n\n- **Docker containers**: Remap the conflicting container to a different port\n- **Other packages**: The conflicting package will need to be uninstalled as Seerr's port cannot be changed\n\nSynoCommunity ensures there are no port conflicts with other SynoCommunity packages or official Synology packages.\n\n### Package Won't Start\n\nEnsure Node.js v22 is installed and running by checking its status in **Package Center**.\n\n## Uninstallation\n\n1. Open **Package Center**\n2. Find **Seerr** in your installed packages\n3. Click **Uninstall**\n\n:::caution\nUninstalling will remove the application but preserve your configuration data by default. Select \"Remove data\" during uninstallation if you want a complete removal.\n:::\n"
  },
  {
    "path": "docs/getting-started/third-parties/truenas.mdx",
    "content": "---\ntitle: TrueNAS (Advanced)\ndescription: Install Seerr using TrueNAS\nsidebar_position: 4\n---\n# TrueNAS\n:::warning\nThird-party installation methods are maintained by the community. The Seerr team is not responsible for these packages.\n:::\n\n:::warning\nThis method is not recommended for most users. It is intended for advanced users who are using TrueNAS distribution.\n:::\n\n## Installation\n\nGo to the 'Apps' menu, click the 'Discover Apps' button in the top right, search for 'Seerr' in the search bar, and install the app.\n"
  },
  {
    "path": "docs/getting-started/third-parties/unraid.mdx",
    "content": "---\ntitle: Unraid (Advanced)\ndescription: Install Seerr using Unraid\nsidebar_position: 3\n---\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n# Unraid\n\n:::warning\nThird-party installation methods are maintained by the community. The Seerr team is not responsible for these packages.\n:::\n\n:::warning\nThis method is not recommended for most users. It is intended for advanced users who are using Unraid.\n:::\n\n## Template installation\n\nSeveral templates from Unraid Community are available right now\n- [Unraid Community Apps](https://unraid.net/community/apps#community-apps-iframe)\n\nIn case you still want to do it manually, please follow the instructions below.\n\n## Manual Installation\n\nBefore proceeding, choose which installation method best suits your server:\n\n**Seerr Default** (`UID 1000:1000`) — Runs with the container's native `node` user. Matches the official image, but may break SMB share access, trigger \"Fix Common Problems\" warnings, and cause issues with backup plugins (such as CA Appdata Backup) and network integrations (such as Tailscale).\n\n**Unraid Default** (`UID 99:100`) — Runs with Unraid's native `nobody:users` ownership. Follows Unraid best practices, but overrides Seerr's built-in rootless user and may cause compatibility issues with future Seerr updates.\n\n<Tabs groupId=\"unraid-permissions\" queryString>\n  <TabItem value=\"seerr-default\" label=\"Seerr Default\">\n\n  ### 1. Create the config directory\n\n  Open the Unraid terminal and run:\n\n  ```bash\n  mkdir -p /mnt/user/appdata/seerr\n  ```\n\n  ### 2. Set folder permissions\n\n  ```bash\n  chown -R 1000:1000 /mnt/user/appdata/seerr\n  ```\n\n  ### 3. Add the Docker container\n\n  :::warning\n  The **Extra Parameters** field is critical. You **must** add `--init --restart=unless-stopped` (see table below). Without `--init`, the container will not handle signals properly or shut down cleanly. Without `--restart=unless-stopped`, the container will not automatically restart after a reboot.\n\n  To see the **Extra Parameters** field, click **Basic View** in the top-right corner of the template page to switch to the advanced editor.\n  :::\n\n  Navigate to the **Docker** tab in Unraid and click **Add Container**. Fill in the following:\n\n  | Field | Value |\n  |---|---|\n  | **Name** | `seerr` |\n  | **Repository** | `ghcr.io/seerr-team/seerr:latest` |\n  | **Icon URL** | `https://raw.githubusercontent.com/seerr-team/seerr/develop/public/android-chrome-512x512.png` |\n  | **WebUI** | `http://[IP]:[PORT:5055]` |\n  | **Extra Parameters** | `--init --restart=unless-stopped` |\n  | **Network Type** | `bridge` |\n  | **Privileged** | `Off` |\n\n  Then click **Add another Path, Port, Variable** to add:\n\n  **Port:**\n  | Field | Value |\n  |---|---|\n  | Container Port | `5055` |\n  | Host Port | `5055` |\n  | Connection Type | `TCP` |\n\n  **Path:**\n  | Field | Value |\n  |---|---|\n  | Container Path | `/app/config` |\n  | Host Path | `/mnt/user/appdata/seerr` |\n\n  **Variable:**\n  | Field | Value |\n  |---|---|\n  | Key | `TZ` |\n  | Value | Your [TZ database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (e.g., `America/New_York`) |\n\n  **Variable (optional):**\n  | Field | Value |\n  |---|---|\n  | Key | `LOG_LEVEL` |\n  | Value | `info` |\n\n  Click **Apply** to create and start the container.\n\n  ### 4. Access Seerr\n\n  Open the WebUI at `http://<your-unraid-ip>:5055` and follow the setup wizard.\n\n  </TabItem>\n  <TabItem value=\"unraid-default\" label=\"Unraid Default\">\n\n  ### 1. Create the config directory\n\n  Open the Unraid terminal and run:\n\n  ```bash\n  mkdir -p /mnt/user/appdata/seerr\n  ```\n\n  ### 2. Set folder permissions\n\n  ```bash\n  chown -R 99:100 /mnt/user/appdata/seerr\n  ```\n\n  ### 3. Add the Docker container\n\n  :::warning\n  The **Extra Parameters** field is critical. You **must** add `--init --restart=unless-stopped --user 99:100` (see table below). Without `--init`, the container will not handle signals properly or shut down cleanly. Without `--restart=unless-stopped`, the container will not automatically restart after a reboot. The `--user 99:100` parameter runs the container process with Unraid's default UID/GID and avoids permission errors accessing your shares without changing host folder ownership.\n\n  To see the **Extra Parameters** field, click **Basic View** in the top-right corner of the template page to switch to the advanced editor.\n  :::\n\n  Navigate to the **Docker** tab in Unraid and click **Add Container**. Fill in the following:\n\n  | Field | Value |\n  |---|---|\n  | **Name** | `seerr` |\n  | **Repository** | `ghcr.io/seerr-team/seerr:latest` |\n  | **Icon URL** | `https://raw.githubusercontent.com/seerr-team/seerr/develop/public/android-chrome-512x512.png` |\n  | **WebUI** | `http://[IP]:[PORT:5055]` |\n  | **Extra Parameters** | `--init --restart=unless-stopped --user 99:100` |\n  | **Network Type** | `bridge` |\n  | **Privileged** | `Off` |\n\n  Then click **Add another Path, Port, Variable** to add:\n\n  **Port:**\n  | Field | Value |\n  |---|---|\n  | Container Port | `5055` |\n  | Host Port | `5055` |\n  | Connection Type | `TCP` |\n\n  **Path:**\n  | Field | Value |\n  |---|---|\n  | Container Path | `/app/config` |\n  | Host Path | `/mnt/user/appdata/seerr` |\n\n  **Variable:**\n  | Field | Value |\n  |---|---|\n  | Key | `TZ` |\n  | Value | Your [TZ database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (e.g., `America/New_York`) |\n\n  **Variable (optional):**\n  | Field | Value |\n  |---|---|\n  | Key | `LOG_LEVEL` |\n  | Value | `info` |\n\n  Click **Apply** to create and start the container.\n\n  ### 4. Access Seerr\n\n  Open the WebUI at `http://<your-unraid-ip>:5055` and follow the setup wizard.\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "docs/migration-guide.mdx",
    "content": "---\ntitle: Migration guide\n---\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n:::important\nRead our [release announcement](/blog/seerr-release) to learn what Seerr means for Jellyseerr and Overseerr users.\n:::\n\nWhether you come from Overseerr or Jellyseerr, you don't need to perform any manual migration steps, your instance will automatically be migrated to Seerr.\nThis migration will run automatically the first time you start your instance using the Seerr codebase (Docker image or source build or Kubernetes, etc.).\nAn additional migration will happen for Overseerr users, to migrate their configuration to the new codebase.\n\n:::danger\nBefore doing anything you should backup your existing instance so that you can rollback in case something goes wrong.\nSee [Backups](/using-seerr/backups) for details on how to properly backup your instance.\n:::\n\n:::warning\nInstallation methods are now divided into two categories: official and third-party methods.\nThe Seerr team is only responsible for official installation methods, while third-party methods are maintained by the community.\nSome methods are currently not maintained, but this does not mean they are permanently discontinued. The community may restore and support them if they choose to do so.\n\n- **Snap package:** Not maintained\n:::\n\n## Docker\nRefer to [Seerr Docker Documentation](/getting-started/docker), all of our examples have been updated to reflect the below change.\n\n:::info\nSeerr provides a secure, fully featured image with everything you need included.\nWe sincerely appreciate the past contributions from third-party maintainers, which helped enhance this image and its capabilities.\nTo maintain consistency and security, we encourage everyone to use the features available in the official Seerr image.\nIf you feel something is missing, please submit a feature request—your feedback is always welcome!\n\nOur Docker images are available with the following tags:\n\n- `latest`: Always points to the most recent stable release.\n- Version tags (e.g., `v3.0.0`): For specific stable versions.\n- `develop`: Rolling release/nightly builds for using the latest changes (use with caution).\n:::\n\nChanges :\n- Renamed all references from `overseerr` or `jellyseerr` to `seerr`.\n- The container image reference has been updated.\n- The container can now be run as a non-root user (`node` user); remove the `user` directive if you have configured it.\n- The container no longer provides an init process, so you must configure it by adding `init: true` for Docker Compose or `--init` for the Docker CLI.\n\n#### Config folder permissions\n:::info\nSince the container now runs as the `node` user (UID 1000), you must ensure your config folder has the correct permissions. The `node` user must have read and write access to the `/app/config` directory.\n\nIf you're migrating from a previous installation, you may need to update the ownership of your config folder:\n\n```bash\ndocker run --rm -v /path/to/appdata/config:/data alpine chown -R 1000:1000 /data\n```\n\nThis ensures the `node` user (UID 1000) owns the config directory and can read and write to it.\n:::\n\n### Unix\n\nSummary of changes :\n<Tabs groupId=\"docker-methods\" queryString>\n  <TabItem value=\"docker-compose\" label=\"Docker compose\">\n  ```yaml {3-6}\n  ---\n  services:\n    seerr:\n      image: ghcr.io/seerr-team/seerr:latest\n      init: true\n      container_name: seerr\n      environment:\n        - LOG_LEVEL=debug\n        - TZ=Asia/Tashkent\n        - PORT=5055 #optional\n      ports:\n        - 5055:5055\n      volumes:\n        - /path/to/appdata/config:/app/config\n      healthcheck:\n        test: wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status || exit 1\n        start_period: 20s\n        timeout: 3s\n        interval: 15s\n        retries: 3\n      restart: unless-stopped\n  ```\n  </TabItem>\n  <TabItem value=\"docker-cli\" label=\"Docker CLI\">\n  ```bash {2-3,10}\n  docker run -d \\\n    --name seerr \\\n    --init \\\n    -e LOG_LEVEL=debug \\\n    -e TZ=Asia/Tashkent \\\n    -e PORT=5055 \\\n    -p 5055:5055 \\\n    -v /path/to/appdata/config:/app/config \\\n    --restart unless-stopped \\\n    ghcr.io/seerr-team/seerr:latest\n  ```\n  </TabItem>\n</Tabs>\n\n### Windows\n\nSummary of changes :\n<Tabs groupId=\"docker-methods\" queryString>\n  <TabItem value=\"docker-compose\" label=\"Docker compose\">\n  ```yaml {3-6,13,23}\n  ---\n  services:\n    seerr:\n      image: ghcr.io/seerr-team/seerr:latest\n      init: true\n      container_name: seerr\n      environment:\n        - LOG_LEVEL=debug\n        - TZ=Asia/Tashkent\n      ports:\n        - 5055:5055\n      volumes:\n        - seerr-data:/app/config\n      healthcheck:\n        test: wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status || exit 1\n        start_period: 20s\n        timeout: 3s\n        interval: 15s\n        retries: 3\n      restart: unless-stopped\n\n  volumes:\n    seerr-data:\n      external: true\n  ```\n  </TabItem>\n  <TabItem value=\"docker-cli\" label=\"Docker CLI (PowerShell)\">\n  ```powershell {2-3,8,10}\n  docker run -d `\n    --name seerr `\n    --init `\n    -e LOG_LEVEL=debug `\n    -e TZ=Asia/Tashkent `\n    -e PORT=5055 `\n    -p 5055:5055 `\n    -v seerr-data:/app/config `\n    --restart unless-stopped `\n    ghcr.io/seerr-team/seerr:latest\n  ```\n  </TabItem>\n\n  <TabItem value=\"docker-cli-cmd\" label=\"Docker CLI (CMD)\">\n  ```batch {2-3,8,10}\n  docker run -d ^\n    --name seerr ^\n    --init ^\n    -e LOG_LEVEL=debug ^\n    -e TZ=Asia/Tashkent ^\n    -e PORT=5055 ^\n    -p 5055:5055 ^\n    -v seerr-data:/app/config ^\n    --restart unless-stopped ^\n    ghcr.io/seerr-team/seerr:latest\n  ```\n  </TabItem>\n</Tabs>\n\n\n## Build From Source\nRefer to [Seerr Build From Source Documentation](/getting-started/buildfromsource), all of our examples have been updated to reflect the below change.\n\nInstall from scratch by following the documentation, restore your data as described in [Backups](/using-seerr/backups), and then start Seerr. No additional steps are required.\n\n## Kubernetes\nRefer to [Seerr Kubernetes Documentation](/getting-started/kubernetes), all of our examples have been updated to reflect the below change.\n\nChanges :\n- All references to `jellyseerr` have been renamed to `seerr` in the manifests.\n- The container image reference has been updated.\n- The default `securityContext` and `podSecurityContext` have been updated to support running the container without root permissions.\n\nSummary of changes :\n<Tabs groupId=\"kubernetes-values\" queryString>\n  <TabItem value=\"old\" label=\"Old values\">\n  ```yaml\n  image:\n    repository: fallenbagel/jellyseerr\n  podSecurityContext: {}\n  securityContext: {}\n  ```\n  </TabItem>\n  <TabItem value=\"new\" label=\"New values\">\n  ```yaml\n  image:\n    repository: seerr-team/seerr\n  podSecurityContext:\n    fsGroup: 1000\n    fsGroupChangePolicy: OnRootMismatch\n  securityContext:\n    allowPrivilegeEscalation: false\n    capabilities:\n      drop:\n        - ALL\n    readOnlyRootFilesystem: false\n    runAsNonRoot: true\n    privileged: false\n    runAsUser: 1000\n    runAsGroup: 1000\n    seccompProfile:\n      type: RuntimeDefault\n  ```\n  </TabItem>\n</Tabs>\n\n## Third-party installation methods\n\n:::warning\nThird-party installation methods are maintained by the community. The Seerr team is not responsible for these packages.\n:::\n\n### Nix\n\nWaiting for https://github.com/NixOS/nixpkgs/pull/450096 and https://github.com/NixOS/nixpkgs/pull/450093\n\n### AUR\n\nSee https://aur.archlinux.org/packages/seerr\n\n### TrueNAS\n\nRefer to [Seerr TrueNAS Documentation](/getting-started/third-parties/truenas), all of our examples have been updated to reflect the below change.\n\n<Tabs groupId=\"truenas-migration\" queryString>\n  <TabItem value=\"hostpath\" label=\"Host Path\">\n    **This guide describes how to migrate from Host Path storage (not ixVolume).**\n    1. Stop Jellyseerr/Overseerr\n    2. Install Seerr and use the same Host Path storage that was used by Jellyseerr/Overseerr\n    3. Start Seerr app\n    4. Delete Jellyseerr/Overseerr app\n  </TabItem>\n  <TabItem value=\"ixvolume\" label=\"ixVolume\">\n    **This guide describes how to migrate from ixVolume storage (not Host Path).**\n    1. Stop Jellyseerr/Overseerr\n    2. Create a dataset for Seerr\n          If your apps normally store data under something like:\n          ```\n          /mnt/storage/<app-name>\n          ```\n          then create a dataset named:\n          ```\n          storage/seerr\n          ```\n          resulting in:\n          ```\n          /mnt/storage/seerr\n          ```\n    3. Copy ixVolume Data\n          Open System Settings → Shell, or SSH into your TrueNAS server as root and run :\n          ```bash\n          rsync -av /mnt/.ix-apps/app_mounts/jellyseerr/ /mnt/storage/seerr/\n          ```\n    4. Install Seerr and use the same Host Path storage that was created before (`/mnt/storage/seerr/config` in our example)\n    5. Start Seerr app\n    6. Delete Jellyseerr/Overseerr app\n  </TabItem>\n</Tabs>\n\n### Unraid\n\nRefer to [Seerr Unraid Documentation](/getting-started/third-parties/unraid), all of our examples have been updated to reflect the below change.\n\nSeerr will automatically migrate your existing Overseerr or Jellyseerr data on first startup. No manual database migration is needed.\n\n**1. Stop the existing container**\nIn the Unraid **Docker** tab, stop your Overseerr (or Jellyseerr) container.\n**⚠️ Do not remove the container or delete the appdata folder yet ⚠️**\n\n**2. Copy existing data to Seerr appdata**\nOpen the Unraid terminal and copy your existing appdata folder into the new Seerr appdata directory:\n```bash\ncp -a /mnt/user/appdata/overseerr /mnt/user/appdata/seerr\n```\n\n*(For Jellyseerr users, replace `overseerr` with `jellyseerr` in the paths).*\n\n**3. Set permissions and install Seerr**\nFollow the [Unraid Installation Guide](/getting-started/third-parties/unraid#2-set-folder-permissions), **starting from step 2** — this covers setting the correct folder permissions and adding the Docker container. The guide offers two permission methods (**Seerr Default** and **Unraid Default**), each with trade-offs — read the descriptions before choosing.\n\n**4. Start the new Seerr app**\nStart the newly created Seerr container. Check the container logs to confirm the automatic migration completed successfully.\n\n**5. Remove the old app**\nOnce you have confirmed Seerr is working properly and your data has successfully migrated, you can safely **Remove** the old Overseerr (or Jellyseerr) container from Unraid.\n"
  },
  {
    "path": "docs/troubleshooting.mdx",
    "content": "---\ntitle: Troubleshooting\n---\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n## [TMDB] failed to retrieve/fetch XXX\n\n### Option 1: Change your DNS servers\n\nThis error often comes from your Internet Service Provider (ISP) blocking TMDB API. The ISP may block the DNS resolution to the TMDB API hostname.\n\nTo fix this, you can change your DNS servers to a public DNS service like Google's DNS or Cloudflare's DNS:\n\n<Tabs groupId=\"methods\" queryString>\n  <TabItem value=\"docker-cli\" label=\"Docker CLI\">\n\nAdd the following to your `docker run` command to use Google's DNS:\n```bash\n--dns=8.8.8.8\n```\nor for Cloudflare's DNS:\n```bash\n--dns=1.1.1.1\n```\nor for Quad9 DNS:\n```bash\n--dns=9.9.9.9\n```\n\nYou can try them all and see which one works for your network.\n\n  </TabItem>\n\n  <TabItem value=\"docker-compose\" label=\"Docker Compose\">\n\nAdd the following to your `compose.yaml` to use Google's DNS:\n```yaml\n---\nservices:\n  seerr:\n    dns:\n      - 8.8.8.8\n```\nor for Cloudflare's DNS:\n```yaml\n---\nservices:\n  seerr:\n    dns:\n      - 1.1.1.1\n```\nor for Quad9's DNS:\n```yaml\n---\nservices:\n  seerr:\n    dns:\n      - 9.9.9.9\n```\n\nYou can try them all and see which one works for your network.\n\n  </TabItem>\n\n  <TabItem value=\"windows\" label=\"Windows\">\n\n1. Open the Control Panel.\n2. Click on Network and Internet.\n3. Click on Network and Sharing Center.\n4. Click on Change adapter settings.\n5. Right-click the network interface connected to the internet and select Properties.\n6. Select Internet Protocol Version 4 (TCP/IPv4) and click Properties.\n7. Select Use the following DNS server addresses and enter `8.8.8.8` for Google's DNS or `1.1.1.1` for Cloudflare's DNS or `9.9.9.9` for Quad9's DNS.\n\n  </TabItem>\n\n  <TabItem value=\"linux\" label=\"Linux\">\n\n1. Open a terminal.\n2. Edit the `/etc/resolv.conf` file with your favorite text editor.\n3. Add the following line to use Google's DNS:\n    ```bash\n    nameserver 8.8.8.8\n    ```\n    or for Cloudflare's DNS:\n\n    ```bash\n    nameserver 1.1.1.1\n    ```\n    or for Quad9's DNS:\n    ```bash\n    nameserver 9.9.9.9\n    ```\n\n  </TabItem>\n</Tabs>\n\n### Option 2: Use Seerr through a proxy\n\nIf you can't change your DNS servers or force IPV4 resolution, you can use Seerr through a proxy.\n\nIn some places (like China), the ISP blocks not only the DNS resolution but also the connection to the TMDB API.\n\nYou can configure Seerr to use a proxy with the [HTTP(S) Proxy](/using-seerr/settings/general#enable-proxy-support) setting.\n\n### Option 3: Force IPV4 resolution first\n\nSometimes there are configuration issues with IPV6 that prevent the hostname resolution from working correctly.\n\nYou can try to force the resolution to use IPV4 first by going to `Settings > Networking > Advanced Networking` and enabling `Force IPv4 Resolution First` setting and restarting Seerr.\n\n### Option 4: Check that your server can reach TMDB API\n\nMake sure that your server can reach the TMDB API by running the following command:\n\n<Tabs groupId=\"methods\" queryString>\n  <TabItem value=\"docker-cli\" label=\"Docker CLI\">\n\n```bash\ndocker exec -it seerr sh -c \"apk update && apk add curl && curl -L https://api.themoviedb.org\"\n```\n\n  </TabItem>\n\n  <TabItem value=\"docker-compose\" label=\"Docker Compose\">\n\n```bash\ndocker compose exec seerr sh -c \"apk update && apk add curl && curl -L https://api.themoviedb.org\"\n```\n\n  </TabItem>\n  <TabItem value=\"linux\" label=\"Linux\">\n\nIn a terminal:\n```bash\ncurl -L https://api.themoviedb.org\n```\n\n  </TabItem>\n  <TabItem value=\"windows\" label=\"Windows\">\n\nIn a PowerShell window:\n```powershell\n(Invoke-WebRequest -Uri \"https://api.themoviedb.org\" -Method Get).Content\n```\n\n  </TabItem>\n\n</Tabs>\n\nIf you can't get a response, then your server can't reach the TMDB API.\nThis is usually due to a network configuration issue or a firewall blocking the connection.\n\n## Account does not have admin privileges\n\nIf your admin account no longer has admin privileges, this is typically because your Jellyfin/Emby user ID has changed on the server side.\n\nThis can happen if you have a new installation of Jellyfin/Emby or if you have changed the user ID of your admin account.\n\n### Solution: Reset admin access\n\n1. Back up your `settings.json` file (located in your Seerr data directory)\n2. Stop the Seerr container/service\n3. Delete the `settings.json` file\n4. Start Seerr again\n5. This will force the setup page to appear\n6. Go through the setup process with the same login details\n7. You can skip the services setup\n8. Once you reach the discover page, stop Seerr\n9. Restore your backed-up `settings.json` file\n10. Start Seerr again\n\nThis process should restore your admin privileges while preserving your settings.\n\n## Failed to enable web push notifications\n\n### Option 1: You are using Pi-hole\n\nWhen using Pi-hole, you need to whitelist the proper domains in order for the queries to not be intercepted and blocked by Pi-hole.\nIf you are using a chromium based browser (eg: Chrome, Brave, Edge...), the domain you need to whitelist is `fcm.googleapis.com`\nIf you are using Firefox, the domain you need to whitelist is `push.services.mozilla.com`\n\n1. Log into your Pi-hole through the admin interface, then click on Domains situated under GROUP MANAGEMENT.\n2. Add the domain corresponding to your browser in the `Domain to be added` field and then click on Add to allowed domains.\n3. Now in order for those changes to be used you need to flush your current dns cache.\n4. You can do so by using this command line in your Pi-hole terminal:\n    ```bash\n    pihole restartdns\n    ```\nIf this command fails (which is unlikely), use this equivalent:\n    ```bash\n    pihole -f && pihole restartdns\n    ```\n5. Then restart your Seerr instance and try to enable the web push notifications again.\n\n\n### Option 2: You are using Brave browser\n\nBrave is a \"De-Googled\" browser. So by default or if you refused a prompt in the past, it cuts the access to the FCM (Firebase Cloud Messaging) service, which is mandatory for the web push notifications on Chromium based browsers.\n\n1. Open Brave and paste this address in the url bar: `brave://settings/privacy`\n2. Look for the option: \"Use Google services for push messaging\"\n3. Activate this option\n4. Relaunch Brave completely\n5. You should now see the notifications prompt appearing instead of an error message.\n\nIf you still encounter issues, please reach out on our support channels.\n"
  },
  {
    "path": "docs/using-seerr/_category_.json",
    "content": "{\n  \"label\": \"Using Seerr\",\n  \"position\": 2,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"title\": \"Using Seerr\",\n    \"description\": \"Learn how to use Seerr\"\n  }\n}\n"
  },
  {
    "path": "docs/using-seerr/advanced/index.mdx",
    "content": "---\ntitle: Advanced Features\ndescription: Advanced configuration and use cases.\nsidebar_position: 6\n---\n\n# Advanced Features\n\n## Advanced Configuration and Use Cases\n\nSeerr currently offers advanced features for power users and specific use cases:\n\nimport DocCardList from '@theme/DocCardList';\n\n<DocCardList />\n"
  },
  {
    "path": "docs/using-seerr/advanced/verifying-signed-artifacts.mdx",
    "content": "---\nid: verifying-signed-artifacts\ntitle: Verifying Signed Artifacts\nsidebar_label: Verify Signed Artifacts\ndescription: Learn how to verify Seerr's signed artifacts and SBOM attestations.\n---\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n# Verifying Signed Artifacts\n\nThese artifacts are cryptographically signed using [Sigstore Cosign](https://docs.sigstore.dev/quickstart/quickstart-cosign/):\n- Container images\n- Helm charts\n\nThis ensures that the images you pull are authentic, tamper-proof, and built by the official Seerr release pipeline.\n\nAdditionally each container image also includes a CycloneDX SBOM (Software Bill of Materials) attestation, generated with [Trivy](https://aquasecurity.github.io/trivy/), providing transparency about all dependencies included in the image.\n\n---\n\n## Prerequisites\n\nYou will need the following tools installed:\n\n- [Cosign](https://docs.sigstore.dev/cosign/system_config/installation/)\n\nTo verify images:\n\n- [Docker](https://docs.docker.com/get-docker/) **or** [Podman](https://podman.io/getting-started/installation) (including [Skopeo](https://github.com/containers/skopeo/blob/main/install.md))\n\n---\n\n## Verifying Signed Images\n\n### Image Locations\n\nOfficial Seerr images are available from:\n\n- GitHub Container Registry (GHCR): `ghcr.io/seerr-team/seerr:<tag>`\n- Docker Hub: `seerr/seerr:<tag>`\n\nYou can view all available tags on the [Seerr Releases page](https://github.com/seerr-team/seerr/releases).\n\n---\n\n### Verifying a Specific Release Tag\n\nEach tagged release (for example `v2.7.4`) is immutable and cryptographically signed.\nVerification should always be performed using the image digest (SHA256).\n\n#### Retrieve the Image Digest\n\n<Tabs groupId=\"verify-methods\">\n  <TabItem value=\"docker\" label=\"Docker\">\n\n```bash\ndocker buildx imagetools inspect ghcr.io/seerr-team/seerr:v2.7.4 --format '{{json .Manifest.Digest}}' | tr -d '\"'\n```\n  </TabItem>\n\n  <TabItem value=\"podman\" label=\"Podman / Skopeo\">\n\n```bash\nskopeo inspect docker://ghcr.io/seerr-team/seerr:v2.7.4 --format '{{.Digest}}'\n```\n  </TabItem>\n</Tabs>\n\nExample output:\n\n```\nsha256:abcd1234...\n```\n\n---\n\n#### Verify the Image Signature\n\n<Tabs groupId=\"registry-methods\">\n  <TabItem value=\"ghcr\" label=\"GitHub Container Registry (GHCR)\">\n\n```bash\ncosign verify ghcr.io/seerr-team/seerr@sha256:abcd1234... \\\n  --certificate-identity \"https://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v2.7.4\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n  </TabItem>\n\n  <TabItem value=\"dockerhub\" label=\"Docker Hub\">\n\n```bash\ncosign verify seerr/seerr@sha256:abcd1234... \\\n  --certificate-identity \"https://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v2.7.4\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n  </TabItem>\n</Tabs>\n\n:::info Successful Verification Example\nVerification for `ghcr.io/seerr-team/seerr@sha256:abcd1234...`\n\nThe following checks were performed:\n\n- Cosign claims validated\n- Signatures verified against the transparency log\n- Certificate issued by Fulcio to the expected workflow identity\n:::\n\n---\n\n### Verifying the `latest` Tag\n\n:::warning Latest Tag Warning\nThe `latest` tag is **mutable**, meaning it will change with each new release.\nAlways verify the digest that `latest` currently points to.\n:::\n\n#### Retrieve the Digest for `latest`\n\n<Tabs groupId=\"verify-methods\">\n  <TabItem value=\"docker\" label=\"Docker\">\n\n```bash\ndocker buildx imagetools inspect ghcr.io/seerr-team/seerr:latest --format '{{json .Manifest.Digest}}' | tr -d '\"'\n```\n  </TabItem>\n\n  <TabItem value=\"podman\" label=\"Podman / Skopeo\">\n\n```bash\nskopeo inspect docker://ghcr.io/seerr-team/seerr:latest --format '{{.Digest}}'\n```\n  </TabItem>\n</Tabs>\n\nExample output:\n\n```\nsha256:abcd1234...\n```\n\n#### Verify the Signature\n\n<Tabs groupId=\"registry-methods\">\n  <TabItem value=\"ghcr\" label=\"GHCR\">\n\n```bash\ncosign verify ghcr.io/seerr-team/seerr@sha256:abcd1234... \\\n  --certificate-identity-regexp \"https://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v.*\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n  </TabItem>\n\n  <TabItem value=\"dockerhub\" label=\"Docker Hub\">\n\n```bash\ncosign verify seerr/seerr@sha256:abcd1234... \\\n  --certificate-identity-regexp \"https://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v.*\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n  </TabItem>\n</Tabs>\n\n:::tip\nThe wildcard `v.*` ensures verification works for any versioned release that `latest` represents.\n:::\n\n---\n\n### Verifying SBOM Attestations\n\nEach image includes a CycloneDX SBOM attestation.\n\n#### Verify the Attestation\n\n```bash\ncosign verify-attestation ghcr.io/seerr-team/seerr@sha256:abcd1234... \\\n  --type cyclonedx \\\n  --certificate-identity \"https://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v2.7.4\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n:::info Successful Verification Example\nVerification for `ghcr.io/seerr-team/seerr@sha256:abcd1234...`\n\nThe following checks were performed:\n\n- Cosign claims validated\n- Signatures verified against the transparency log\n- Certificate issued by Fulcio to the expected workflow identity\n:::\n\n#### Extract the SBOM for Inspection\n\n```bash\ncosign verify-attestation ghcr.io/seerr-team/seerr@sha256:abcd1234... \\\n  --type cyclonedx \\\n  --certificate-identity \"https://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v2.7.4\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\" | jq -r '.payload | @base64d' > sbom.json\n```\n\nYou can open `sbom.json` in a CycloneDX viewer or analyse it with [Trivy](https://aquasecurity.github.io/trivy/) or [Dependency-Track](https://dependencytrack.org/).\n\n---\n\n### Expected Certificate Identity\n\nThe expected certificate identity for all signed Seerr images is:\n\n```\nhttps://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v*\n```\n\nThis confirms that the image was:\n\n- Built by the official Seerr Release workflow\n- Produced from the seerr-team/seerr repository\n- Signed using GitHub’s OIDC identity via Sigstore Fulcio\n\n---\n\n### Example: Full Verification Flow\n\n<Tabs groupId=\"verify-examples\">\n  <TabItem value=\"docker\" label=\"Docker\">\n\n```bash\nDIGEST=$(docker buildx imagetools inspect ghcr.io/seerr-team/seerr:latest --format '{{json .Manifest.Digest}}' | tr -d '\"')\n\ncosign verify ghcr.io/seerr-team/seerr@\"$DIGEST\" \\\n  --certificate-identity-regexp \"https://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v.*\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n\ncosign verify-attestation ghcr.io/seerr-team/seerr@\"$DIGEST\" \\\n  --type cyclonedx \\\n  --certificate-identity-regexp \"https://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v.*\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n  </TabItem>\n\n  <TabItem value=\"podman\" label=\"Podman / Skopeo\">\n\n```bash\nDIGEST=$(skopeo inspect docker://ghcr.io/seerr-team/seerr:latest --format '{{.Digest}}')\n\ncosign verify ghcr.io/seerr-team/seerr@\"$DIGEST\" \\\n  --certificate-identity-regexp \"https://github.com/seerr-team/seerr/.github/workflows/release.yml@refs/tags/v.*\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n  </TabItem>\n</Tabs>\n\n## Verifying Signed Helm charts\n\n### Helm Chart Locations\n\nOfficial Seerr helm charts are available from:\n\n- GitHub Container Registry (GHCR): `ghcr.io/seerr-team/seerr/seerr-chart/seerr-chart:<tag>`\n\nYou can view all available tags on the [Seerr Releases page](https://github.com/seerr-team/seerr/pkgs/container/seerr%2Fseerr-chart).\n\n---\n\n### Verifying a Specific Release Tag\n\nEach tagged release (for example `3.0.0`) is immutable and cryptographically signed.\nVerification should always be performed using the image digest (SHA256).\n\n#### Retrieve the Helm Chart Digest\n\n<Tabs groupId=\"verify-methods\">\n  <TabItem value=\"docker\" label=\"Docker\">\n\n```bash\ndocker buildx imagetools inspect ghcr.io/seerr-team/seerr/seerr-chart:3.0.0 --format '{{json .Manifest.Digest}}' | tr -d '\"'\n```\n  </TabItem>\n\n  <TabItem value=\"podman\" label=\"Podman / Skopeo\">\n\n```bash\nskopeo inspect docker://ghcr.io/seerr-team/seerr/seerr-chart:3.0.0 --format '{{.Digest}}'\n```\n  </TabItem>\n</Tabs>\n\nExample output:\n\n```\nsha256:abcd1234...\n```\n\n---\n\n#### Verify the Helm Chart Signature\n\n```bash\ncosign verify ghcr.io/seerr-team/seerr/seerr-chart@sha256:abcd1234... \\\n  --certificate-identity \"https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n\n:::info Successful Verification Example\nVerification for `ghcr.io/seerr-team/seerr/seerr-chart@sha256:abcd1234...`\n\nThe following checks were performed:\n\n- Cosign claims validated\n- Signatures verified against the transparency log\n- Certificate issued by Fulcio to the expected workflow identity\n:::\n\n---\n\n### Expected Certificate Identity\n\nThe expected certificate identity for all signed Seerr images is:\n\n```\nhttps://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main\n```\n\nThis confirms that the image was:\n\n- Built by the official Seerr Release workflow\n- Produced from the seerr-team/seerr repository\n- Signed using GitHub’s OIDC identity via Sigstore Fulcio\n\n---\n\n### Example: Full Verification Flow\n\n<Tabs groupId=\"verify-examples\">\n  <TabItem value=\"docker\" label=\"Docker\">\n\n```bash\nDIGEST=$(docker buildx imagetools inspect ghcr.io/seerr-team/seerr/seerr-chart:3.0.0 --format '{{json .Manifest.Digest}}' | tr -d '\"')\n\ncosign verify ghcr.io/seerr-team/seerr/seerr-chart@\"$DIGEST\" \\\n  --certificate-identity-regexp \"https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n\ncosign verify-attestation ghcr.io/seerr-team/seerr/seerr-chart@\"$DIGEST\" \\\n  --type cyclonedx \\\n  --certificate-identity-regexp \"https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n  </TabItem>\n\n  <TabItem value=\"podman\" label=\"Podman / Skopeo\">\n\n```bash\nDIGEST=$(skopeo inspect docker://ghcr.io/seerr-team/seerr/seerr-chart:3.0.0 --format '{{.Digest}}')\n\ncosign verify ghcr.io/seerr-team/seerr/seerr-chart@\"$DIGEST\" \\\n  --certificate-identity-regexp \"https://github.com/seerr-team/seerr/.github/workflows/helm.yml@refs/heads/main\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n  </TabItem>\n</Tabs>\n\n---\n\n## Troubleshooting\n\n| Issue | Likely Cause | Suggested Fix |\n|-------|---------------|----------------|\n| `no matching signatures` | Incorrect digest or tag | Retrieve the digest again using Docker or Skopeo |\n| `certificate identity does not match expected` | Workflow reference changed | Ensure your `--certificate-identity` matches this documentation |\n| `cosign: command not found` | Cosign not installed | Install Cosign from the official release |\n| `certificate expired` | Old release | Verify a newer tag or digest |\n\n---\n\n## Further Reading\n\n- [Sigstore Documentation](https://docs.sigstore.dev)\n- [Cosign Verification Guide](https://docs.sigstore.dev/cosign/verifying/verify/)\n- [CycloneDX Specification](https://cyclonedx.org/specification/overview/)\n- [Trivy Documentation](https://trivy.dev/latest/docs/)\n- [Skopeo Documentation](https://github.com/containers/skopeo)\n- [Podman Documentation](https://podman.io/get-started/)\n- [Docker Documentation](https://docs.docker.com/)\n- [Seerr GitHub Repository](https://github.com/seerr-team/seerr)\n"
  },
  {
    "path": "docs/using-seerr/backups.md",
    "content": "---\ntitle: Backups\ndescription: Understand which data you should back up.\nsidebar_position: 4\n---\n\n# Which data does Seerr save and where?\n\n## Settings  \n\nAll configurations from the **Settings** panel in the Seerr web UI are saved, including integrations with Radarr, Sonarr, Jellyfin, Plex, and notification settings.  \nThese settings are stored in the `settings.json` file located in the Seerr data folder.\n\n## User Data  \n\nApart from the settings, all other data—including user accounts, media requests, blocklist etc. are stored in the database (either SQLite or PostgreSQL).\n\n# Backup\n\n### SQLite\n\nIf your backup system uses filesystem snapshots (such as Kubernetes with Volsync), you can directly back up the Seerr data folder.  \nOtherwise, you need to stop the Seerr application and back up the `config` folder.\n\nFor advanced users, it's possible to back up the database without stopping the application by using the [SQLite CLI](https://www.sqlite.org/download.html). Run the following command to create a backup:  \n\n```bash\nsqlite3 db/db.sqlite3 \".backup '/tmp/seerr_db.sqlite3.bak'\"\n```  \n\nThen, copy the `/tmp/seerr_dump.sqlite3.bak` file to your desired backup location.\n\n### PostgreSQL\n\nYou can back up the `config` folder and dump the PostgreSQL database without stopping the Seerr application.\n\nInstall [postgresql-client](https://www.postgresql.org/download/) and run the following command to create a backup (just replace the placeholders):\n\n:::info\nDepending on how your PostgreSQL instance is configured, you may need to add these options to the command below.\n\n  -h, --host=HOSTNAME      database server host or socket directory\n\n  -p, --port=PORT          database server port number\n:::\n\n```bash\npg_dump -U <database_user> -d <database_name> -f /tmp/seerr_db.sql\n```\n\n# Restore\n\n### SQLite\n\nAfter restoring your `db/db.sqlite3` file and, optionally, the `settings.json` file, the `config` folder structure should look like this:\n\n```\n.\n├── cache            <-- Optional\n├── db\n│   └── db.sqlite3\n├── logs             <-- Optional\n└── settings.json    <-- Optional (required if you want to avoid reconfiguring Seerr)\n```\n\nOnce the files are restored, start the Seerr application.\n\n### PostgreSQL\n\nInstall the [PostgreSQL client](https://www.postgresql.org/download/) and restore the PostgreSQL database using the following command (replace the placeholders accordingly):\n\n:::info\nDepending on how your PostgreSQL instance is configured, you may need to add these options to the command below.\n\n  -h, --host=HOSTNAME      database server host or socket directory\n\n  -p, --port=PORT          database server port number\n:::\n\n```bash\npg_restore -U <database_user> -d <database_name> /tmp/seerr_db.sql\n```\n\nOptionally, restore the `settings.json` file. The `config` folder structure should look like this:\n\n```\n.\n├── cache            <-- Optional\n├── logs             <-- Optional\n└── settings.json    <-- Optional (required if you want to avoid reconfiguring Seerr)\n```\n\nOnce the database and files are restored, start the Seerr application.\n"
  },
  {
    "path": "docs/using-seerr/notifications/discord.md",
    "content": "---\ntitle: Discord\ndescription: Configure Discord notifications.\nsidebar_position: 3\n---\n\n# Discord\n\nThe Discord notification agent enables you to post notifications to a channel in a server you manage.\n\n:::info\nUsers can optionally opt-in to being mentioned in Discord notifications by configuring their [Discord user ID](https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-) in their user settings.\n:::\n\n## Configuration\n\n### Webhook URL\n\nYou can find the webhook URL in the Discord application, at **Server Settings &rarr; Integrations &rarr; Webhooks**.\n\n### Notification Role ID (optional)\n\nIf a role ID is specified, it will be included in the webhook message. See [Discord role ID](https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID).\n\n### Bot Username (optional)\n\nIf you would like to override the name you configured for your bot in Discord, you may set this value to whatever you like!\n\n### Bot Avatar URL (optional)\n\nSimilar to the bot username, you can override the avatar for your bot.\n"
  },
  {
    "path": "docs/using-seerr/notifications/email.md",
    "content": "---\ntitle: Email\ndescription: Configure email notifications for your users.\nsidebar_position: 1\n---\n\n# Email\n\n## Configuration\n\n:::info\nIf the [Application URL](/using-seerr/settings/general#application-title) setting is configured in **Settings → General**, Seerr will explicitly set the origin server hostname when connecting to the SMTP host.\n:::\n\n### Sender Name (optional)\n\nConfigure a friendly name for the email sender (e.g., \"Seerr\").\n\n### Sender Address\n\nSet this to the email address you would like to appear in the \"from\" field of the email message.\n\nDepending on your email provider, this may need to be an address you own. For example, Gmail requires this to be your actual email address.\n\n### SMTP Host\n\nSet this to the hostname or IP address of your SMTP server.\n\n### SMTP Port\n\nSet this to a supported port number for your SMTP host. `465` and `587` are commonly used.\n\n### Encryption Method\n\nIn most cases, [Use Implicit TLS](https://tools.ietf.org/html/rfc8314) should be selected for port 465, and [Use STARTTLS](https://en.wikipedia.org/wiki/Opportunistic_TLS) if available for port 587. Please refer to your email provider's documentations for details on how to configure this setting.\n\nThe default value for this setting is **Use STARTTLS if available**.\n\n### SMTP Username & Password\n\n:::info\nIf your account has two-factor authentication enabled, you may need to create an application password instead of using your account password.\n:::\nConfigure these values as appropriate to authenticate with your SMTP host.\n\n### PGP Private Key & Password (optional)\n\nConfigure 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.\n\nWhen 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-----`.\n"
  },
  {
    "path": "docs/using-seerr/notifications/gotify.md",
    "content": "---\ntitle: Gotify\ndescription: Configure Gotify notifications.\nsidebar_position: 5\n---\n\n# Gotify\n\n## Configuration\n\n### Server URL\n\nSet this to the URL of your Gotify server.\n\n### Application Token\n\nAdd an application to your Gotify server, and set this field to the generated application token.\n\n:::info\nPlease refer to the [Gotify API documentation](https://gotify.net/docs) for more details on configuring these notifications.\n:::\n"
  },
  {
    "path": "docs/using-seerr/notifications/index.mdx",
    "content": "---\ntitle: Notifications\ndescription: Configure notifications for your users.\nsidebar_position: 3\n---\n\n# Notifications\n\n## Supported Notification Agents\n\nSeerr currently supports the following notification agents:\n\nimport DocCardList from '@theme/DocCardList';\n\n<DocCardList />\n\n## Setting Up Notifications\n\nSimply configure your desired notification agents in **Settings -> Notifications** in the Seerr web UI.\n\nUsers can customize their notification preferences in their own user notification settings.\n\n## Requesting New Notification Agents\n\nIf we do not currently support your preferred notification agent, feel free to [submit a feature request on GitHub](https://github.com/seerr-team/seerr/issues). However, please be sure to search first and confirm that there is not already an existing request for the agent!\n"
  },
  {
    "path": "docs/using-seerr/notifications/ntfy.md",
    "content": "---\ntitle: ntfy.sh\ndescription: Configure ntfy.sh notifications.\nsidebar_position: 6\n---\n\n# ntfy.sh\n\n## Configuration\n\n### Server Root URL\n\nSet this to the URL of your ntfy.sh server.\n\n### Topic\n\nSet this to the topic you want to send notifications to.\n\n### Username + Password authentication (optional)\n\nSet this to the username and password for your ntfy.sh server.\n\n### Token authentication (optional)\n\nSet this to the token for your ntfy.sh server.\n\n### Priority (optional)\n\nSet the priority level for notifications. Options range from Minimum (1) to Urgent (5), with Default (3) being the standard level. Higher priority notifications may bypass Do Not Disturb settings on some devices.\n\n:::info\nPlease refer to the [ntfy.sh API documentation](https://docs.ntfy.sh/) for more details on configuring these notifications.\n:::\n"
  },
  {
    "path": "docs/using-seerr/notifications/pushbullet.md",
    "content": "---\ntitle: Pushbullet\ndescription: Configure Pushbullet notifications.\nsidebar_position: 7\n---\n\n# Pushbullet\n\n:::info\nUsers can optionally configure personal notifications in their user settings.\n\nUser notifications are separate from system notifications, and the available notification types are dependent on user permissions.\n:::\n\n## Configuration\n\n### Access Token\n\n[Create an access token](https://www.pushbullet.com/#settings) and set it here to grant Seerr access to the Pushbullet API.\n\n### Channel Tag (optional)\n\nOptionally, [create a channel](https://www.pushbullet.com/my-channel) to allow other users to follow the notification feed using the specified channel tag.\n"
  },
  {
    "path": "docs/using-seerr/notifications/pushover.md",
    "content": "---\ntitle: Pushover\ndescription: Configure Pushover notifications.\nsidebar_position: 8\n---\n\n# Pushover\n\n:::info\nUsers can optionally configure personal notifications in their user settings.\n\nUser notifications are separate from system notifications, and the available notification types are dependent on user permissions.\n:::\n\n## Configuration\n\n### Application/API Token\n\n[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/seerr-team/seerr/tree/develop/public) when configuring the application.)\n\nFor more details on registering applications or the API token, please see the [Pushover API documentation](https://pushover.net/api#registration).\n\n### User Key\n\nSet this to the user key for your Pushover account. Alternatively, you can set this to a group key to deliver notifications to multiple users.\n\nFor more details, please see the [Pushover API documentation](https://pushover.net/api#identifiers).\n"
  },
  {
    "path": "docs/using-seerr/notifications/slack.md",
    "content": "---\ntitle: Slack\ndescription: Configure Slack notifications.\nsidebar_position: 9\n---\n\n# Slack\n\n## Configuration\n\n### Webhook URL\n\nSimply [create a webhook](https://my.slack.com/services/new/incoming-webhook/) and enter the URL in this field.\n\n:::info\nPlease refer to the [Slack API documentation](https://api.slack.com/messaging/webhooks) for more details on configuring these notifications.\n:::\n"
  },
  {
    "path": "docs/using-seerr/notifications/telegram.md",
    "content": "---\ntitle: Telegram\ndescription: Configure Telegram notifications.\nsidebar_position: 10\n---\n\n# Telegram\n\n:::info\nUsers can optionally configure personal notifications in their user settings.\n\nUser notifications are separate from system notifications, and the available notification types are dependent on user permissions.\n:::\n\n## Configuration\n\n:::info\nIn order to configure Telegram notifications, you first need to [create a bot](https://telegram.me/BotFather).\n\nBots **cannot** initiate conversations with users, so users must have your bot added to a conversation in order to receive notifications.\n:::\n\n### Bot Username (optional)\n\nIf this value is configured, users will be able to click a link to start a chat with your bot and configure their own personal notifications.\n\nThe bot username should end with `_bot`, and the `@` prefix should be omitted.\n\n### Bot Authentication Token\n\nAt the end of the bot creation process, [@BotFather](https://telegram.me/botfather) will provide an authentication token.\n\n### Chat ID\n\nTo 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.\n\n### Send Silently (optional)\n\nOptionally, notifications can be sent silently. Silent notifications send messages without notification sounds.\n"
  },
  {
    "path": "docs/using-seerr/notifications/webhook.md",
    "content": "---\ntitle: Webhook\ndescription: Configure webhook notifications.\nsidebar_position: 4\n---\n\n# Webhook\n\nThe webhook notification agent enables you to send a custom JSON payload to any endpoint for specific notification events.\n\n## Configuration\n\n### Webhook URL\n\nThe URL you would like to post notifications to. Your JSON will be sent as the body of the request.\n\n### Authorization Header (optional)\n\n:::info\nThis is typically not needed. Please refer to your webhook provider's documentation for details.\n:::\n\nThis value will be sent as an `Authorization` HTTP header.\n\n### Custom Headers (optional)\n\nYou can add additional custom HTTP headers to be sent with each webhook request. This is useful for API keys, custom authentication schemes, or any other headers your webhook endpoint requires.\n\n- Click \"Add Header\" to add a new header\n- Enter the header name and value\n\n:::warning\nYou cannot configure both the **Authorization Header** field and a custom `Authorization` header in Custom Headers at the same time. You must choose one method.\n:::\n\n### JSON Payload\n\nCustomize the JSON payload to suit your needs. Seerr provides several [template variables](#template-variables) for use in the payload, which will be replaced with the relevant data when the notifications are triggered.\n\n## Template Variables\n\n### General\n\n| Variable                | Value                                                                                                                               |\n| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |\n| `{{notification_type}}` | The type of notification (e.g. `MEDIA_PENDING` or `ISSUE_COMMENT`)                                                                  |\n| `{{event}}`             | A friendly description of the notification event                                                                                    |\n| `{{subject}}`           | The notification subject (typically the media title)                                                                                |\n| `{{message}}`           | The notification message body (the media overview/synopsis for request notifications; the issue description for issue notificatons) |\n| `{{image}}`             | The notification image (typically the media poster)                                                                                 |\n\n### Notify User\n\nThese variables are for the target recipient of the notification.\n\n| Variable                                 | Value                                                         |\n| ---------------------------------------- | ------------------------------------------------------------- |\n| `{{notifyuser_username}}`                | The target notification recipient's username                  |\n| `{{notifyuser_email}}`                   | The target notification recipient's email address             |\n| `{{notifyuser_avatar}}`                  | The target notification recipient's avatar URL                |\n| `{{notifyuser_settings_discordId}}`      | The target notification recipient's Discord ID (if set)       |\n| `{{notifyuser_settings_telegramChatId}}` | The target notification recipient's Telegram Chat ID (if set) |\n\n:::info\nThe `notifyuser` variables are not defined for the following request notification types, as they are intended for application administrators rather than end users:\n\n- Request Pending Approval\n- Request Automatically Approved\n- Request Processing Failed\n\nOn the other hand, the `notifyuser` variables _will_ be replaced with the requesting user's information for the below notification types:\n\n- Request Approved\n- Request Declined\n- Request Available\n\nIf 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.\n:::\n\n### Special\n\nThe following variables must be used as a key in the JSON payload (e.g., `\"{{extra}}\": []`).\n\n| Variable      | Value                                                                                                                          |\n| ------------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| `{{media}}`   | The relevant media object                                                                                                      |\n| `{{request}}` | The relevant request object                                                                                                    |\n| `{{issue}}`   | The relevant issue object                                                                                                      |\n| `{{comment}}` | The relevant issue comment object                                                                                              |\n| `{{extra}}`   | The \"extra\" array of additional data for certain notifications (e.g., season/episode numbers for series-related notifications) |\n\n#### Media\n\nThe `{{media}}` will be `null` if there is no relevant media object for the notification.\n\nThese following special variables are only included in media-related notifications, such as requests.\n\n| Variable                      | Value                                                                                                          |\n| ------------------------------| -------------------------------------------------------------------------------------------------------------- |\n| `{{media_type}}`              | The media type (`movie` or `tv`)                                                                               |\n| `{{media_tmdbid}}`            | The media's TMDB ID                                                                                            |\n| `{{media_tvdbid}}`            | The media's TheTVDB ID                                                                                         |\n| `{{media_status}}`            | The media's availability status (`UNKNOWN`, `PENDING`, `PROCESSING`, `PARTIALLY_AVAILABLE`, or `AVAILABLE`)    |\n| `{{media_status4k}}`          | The media's 4K availability status (`UNKNOWN`, `PENDING`, `PROCESSING`, `PARTIALLY_AVAILABLE`, or `AVAILABLE`) |\n| `{{media_jellyfinMediaId}}`   | The media's Jellyfin Media ID                                                                                  |\n\n#### Request\n\nThe `{{request}}` will be `null` if there is no relevant media object for the notification.\n\nThe following special variables are only included in request-related notifications.\n\n| Variable                                  | Value                                           |\n| ----------------------------------------- | ----------------------------------------------- |\n| `{{request_id}}`                          | The request ID                                  |\n| `{{requestedBy_username}}`                | The requesting user's username                  |\n| `{{requestedBy_email}}`                   | The requesting user's email address             |\n| `{{requestedBy_avatar}}`                  | The requesting user's avatar URL                |\n| `{{requestedBy_jellyfinUserId}}`          | The requesting user's Jellyfin User ID          |\n| `{{requestedBy_settings_discordId}}`      | The requesting user's Discord ID (if set)       |\n| `{{requestedBy_settings_telegramChatId}}` | The requesting user's Telegram Chat ID (if set) |\n\n#### Issue\n\nThe `{{issue}}` will be `null` if there is no relevant media object for the notification.\n\nThe following special variables are only included in issue-related notifications.\n\n| Variable                                 | Value                                           |\n| ---------------------------------------- | ----------------------------------------------- |\n| `{{issue_id}}`                           | The issue ID                                    |\n| `{{reportedBy_username}}`                | The requesting user's username                  |\n| `{{reportedBy_email}}`                   | The requesting user's email address             |\n| `{{reportedBy_avatar}}`                  | The requesting user's avatar URL                |\n| `{{reportedBy_settings_discordId}}`      | The requesting user's Discord ID (if set)       |\n| `{{reportedBy_settings_telegramChatId}}` | The requesting user's Telegram Chat ID (if set) |\n\n#### Comment\n\nThe `{{comment}}` will be `null` if there is no relevant media object for the notification.\n\nThe following special variables are only included in issue comment-related notifications.\n\n| Variable                                  | Value                                           |\n| ----------------------------------------- | ----------------------------------------------- |\n| `{{comment_message}}`                     | The comment message                             |\n| `{{commentedBy_username}}`                | The commenting user's username                  |\n| `{{commentedBy_email}}`                   | The commenting user's email address             |\n| `{{commentedBy_avatar}}`                  | The commenting user's avatar URL                |\n| `{{commentedBy_settings_discordId}}`      | The commenting user's Discord ID (if set)       |\n| `{{commentedBy_settings_telegramChatId}}` | The commenting user's Telegram Chat ID (if set) |\n"
  },
  {
    "path": "docs/using-seerr/notifications/webpush.md",
    "content": "---\ntitle: Web Push\ndescription: Configure web push notifications for your users.\nsidebar_position: 2\n---\n\n# Web Push\n\n:::warning\nWeb push notifications require a secure connection to your Seerr instance. Refer to the [Reverse Proxy](/extending-seerr/reverse-proxy) documentation for more information.\n:::\n\nThe web push notification agent enables you and your users to receive Seerr notifications in a supported browser. This offers a native notification experience without the need to install an app.\n\nThis notification agent does not require any configuration, but is not enabled by default in Seerr.\n\nTo set up web push notifications, simply enable the agent in **Settings → Notifications → Web Push**.\n\nYou and your users have the option to enable web push notifications by going to your **User Profile → Edit Settings → Notifications → Web Push → Enable web push**. Here you can also customize the notifications you'd like to receive.\n\n:::info[Mobile Users]\nFor Web Push notifications to work on mobile you need to add Seerr to your home screen as progressive web app (PWA). \n:::\n\n:::info[iOS Users]\nOn iOS you may need to enable the Safari notifications feature flag by going to **Settings → Safari → Advanced → Feature Flags** and enabling \"Notifications\".\n:::\n"
  },
  {
    "path": "docs/using-seerr/plex/_category_.json",
    "content": "{\n  \"label\": \"Plex Integration\",\n  \"position\": 3,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"title\": \"Plex Integration\",\n    \"description\": \"Learn about Seerr's Plex integration features\"\n  }\n}\n"
  },
  {
    "path": "docs/using-seerr/plex/index.md",
    "content": "---\ntitle: Overview\ndescription: Learn about Seerr's Plex integration features\nsidebar_position: 1\n---\n\n# Plex Features Overview\n\nSeerr provides integration features that connect with your Plex media server to automate media management tasks.\n\n## Available Features\n\n- [Watchlist Auto Request](./plex/watchlist-auto-request) - Automatically request media from your Plex Watchlist\n- More features coming soon!\n\n## Prerequisites\n\n:::info Authentication Required\nTo use any Plex integration features, you must have logged into Seerr at least once with your Plex account.\n:::\n\n**Requirements:**\n- Plex account with access to the configured Plex server\n- Seerr configured with Plex as the media server\n- User authentication via Plex login\n- Appropriate user permissions for specific features\n\n## Getting Started\n\n1. Authenticate at least once using your Plex credentials\n2. Verify you have the necessary permissions for desired features\n3. Follow individual feature guides for setup instructions\n\n:::note Server Configuration\nPlex server configuration is handled by your administrator. If you cannot log in with your Plex account, contact your administrator to verify the server setup.\n:::\n"
  },
  {
    "path": "docs/using-seerr/plex/watchlist-auto-request.md",
    "content": "---\ntitle: Watchlist Auto Request\ndescription: Learn how to use the Plex Watchlist Auto Request feature\nsidebar_position: 1\n---\n\n# Watchlist Auto Request\n\nThe Plex Watchlist Auto Request feature allows Seerr to automatically create requests for media items you add to your Plex Watchlist. Simply add content to your Plex Watchlist, and Seerr will automatically request it for you.\n\n:::info\nThis feature is only available for Plex users. Local users cannot use the Watchlist Auto Request feature.\n:::\n\n## Prerequisites\n\n- You must have logged into Seerr at least once with your Plex account\n- Your administrator must have granted you the necessary permissions\n- Your Plex account must have access to the Plex server configured in Seerr\n\n## Permission System\n\nThe Watchlist Auto Request feature uses a two-tier permission system:\n\n### Administrator Permissions (Required)\nYour administrator must grant you these permissions in your user profile:\n- **Auto-Request** (master permission)\n- **Auto-Request Movies** (for movie auto-requests)\n- **Auto-Request Series** (for TV series auto-requests)\n\n### User Activation (Required)\nYou must enable the feature in your own profile settings:\n- **Auto-Request Movies** toggle\n- **Auto-Request Series** toggle\n\n:::warning Two-Step Process\nBoth administrator permissions AND user activation are required. Having permissions doesn't automatically enable the feature - you must also activate it in your profile.\n:::\n\n## How to Enable\n\n### Step 1: Check Your Permissions\nContact your administrator to verify you have been granted:\n- `Auto-Request` permission\n- `Auto-Request Movies` and/or `Auto-Request Series` permissions\n\n### Step 2: Activate the Feature\n1. Go to your user profile settings\n2. Navigate to the \"General\" section\n3. Find the \"Auto-Request\" options\n4. Enable the toggles for:\n   - **Auto-Request Movies** - to automatically request movies from your watchlist\n   - **Auto-Request Series** - to automatically request TV series from your watchlist\n\n### Step 3: Start Using\n- Add movies and TV shows to your Plex Watchlist\n- Seerr will automatically create requests for new items\n- You'll receive notifications when items are auto-requested\n\n## How It Works\n\nOnce properly configured, Seerr will:\n\n1. Periodically checks your Plex Watchlist for new items\n2. Verify if the content already exists in your media libraries\n3. Automatically submits requests for new items that aren't already available\n4. Only requests content types you have permissions for\n5. Notifiy you when auto-requests are created\n\n:::info Content Limitations\nAuto-request only works for standard quality content. 4K content must be requested manually if you have 4K permissions.\n:::\n\n## For Administrators\n\n### Granting Permissions\n1. Navigate to **Users** > **[Select User]** > **Permissions**\n2. Enable the required permissions:\n   - **Auto-Request** (master toggle)\n   - **Auto-Request Movies** (for movie auto-requests)\n   - **Auto-Request Series** (for TV series auto-requests)\n3. Optionally enable **Auto-Approve** permissions for automatic approval\n\n### Default Permissions\n- Go to **Settings** > **Users** > **Default Permissions**\n- Configure auto-request permissions for new users\n- This sets the default permissions but users still need to activate the feature individually\n\n## Limitations\n\n- Local users cannot use this feature\n- 4K content requires manual requests\n- Users must have logged into Seerr with their Plex account\n- Respects user request limits and quotas\n- Won't request content already in your libraries\n"
  },
  {
    "path": "docs/using-seerr/settings/_category_.json",
    "content": "{\n  \"label\": \"Settings\",\n  \"position\": 1,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"title\": \"Settings\",\n    \"description\": \"Configure Seerr to your liking\"\n  }\n}\n"
  },
  {
    "path": "docs/using-seerr/settings/dns-caching.md",
    "content": "---\ntitle: DNS Caching\ndescription: Configure DNS caching settings.\nsidebar_position: 7\n---\n\n# DNS Caching\n\nSeerr uses DNS caching to improve performance and reduce the number of DNS lookups required for external API calls. This can help speed up response times and reduce load on DNS servers, when something like a Pi-hole is used as a DNS resolver.\n\n## Configuration\n\nYou can enable the DNS caching settings in the Network tab of the Seerr settings. The default values follow the standard DNS caching behavior.\n\n- **Force Minimum TTL**: Set a minimum time-to-live (TTL) in seconds for DNS cache entries. This ensures that frequently accessed DNS records are cached for a longer period, reducing the need for repeated lookups. Default is 0.\n- **Force Maximum TTL**: Set a maximum time-to-live (TTL) in seconds for DNS cache entries. This prevents infrequently accessed DNS records from being cached indefinitely, allowing for more up-to-date information to be retrieved. Default is -1 (unlimited).\n"
  },
  {
    "path": "docs/using-seerr/settings/general.md",
    "content": "---\ntitle: General\ndescription: Configure global and default settings for Seerr.\nsidebar_position: 1\n---\n\n# General\n\n## API Key\n\nThis is your Seerr API key, which can be used to integrate Seerr with third-party applications. Do **not** share this key publicly, as it can be used to gain administrator access!\n\nIf you need to generate a new API key for any reason, simply click the button to the right of the text box.\n\nIf you want to set the API key, rather than letting it be randomly generated, you can use the API_KEY environment variable. Whatever that variable is set to will be your API key.\n\n## Application Title\n\nIf you aren't a huge fan of the name \"Seerr\" and would like to display something different to your users, you can customize the application title!\n\n## Application URL\n\nSet this to the externally-accessible URL of your Seerr instance.\n\nYou must configure this setting in order to enable password reset and generation emails.\n\n## Enable Proxy Support\n\nIf you have Seerr behind a reverse proxy, enable this setting to allow Seerr to correctly register client IP addresses. For details, please see the [Express Documentation](https://expressjs.com/en/guide/behind-proxies.html).\n\nThis setting is **disabled** by default.\n\n## Enable CSRF Protection\n\n:::warning\n**This is an advanced setting.** Please only enable this setting if you are familiar with CSRF protection and how it works.\n:::\n\nCSRF stands for [cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery). When this setting is enabled, all external API access that alters Seerr application data is blocked.\n\nIf you do not use Seerr integrations with third-party applications to add/modify/delete requests or users, you can consider enabling this setting to protect against malicious attacks.\n\nOne caveat, however, is that HTTPS is required, meaning that once this setting is enabled, you will no longer be able to access your Seerr instance over _HTTP_ (including using an IP address and port number).\n\nIf you enable this setting and find yourself unable to access Seerr, you can disable the setting by modifying `settings.json` in `/app/config`.\n\nThis setting is **disabled** by default.\n\n## Enable Image Caching\n\nWhen enabled, Jellseerr will proxy and cache images from pre-configured sources (such as TMDB). This can use a significant amount of disk space.\n\nImages are saved in the `config/cache/images` and stale images are cleared out every 24 hours.\n\nYou should enable this if you are having issues with loading images directly from TMDB in your browser.\n\n## Display Language\n\nSet the default display language for Seerr. Users can override this setting in their user settings.\n\n## Discover Region, Discover Language & Streaming Region\n\nThese settings filter content shown on the \"Discover\" home page based on regional availability and original language, respectively. The Streaming Region filters the available streaming providers on the media page. Users can override these global settings by configuring these same options in their user settings.\n\n## Blocklist Content with Tags and Limit Content Blocklisted per Tag\n\nThese settings blocklist any TV shows or movies that have one of the entered tags. The \"Process Blocklisted Tags\" job adds entries to the blocklist based on the configured blocklisted tags. If a blocklisted tag is removed, any media blocklisted under that tag will be removed from the blocklist when the \"Process Blocklisted Tags\" job runs.\n\nThe limit setting determines how many pages per tag the job will process, with each page containing 20 entries. The job cycles through all 16 available discovery sort options, querying the defined number of pages to blocklist media that is most likely to appear at the top of each sort. Higher limits will create a more accurate blocklist, but will require more storage.\n\nBlocklisted tags are disabled until at least one tag is entered. These settings cannot be overridden in user settings.\n\n## Hide Available Media\n\nWhen enabled, media which is already available will not appear on the \"Discover\" home page, or in the \"Recommended\" or \"Similar\" categories or other links on media detail pages.\n\nAvailable media will still appear in search results, however, so it is possible to locate and view hidden items by searching for them by title.\n\nThis setting is **disabled** by default.\n\n## Hide Blocklisted Items\n\nWhen enabled, media that has been blocklisted will not appear on the \"Discover\" home page, for all administrators. This can be useful to hide content that you don't want to see, such as content with specific tags or content that has been manually blocklisted when you have the \"Manage Blocklist\" permission.\n\nThis setting is **disabled** by default.\n\n## Allow Partial Series Requests\n\nWhen enabled, users will be able to submit requests for specific seasons of TV series. If disabled, users will only be able to submit requests for all unavailable seasons.\n\nThis setting is **enabled** by default.\n"
  },
  {
    "path": "docs/using-seerr/settings/jobs&cache.md",
    "content": "---\ntitle: Jobs & Cache\ndescription: Configure jobs and cache settings.\nsidebar_position: 6\n---\n\n# Jobs & Cache\n\nSeerr performs certain maintenance tasks as regularly-scheduled jobs, but they can also be manually triggered on this page.\n\nSeerr also caches requests to external API endpoints to optimize performance and avoid making unnecessary API calls. If necessary, the cache for any particular endpoint can be cleared by clicking the \"Flush Cache\" button.\n\nYou can also view the current image cache size as well as the total number of cached images.\n"
  },
  {
    "path": "docs/using-seerr/settings/mediaserver.mdx",
    "content": "---\ntitle: Mediaserver Settings\ndescription: Configure your Jellyfin, Emby, or Plex server settings.\nsidebar_position: 3\n---\n\n# Media Server\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n<Tabs groupId=\"media-server-type\" queryString>\n    <TabItem value=\"jellyfin\" label=\"Jellyfin\">\n:::info\nTo set up Jellyfin, make sure you log in using an account with administrative privileges.\n\nThe email address can be any email address and is only used for notifications, password resets, and local sign-in.\nIt is **not** tied to your Jellyfin account.\n:::\n\n### Jellyfin Libraries\n\nIn this section, simply select the libraries you would like Seerr to scan. Seerr will periodically check the selected libraries for available content to update the media status that is displayed to users.\n\nIf you do not see your Jellyfin library listed, verify your Jellyfin settings are correct and click the Sync Libraries button.\n\n### Manual Library Scan\n\nSeerr will perform a full scan of your Jellyfin libraries once every 24 hours (recently added items are fetched more frequently). If this is your first time configuring Jellyfin, a one-time full manual library scan is recommended!\n\n### Jellyfin Settings\n\nThis section is where you configure the connection to your Jellyfin server.\n\n    <Tabs groupId=\"versions\" queryString>\n        <TabItem value=\"latest\" label=\"Latest\">\n\n#### Internal URL\n\nThe internal URL is the URL that Seerr will use to communicate with your Jellyfin server. This URL should be accessible from the machine running Seerr.\n\nIn most cases, this will be the hostname or IP address of the machine running Jellyfin, followed by the port number Jellyfin is running on (usually 8096).\n\n:::note\nWhen running Seerr in a docker container with a bridged network (default), the container's network will be separate from the host network. Therefore, you cannot use `localhost` or `127.0.0.1` as the internal URL as it will resolve to the container itself.\n:::\n:::tip\nIf you are running Jellyfin in a docker container, you can put both Seerr and Jellyfin on the same docker network by using a custom [docker network](https://docs.docker.com/reference/cli/docker/network/). This will allow you to use the container name as the internal URL.\n:::\n\n#### External URL\n\nThe external URL is the URL that your users will use to access Jellyfin. This URL is used to generate links in `Play on Jellyfin` buttons, Jellyfin avatars and other places where users need to access Jellyfin directly.\n\nIn most cases, the external URL will be different from the internal URL. This is especially true if you are connecting to Jellyfin using docker container names or local IP addresses.\n\n#### Forgot Password URL\n\nThe forgot password URL is the URL that users will be directed to when they click the \"Forgot Password\" button on the login page. This URL should be accessible from the machine running Seerr.\n\nBy default, this field is empty and the \"Forgot Password\" button on the login page will redirect to the Jellyfin internal URL with the path `/web/index.html#!/forgotpassword`.\n\nYou can customize this URL to point to a custom password reset page if you have one.\n\n        </TabItem>\n        <TabItem value=\"develop\" label=\"develop\">\n\n#### Hostname or IP Address\n\nIf you have Seerr installed on the same network as Jellyfin, you can set this to the local IP address of your Jellyfin server. Otherwise, this should be set to a valid hostname (e.g., jellyfin.myawesomeserver.com).\n\nIn most cases, this will be the hostname or IP address of the machine running Jellyfin.\n\n:::note\nWhen running Seerr in a docker container with a bridged network (default), the container's network will be separate from the host network. Therefore, you cannot use `localhost` or `127.0.0.1` as the internal URL as it will resolve to the container itself.\n:::\n:::tip\nIf you are running Jellyfin in a docker container, you can put both Seerr and Jellyfin on the same docker network by using a custom [docker network](https://docs.docker.com/reference/cli/docker/network/). This will allow you to use the container name as the internal URL.\n:::\n\n#### Port\n\nThis value should be set to the port that your Jellyfin server listens on. The default port that Jellyfin uses is 8096, but you may need to set this to 443 or some other value if your Jellyfin server is hosted on a VPS or a different machine and is behind a reverse proxy.\n\n#### Use SSL\n\nEnable this setting to connect to Jellyfin via HTTPS rather than HTTP. Note that self-signed certificates are **not** officially supported.\n\n#### External URL\n\nThe external URL is the URL that your users will use to access Jellyfin. This URL is used to generate links in `Play on Jellyfin` buttons, Jellyfin avatars and other places where users need to access Jellyfin directly.\n\nIn most cases, the external URL will be different from the internal URL. This is especially true if you are connecting to Jellyfin using docker container names or local IP addresses.\n\n#### Forgot Password URL\n\nThe forgot password URL is the URL that users will be directed to when they click the \"Forgot Password\" button on the login page. This URL should be accessible from the machine running Seerr.\n\nBy default, this field is empty and the \"Forgot Password\" button on the login page will redirect to the Jellyfin internal URL with the path `/web/index.html#!/forgotpassword`.\n\nYou can customize this URL to point to a custom password reset page if you have one.\n\n            </TabItem>\n        </Tabs>\n    </TabItem>\n\n   <TabItem value=\"emby\" label=\"Emby\">\n:::info\nTo set up Emby, make sure you log in using an account with administrative privileges.\n\nThe email address can be any email address and is only used for notifications, password resets, and local sign-in.\nIt is **not** tied to your Emby account.\n:::\n\n### Emby Libraries\n\nIn this section, simply select the libraries you would like Seerr to scan. Seerr will periodically check the selected libraries for available content to update the media status that is displayed to users.\n\nIf you do not see your Emby library listed, verify your Emby settings are correct and click the Sync Libraries button.\n\n### Manual Library Scan\n\nSeerr will perform a full scan of your Emby libraries once every 24 hours (recently added items are fetched more frequently). If this is your first time configuring Emby, a one-time full manual library scan is recommended!\n\n### Emby Settings\n\nThis section is where you configure the connection to your Emby server.\n\n        <Tabs groupId=\"versions\" queryString>\n            <TabItem value=\"latest\" label=\"Latest\">\n\n#### Internal URL\n\nThe internal URL is the URL that Seerr will use to communicate with your Emby server. This URL should be accessible from the machine running Seerr.\n\nIn most cases, this will be the hostname or IP address of the machine running Emby, followed by the port number Emby is running on (usually 8096).\n\n:::note\nWhen running Seerr in a docker container with a bridged network (default), the container's network will be separate from the host network. Therefore, you cannot use `localhost` or `127.0.0.1` as the internal URL as it will resolve to the container itself.\n:::\n:::tip\nIf you are running Emby in a docker container, you can put both Seerr and Emby on the same docker network by using a custom [docker network](https://docs.docker.com/reference/cli/docker/network/). This will allow you to use the container name as the internal URL.\n:::\n\n#### External URL\n\nThe external URL is the URL that your users will use to access Emby. This URL is used to generate links in `Play on Emby` buttons, Emby avatars and other places where users need to access Emby directly.\n\nIn most cases, the external URL will be different from the internal URL. This is especially true if you are connecting to Emby using docker container names or local IP addresses.\n\n#### Forgot Password URL\n\nThe forgot password URL is the URL that users will be directed to when they click the \"Forgot Password\" button on the login page. This URL should be accessible from the machine running Seerr.\n\nBy default, this field is empty and the \"Forgot Password\" button on the login page will redirect to the Emby internal URL with the path `/web/index.html#!/forgotpassword.html`.\n\nYou can customize this URL to point to a custom password reset page if you have one.\n\n            </TabItem>\n            <TabItem value=\"develop\" label=\"develop\">\n\n#### Hostname or IP Address\n\nIf you have Seerr installed on the same network as Emby, you can set this to the local IP address of your Emby server. Otherwise, this should be set to a valid hostname (e.g., jellyfin.myawesomeserver.com).\n\nIn most cases, this will be the hostname or IP address of the machine running Emby.\n\n:::note\nWhen running Seerr in a docker container with a bridged network (default), the container's network will be separate from the host network. Therefore, you cannot use `localhost` or `127.0.0.1` as the internal URL as it will resolve to the container itself.\n:::\n:::tip\nIf you are running Emby in a docker container, you can put both Seerr and Emby on the same docker network by using a custom [docker network](https://docs.docker.com/reference/cli/docker/network/). This will allow you to use the container name as the internal URL.\n:::\n\n#### Port\n\nThis value should be set to the port that your Emby server listens on. The default port that Emby uses is 8096, but you may need to set this to 443 or some other value if your Emby server is hosted on a VPS or a different machine and is behind a reverse proxy.\n\n#### Use SSL\n\nEnable this setting to connect to Emby via HTTPS rather than HTTP. Note that self-signed certificates are **not** officially supported.\n\n#### External URL\n\nThe external URL is the URL that your users will use to access Emby. This URL is used to generate links in `Play on Emby` buttons, Emby avatars and other places where users need to access Emby directly.\n\nIn most cases, the external URL will be different from the internal URL. This is especially true if you are connecting to Emby using docker container names or local IP addresses.\n\n#### Forgot Password URL\n\nThe forgot password URL is the URL that users will be directed to when they click the \"Forgot Password\" button on the login page. This URL should be accessible from the machine running Seerr.\n\nBy default, this field is empty and the \"Forgot Password\" button on the login page will redirect to the Emby internal URL with the path `/web/index.html#!/startup/forgotpassword.html`.\n\nYou can customize this URL to point to a custom password reset page if you have one.\n\n            </TabItem>\n        </Tabs>\n    </TabItem>\n\n    <TabItem value=\"plex\" label=\"Plex\">\n\n### Plex Settings\n\n:::info\nTo set up Plex, you can either enter your details manually or select a server retrieved from [plex.tv](https://plex.tv/). Press the button to the right of the \"Server\" dropdown to retrieve available servers.\n\nDepending on your setup/configuration, you may need to enter your Plex server details manually in order to establish a connection from Seerr.\n:::\n\n#### Hostname or IP Address\n\nIf you have Seerr installed on the same network as Plex, you can set this to the local IP address of your Plex server. Otherwise, this should be set to a valid hostname (e.g., `plex.myawesomeserver.com`).\n\n#### Port\n\nThis value should be set to the port that your Plex server listens on. The default port that Plex uses is `32400`, but you may need to set this to `443` or some other value if your Plex server is hosted on a VPS or cloud provider.\n\n#### Use SSL\n\nEnable this setting to connect to Plex via HTTPS rather than HTTP. Note that self-signed certificates are _not_ supported.\n\n#### Web App URL (optional)\n\nThe **Play on Plex** buttons on media pages link to items on your Plex server. By default, these links use the [Plex Web App](https://support.plex.tv/articles/200288666-opening-plex-web-app/) hosted from plex.tv, but you can provide the URL to the web app on your Plex server and we'll use that instead!\n\nNote that you will need to enter the full path to the web app (e.g., `https://plex.myawesomeserver.com/web`).\n\n### Plex Libraries\n\nIn this section, simply select the libraries you would like Seerr to scan. Seerr will periodically check the selected libraries for available content to update the media status that is displayed to users.\n\nIf you do not see your Plex libraries listed, verify your Plex settings are correct and click the **Sync Libraries** button.\n\n### Manual Library Scan\n\nSeerr will perform a full scan of your Plex libraries once every 24 hours (recently added items are fetched more frequently). If this is your first time configuring Plex, a one-time full manual library scan is recommended!\n\n</TabItem>\n\n</Tabs>\n"
  },
  {
    "path": "docs/using-seerr/settings/notifications.mdx",
    "content": "---\ntitle: Notifications\ndescription: Configure notifications for your users.\nsidebar_position: 5\n---\n\n# Notifications\n\nPlease see the [Notifications](/using-seerr/notifications) page for more information.\n"
  },
  {
    "path": "docs/using-seerr/settings/services.md",
    "content": "---\ntitle: Services\ndescription: Configure your default services.\nsidebar_position: 4\n---\n\n# Services\n\n:::info\n**If you keep separate copies of non-4K and 4K content in your media libraries, you will need to set up multiple Radarr/Sonarr instances and link each of them to Seerr.**\n\nSeerr checks these linked servers to determine whether or not media has already been requested or is available, so two servers of each type are required _if you keep separate non-4K and 4K copies of media._\n\n**If you only maintain one copy of media, you can instead simply set up one server and set the \"Quality Profile\" setting on a per-request basis.**\n:::\n\n### Radarr/Sonarr Settings\n\n:::warning\n**Only v3 & V4 Radarr/Sonarr servers are supported!** If your Radarr/Sonarr server is still running v2, you will need to upgrade in order to add it to Seerr.\n::::\n\n#### Default Server\n\nAt least one server needs to be marked as \"Default\" in order for requests to be sent successfully to Radarr/Sonarr.\n\nIf you have separate 4K Radarr/Sonarr servers, you need to designate default 4K servers _in addition to_ default non-4K servers.\n\n#### 4K Server\n\nOnly select this option if you have separate non-4K and 4K servers. If you only have a single Radarr/Sonarr server, do _not_ check this box!\n\n#### Server Name\n\nEnter a friendly name for the Radarr/Sonarr server.\n\n#### Hostname or IP Address\n\nIf you have Seerr installed on the same network as Radarr/Sonarr, you can set this to the local IP address of your Radarr/Sonarr server. Otherwise, this should be set to a valid hostname (e.g., `radarr.myawesomeserver.com`).\n\n#### Port\n\nThis value should be set to the port that your Radarr/Sonarr server listens on. By default, Radarr uses port `7878` and Sonarr uses port `8989`, but you may need to set this to `443` or some other value if your Radarr/Sonarr server is hosted on a VPS or cloud provider.\n\n#### Use SSL\n\nEnable this setting to connect to Radarr/Sonarr via HTTPS rather than HTTP. Note that self-signed certificates are _not_ supported.\n\n#### API Key\n\nEnter your Radarr/Sonarr API key here. Do _not_ share these key publicly, as they can be used to gain administrator access to your Radarr/Sonarr servers!\n\nYou can locate the required API keys in Radarr/Sonarr in **Settings &rarr; General &rarr; Security**.\n\n#### URL Base\n\nIf you have configured a URL base for your Radarr/Sonarr server, you _must_ enter it here in order for Jellyeerr to connect to those services!\n\nYou can verify whether or not you have a URL base configured in your Radarr/Sonarr server at **Settings &rarr; General &rarr; Host**. (Note that a restart of your Radarr/Sonarr server is required if you modify this setting!)\n\n#### Profiles, Root Folder, Minimum Availability\n\nSelect the default settings you would like to use for all new requests. Note that all of these options are required, and that requests will fail if any of these are not configured!\n\n#### External URL (optional)\n\nIf the hostname or IP address you configured above is not accessible outside your network, you can set a different URL here. This \"external\" URL is used to add clickable links to your Radarr/Sonarr servers on media detail pages.\n\n#### Enable Scan (optional)\n\nEnable this setting if you would like to scan your Radarr/Sonarr server for existing media/request status. It is recommended that you enable this setting, so that users cannot submit requests for media which has already been requested or is already available.\n\n#### Enable Automatic Search (optional)\n\nEnable this setting to have Radarr/Sonarr to automatically search for media upon approval of a request.\n"
  },
  {
    "path": "docs/using-seerr/settings/users.md",
    "content": "---\ntitle: User Settings\ndescription: Configure global and default user settings.\nsidebar_position: 2\n---\n\n# Users\n\n## Enable Local Sign-In\n\nWhen enabled, users who have configured passwords will be allowed to sign in using their email address.\n\nWhen disabled, your mediaserver OAuth becomes the only sign-in option, and any \"local users\" you have created will not be able to sign in to Seerr.\n\nThis setting is **enabled** by default.\n\n## Enable Jellyfin/Emby/Plex Sign-In\n\nWhen enabled, users will be able to sign in to Seerr using their Jellyfin/Emby/Plex credentials, provided they have linked their media server accounts.\n\nWhen disabled, users will only be able to sign in using their email address. Users without a password set will not be able to sign in to Seerr.\n\nThis setting is **enabled** by default.\n\n## Enable New Jellyfin/Emby/Plex Sign-In\n\nWhen enabled, users with access to your media server will be able to sign in to Seerr even if they have not yet been imported. Users will be automatically assigned the permissions configured in the [Default Permissions](#default-permissions) setting upon first sign-in.\n\nThis setting is **enabled** by default.\n\n## Global Movie Request Limit & Global Series Request Limit\n\nSelect the request limits you would like granted to users.\n\nUnless an override is configured, users are granted these global request limits.\n\nNote 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.\n\n## Default Permissions\n\nSelect the permissions you would like assigned to new users to have by default upon account creation.\n\nIf [Enable New Jellyfin/Emby/Plex Sign-In](#enable-new-jellyfinembyplex-sign-in) is enabled, any user with access to your media server will be able to sign in to Seerr, and they will be granted the permissions you select here upon first sign-in.\n\nThis 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.\n"
  },
  {
    "path": "docs/using-seerr/users/_category_.json",
    "content": "{\n  \"label\": \"Users\",\n  \"position\": 2,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"title\": \"Users\",\n    \"description\": \"Configure your Seerr users\"\n  }\n}\n"
  },
  {
    "path": "docs/using-seerr/users/adding-users.mdx",
    "content": "---\ntitle: Adding Users\ndescription: Add users to your Seerr instance.\nsidebar_position: 2\n---\n\n# Adding Users\n\nThere are currently two methods to add users to Seerr: importing Mediaserver users and creating \"local users.\" All new users are created with the [default permissions](/using-seerr/settings/users#default-permissions) defined in **Settings &rarr; Users**.\n\n### Importing Mediaserver Users\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n<Tabs groupId=\"media-server-type\" queryString>\n  <TabItem value=\"jellyfin\" label=\"Jellyfin\">\n    Clicking the **Import Jellyfin Users** button on the **User List** page will fetch the list of users with access to the Jellyfin server and add them to Seerr automatically.\n\n    Importing Jellyfin users is not required, however. Any user with access to the Jellyfin server can log in to Seerr even if they have not been imported, and will be assigned the configured [default permissions](/using-seerr/settings/users#default-permissions) upon their first login.\n\n:::tip\nTo disable new Jellyfin sign-ins, navigate to **Settings &rarr; Users** and uncheck the [**Enable New Jellyfin Sign-In**](/using-seerr/settings/users#enable-new-jellyfinembyplex-sign-in) box.\n:::\n\n  </TabItem>\n  <TabItem value=\"emby\" label=\"Emby\">\n    Clicking the **Import Emby Users** button on the **User List** page will fetch the list of users with access to the Emby server and add them to Seerr automatically.\n\n    Importing Emby users is not required, however. Any user with access to the Emby server can log in to Seerr even if they have not been imported, and will be assigned the configured [default permissions](/using-seerr/settings/users#default-permissions) upon their first login.\n\n:::tip\nTo disable new Emby sign-ins, navigate to **Settings &rarr; Users** and uncheck the [**Enable New Emby Sign-In**](/using-seerr/settings/users#enable-new-jellyfinembyplex-sign-in) box.\n:::\n\n  </TabItem>\n\n  <TabItem value=\"plex\" label=\"Plex\">\n    Clicking the **Import Plex Users** 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 Seerr automatically.\n\n    Importing Plex users is not required, however. Any user with access to the Plex server can log in to Seerr even if they have not been imported, and will be assigned the configured [default permissions](/using-seerr/settings/users#default-permissions) upon their first login.\n\n:::tip\nTo disable new Plex sign-ins, navigate to **Settings &rarr; Users** and uncheck the [**Enable New Plex Sign-In**](/using-seerr/settings/users#enable-new-jellyfinembyplex-sign-in) box.\n:::\n\n  </TabItem>\n</Tabs>\n\n### Creating Local Users\n\nIf you would like to grant Seerr 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.\n\n#### Email Address\n\nEnter 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.\n\n#### Automatically Generate Password\n\nIf an [application URL](/using-seerr/settings/general#application-url) is set and [email notifications](/using-seerr/notifications/email) have been configured and enabled, Seerr can automatically generate a password for the new user.\n\n#### Password\n\nIf you would prefer to manually configure a password, enter a password here that is a minimum of 8 characters.\n"
  },
  {
    "path": "docs/using-seerr/users/deleting-users.md",
    "content": "---\ntitle: Deleting Users\ndescription: Delete users from Seerr.\nsidebar_position: 4\n---\n\n# Deleting Users\n\nWhen users are deleted, all of their data and request history is also cleared from the database.\n"
  },
  {
    "path": "docs/using-seerr/users/editing-users.md",
    "content": "---\ntitle: Editing Users\ndescription: Edit user settings and permissions.\nsidebar_position: 3\n---\n\n# Editing Users\n\nFrom the **User List**, you can click the **Edit** button to modify a particular user's settings.\n\nYou can also click the check boxes and click the **Bulk Edit** button to set user permissions for multiple users at once.\n\n## General\n\n### Display Name\n\nYou can optionally set a \"friendly name\" for any user. This name will be used in lieu of their media server (Jellyfin/Emby/Plex) username (for users imported from the media server) or their email address (for manually-created local users).\n\n### Email\n\n:::note\nThis field is read-only for users imported from Plex.\n:::\nYou can optionally set a proper email address for any user. This email address will be used for notifications, local sign-in and password resets.\n\nBy default, users imported from Jellyfin/Emby will use their media server username as their email address.\n\n:::warning\nYou cannot leave this field blank.\n:::\n\n### Display Language\n\nUsers can override the [global display language](/using-seerr/settings/general#display-language) to use Seerr in their preferred language.\n\n### Discover Region & Discover Language\n\nUsers can override the [global filter settings](/using-seerr/settings/general#discover-region-discover-language--streaming-region) to suit their own preferences.\n\n### Movie Request Limit & Series Request Limit\n\nYou 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.\n\nUnless an override is configured, users are granted the global request limits.\n\nNote 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.\n\nUsers are also unable to modify their own request limits.\n\n## Password\n\nAll \"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.\n\nPasswords must be a minimum of 8 characters long.\n\n## Notifications\n\nUsers can configure their personal notification settings here. Please see [Notifications](/using-seerr/notifications/) for details on configuring and enabling notifications.\n\n## Permissions\n\nUsers 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.\n"
  },
  {
    "path": "docs/using-seerr/users/owner.md",
    "content": "---\ntitle: Owner Account\ndescription: Your owner account is the primary account for managing Seerr.\nsidebar_position: 1\n---\n\n# Owner Account\n\nThe user account created during Seerr setup is the \"Owner\" account, which cannot be deleted or modified by other users. This account's credentials are used to authenticate with your media server and configure Seerr settings.\n\n:::note\nIn case of Jellyfin/Emby, the owner account is also used for API access to your media server. This account should have a valid authentication token for your media server.\n:::\n\n:::tip\nIf your authentication token is ever invalidated or changed, you can refresh it by re-authenticating with your media server.\n:::\n"
  },
  {
    "path": "eslint.config.mts",
    "content": "import js from '@eslint/js';\nimport nextPlugin from '@next/eslint-plugin-next';\nimport prettier from 'eslint-config-prettier';\nimport formatjs from 'eslint-plugin-formatjs';\nimport jsxA11y from 'eslint-plugin-jsx-a11y';\nimport noRelativeImportPaths from 'eslint-plugin-no-relative-import-paths';\nimport reactPlugin from 'eslint-plugin-react';\nimport reactHooks from 'eslint-plugin-react-hooks';\nimport { defineConfig, type Config } from 'eslint/config';\nimport globals from 'globals';\nimport tseslint from 'typescript-eslint';\n\ntype Plugin = NonNullable<Config['plugins']>[string];\n\nexport default defineConfig(\n  // Global ignores\n  {\n    ignores: ['node_modules/**', '.next/**'],\n  },\n  js.configs.recommended,\n  tseslint.configs.recommended,\n  jsxA11y.flatConfigs.recommended,\n  {\n    languageOptions: {\n      ecmaVersion: 2023,\n      sourceType: 'module',\n      parserOptions: {\n        ecmaFeatures: { jsx: true },\n      },\n      globals: {\n        ...globals.browser,\n        ...globals.node,\n        ...globals.jest,\n      },\n    },\n    settings: {\n      react: {\n        pragma: 'React',\n        version: '18.3',\n      },\n    },\n    plugins: {\n      react: reactPlugin,\n      'react-hooks': reactHooks as Plugin,\n      formatjs,\n      'no-relative-import-paths': noRelativeImportPaths,\n      '@next/next': nextPlugin,\n    },\n    rules: {\n      ...nextPlugin.configs.recommended.rules,\n\n      // TypeScript\n      '@typescript-eslint/no-explicit-any': 'warn',\n      '@typescript-eslint/no-use-before-define': 'off',\n      '@typescript-eslint/explicit-function-return-type': 'off',\n      '@typescript-eslint/no-unused-vars': 'error',\n      '@typescript-eslint/array-type': ['error', { default: 'array' }],\n      '@typescript-eslint/consistent-type-imports': [\n        'error',\n        { prefer: 'type-imports' },\n      ],\n\n      // React\n      'react/prop-types': 'off',\n      'react/self-closing-comp': 'error',\n\n      // jsx-a11y\n      'jsx-a11y/no-noninteractive-tabindex': 'off',\n      'jsx-a11y/anchor-is-valid': 'off',\n      'jsx-a11y/no-onchange': 'off',\n\n      // React Hooks\n      'react-hooks/rules-of-hooks': 'error',\n      'react-hooks/exhaustive-deps': 'warn',\n\n      // General\n      'arrow-parens': 'off',\n      'no-console': 'warn',\n      'no-unused-vars': 'off',\n\n      // Plugins\n      'formatjs/no-offset': 'error',\n      'no-relative-import-paths/no-relative-import-paths': [\n        'error',\n        { allowSameFolder: true },\n      ],\n    },\n  },\n  prettier,\n  {\n    linterOptions: {\n      reportUnusedDisableDirectives: true,\n    },\n  }\n);\n"
  },
  {
    "path": "gen-docs/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "gen-docs/README.md",
    "content": "# Seerr Documentation\n\nSeerr docs is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.\n\nSeerr docs will be available at [docs.seerr.dev](https://docs.seerr.dev).\n\n### Installation\n\n```\n$ pnpm install\n```\n\n### Local Development\n\n```\n$ pnpm start\n```\n\nThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.\n\n### Build\n\n```\n$ pnpm build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n"
  },
  {
    "path": "gen-docs/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "gen-docs/blog/2025-09-29-introducing-seerr-blog.md",
    "content": "---\ntitle: Welcome to the Seerr Blog\ndescription: The official Seerr blog for release notes, technical updates, and community news.\nslug: welcome\nauthors: [fallenbagel, gauthier-th]\ntags: [announcement, seerr, blog]\nimage: https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/gen-docs/static/img/logo_full.svg\nhide_table_of_contents: false\n---\n\nWe are pleased to introduce the official Seerr blog.\n\nThis space will serve as the central place for:\n\n- Release announcements\n- Updates on new features and improvements\n- Technical articles, such as details on our [**DNS caching package**](https://github.com/seerr/dns-caching) and other enhancements\n- Community-related news\n\n<!--truncate-->\n\nOur goal is to keep the community informed and provide deeper insights into the ongoing development of Seerr.\n\nThank you for being part of the Seerr project. More updates will follow soon.\n"
  },
  {
    "path": "gen-docs/blog/2026-02-10/seerr-release.md",
    "content": "---\ntitle: \"Seerr Release: Unifying Overseerr and Jellyseerr\"\ndescription: \"Overseerr and Jellyseerr are merging into a unified project: Seerr\"\nslug: seerr-release\nauthors: [seerr-team]\nimage: https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/gen-docs/static/img/logo_full.svg\nhide_table_of_contents: false\n---\n\nWe're excited to announce a major update: the Jellyseerr and Overseerr teams are officially merging into a single team called **Seerr**. This unification marks an important step forward as we bring our efforts together under one banner.\n\nFor users, this means one shared codebase combining all existing Overseerr functionalities with the latest Jellyseerr features, along with Jellyfin and Emby support, allowing us to deliver updates more efficiently and keep the project moving forward.\n\nPlease check how to migrate to Seerr in our [migration guide](https://docs.seerr.dev/migration-guide) and stay tuned for more updates on the project!\n\n<!--truncate-->\n\n## What's new in Seerr for Overseerr users\n\nSeerr brings several features that were previously available in Jellyseerr but missing from Overseerr. These additions improve flexibility, performance, and overall control for admins and power users:\n\n* **Alternative media solution:** Added support for Jellyfin and Emby as alternatives to Plex. Only one integration can be used at a time.\n* **PostgreSQL support**: In addition to SQLite, you can now opt in to using a PostgreSQL database.\n* **Blocklist for movies, series, and tags**: Allows permitted users to hide movies, series, or tags from regular users.\n* **Override rules**: Adjust default request settings based on conditions such as user, tag, or other criteria.\n* **TVDB metadata**: Option to use TheTVDB metadata for series (as in Sonarr) instead of TMDB.\n* **DNS caching**: Reduces lookup times and external requests, especially useful when using systems like Pi-Hole/Adguard Home.\n* **Helm chart included**: Enables easier installation and maintenance in Kubernetes environments.\n* **ntfy.sh notifications**: Support for sending notifications via ntfy.sh.\n* **Disable special seasons:** Adds a setting to prevent special seasons from being shown or requested.\n* **New languages**: Turkish and Basque\n\n## What's new since the previous Jellyseerr release\n\nThis release also brings several important improvements and long-requested features, including **TheTVDB metadata support**, **DNS caching**, and **dynamic webhook placeholders**, along with a few quality-of-life improvements for developers and users alike.\n\n### PNPM v10 Upgrade\n\nWe're updating Seerr to **PNPM v10** to keep up-to-date development tools. If you are building Seerr from source or if you contribute to Seerr, you'll need to **update your local PNPM installation** before working on the project.\n\nThis doesn't concern you if you're using Docker.\n\nTo update, run the following command:\n`pnpm self-update`\n\nAfter updating, verify your version with:\n`pnpm -v`\n\nYou should see version **10.x.x**.\n\n### TVDB Metadata Provider (Experimental)\n\nWe're excited to introduce support for **TheTVDB** as a new metadata provider!\nPreviously, Seerr relied solely on **TMDB** for movie and TV show information, which sometimes led to discrepancies in season and episode numbering when working with **Sonarr**, since Sonarr uses **TheTVDB** as its metadata source.\n\nWith this new integration, Seerr can now use **the same data source as Sonarr** for series and anime, ensuring consistent and accurate season and episode information across both platforms.\n\nYou can try this new experimental feature in the new “Metadata Providers” tab of the settings page:\n\n![Metadata Providers](./metadata-providers.png)\n\n### DNS Caching (Experimental)\n\nBy default, Node.js doesn't cache any DNS requests. Our DNS cache manager addresses the problems caused by extremely high DNS query rates, particularly for large Jellyfin libraries as each HTTP request was also resulting in another DNS request. Therefore, by caching these DNS lookups, **Seerr will now reduce stress on DNS servers** and avoid rate-limiting or blocks encountered with services like **Pi-Hole**/**Adguard Home**.\n\nWe will post another blog post soon on all the issues we encountered with DNS caching in Node.js.\n\nYou can enable this by checking the “DNS Cache” setting in the network tabs of the Seerr settings:\n\n![DNS Cache](./dns-cache.png)\n\n### AniDB for Jellyfin Libraries\n\nThis new version also brings additional metadata to Jellyfin-managed collections. When there's no provider ID from TMDB or TVDB, Seerr will automatically **fall back on AniDB**, expanding coverage for lesser-known or region-specific anime.\n\n### Dynamic Placeholders in Webhook URLs\n\nWebhook notifications are now more powerful and adaptable with **dynamic placeholder support in webhook URLs**. This allows Seerr to automatically replace placeholders in the webhook URL with real values at runtime.\n\nFor example, you can include the requester's username directly in your webhook URL to better integrate with third-party services or user-specific endpoints.\n\nThis feature can be enabled from the **Notifications** settings page, where available placeholders are listed for reference. It's currently marked as **experimental**, and we welcome community feedback to help refine and expand support for additional placeholders in future releases.\n\n### Optional Images in Notifications\n\nAnother small feature: **images in notifications are now optional** (but still enabled by default). Previous versions always included images in notifications, which could lead to broken links or failed requests if images were missing or unavailable.\n\n### Security improvement\n\nSome outdated dependencies have been updated (some work is still in progress). Helm charts and containers are now cryptographically signed and can be verified and enforced client-side. Containers now run as rootless. Workflows have been completely reworked to minimize third-party actions. Permissions have been strengthened, and actions are now pinned to specific hashes for better traceability. The release process has been updated to remove many outdated and plugin dependencies, replacing them with more standard industry solutions.\n\n:::important\n## Note for PostgreSQL users (optional)\n\nIf you're migrating Postgres from version 17 to 18 in Docker, note that the data mount point has changed. Instead of using `/var/lib/postgresql/data`, the correct mount path is now `/var/lib/postgresql`. This update of the mount point is required to ensure the container functions correctly after the upgrade.\n:::\n\n## Conclusion\n\nSeerr is built and maintained by dedicated volunteer contributors, whose skills and commitment make it all possible. Many thanks to everyone who contributed to this version:\n\n* [0xsysr3ll](https://github.com/0xSysR3ll)\n* [ale183](https://github.com/ale183)\n* [Brandon Cohen](https://github.com/OwsleyJr)\n* [Disparate2761](https://github.com/Disparate2761)\n* [fallenbagel](https://github.com/fallenbagel)\n* [Gauthier](https://github.com/gauthier-th)\n* [Gauvain](https://github.com/Gauvino)\n* [Georgy](https://github.com/tarasverq)\n* [Ishan Jain](https://github.com/ishanjain28)\n* [James Kruger](https://github.com/theGunner295)\n* [Joe Harrison](https://github.com/sudo-kraken)\n* [J. Winters-Brown](https://github.com/ofgrenudo)\n* [Ludovic Ortega](https://github.com/M0NsTeRRR)\n* [RolliePollie18](https://github.com/RolliePollie18)\n* [Ryan Cohen](https://github.com/sct)\n* [salty](https://github.com/saltydk)\n* [samohtxotom](https://github.com/samohtxotom)\n* [Sergii Bogomolov](https://github.com/sbogomolov)\n* [Someone](https://github.com/InterN0te)\n* [TacoCake](https://github.com/TacoCake)\n* [Terry Sposato](https://github.com/tsposato)\n* [TheCatLady](https://github.com/TheCatLady)\n* [Thibaut Noah](https://github.com/tirrorex)\n* [THOMAS B](https://github.com/TOomaAh)\n\nKeep an eye on our blog for in-depth looks at our work and upcoming releases!\n"
  },
  {
    "path": "gen-docs/blog/2026-02-28-seerr-security-fix-release.md",
    "content": "---\ntitle: \"Seerr v3.1.0: Critical Security Release\"\ndescription: \"Seerr v3.1.0 addresses three CVEs, including a high-priority vulnerability affecting Plex-configured instances. Upgrade immediately.\"\nslug: seerr-3-1-0-security-release\nauthors: [seerr-team]\nimage: https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/gen-docs/static/img/logo_full.svg\nhide_table_of_contents: false\n---\n\nWe are releasing **Seerr v3.1.0**, a security-focused update that addresses three CVEs, including a high-priority vulnerability affecting instances configured with Plex Media Server. **We strongly recommend upgrading as soon as possible.**\n\nThis release also includes a number of bug fixes and marks the end of our post-merger feature freeze. New features will be resuming in future updates.\n\n<!--truncate-->\n\n## Security Vulnerabilities\n\nThis release patches three newly identified CVEs. If you are running a Plex-configured instance of Seerr, **one of these vulnerabilities is high priority and poses a significant risk**, please upgrade immediately.\n\n### [CVE-2026-27707](https://github.com/seerr-team/seerr/security/advisories/GHSA-rc4w-7m3r-c2f7) — Unauthenticated Account Registration via Jellyfin Endpoint (High)\n\nOn instances configured to use Plex as the media server, an unauthenticated attacker could register an account by abusing the Jellyfin authentication endpoint. This could allow unauthorized users to gain access to your Seerr instance without valid Plex credentials.\n\n### [CVE-2026-27793](https://github.com/seerr-team/seerr/security/advisories/GHSA-f7xw-jcqr-57hp) — Broken Object-Level Authorization in User Profile Endpoint (Medium)\n\nA broken object-level authorization vulnerability in the user profile endpoint could allow an authenticated user to access another user's profile data, including third-party notification credentials such as webhook URLs, Telegram tokens, and similar sensitive configuration.\n\n### [CVE-2026-27792](https://github.com/seerr-team/seerr/security/advisories/GHSA-gx3h-3jg5-q65f) — Missing Authentication on Push Subscription Endpoints (Medium)\n\nThe push subscription endpoints lacked proper authentication checks, allowing unauthenticated requests to interact with subscription management functionality.\n\n---\n\nPlease review the full security advisories linked above for technical details, impact assessment, and mitigation steps.\n\n## Bug Fixes\n\nAlongside the security patches, this release ships a number of bug fixes:\n\n- ***(helm)*** Add `\"v\"` as prefix for `appVersion` tag\n- ***(jellyfin-scanner)*** Include unmatched seasons in processable seasons\n- ***(link-account)*** Fix error-message override\n- ***(plex-scanner)*** Add TVDb to TMDB fallback in Plex scanner\n- ***(radarr)*** Trigger search for existing monitored movies without files\n- ***(servarr)*** Increase default API timeout from 5000ms to 10000ms\n- ***(sonarr)*** Use configured metadata provider for season filtering\n- ***(watch-data)*** Use sentinel values to avoid invalid SQL syntax\n- ***(watchlist-sync)*** Correct permission typo for TV auto requests\n- Preserve blocklist on media deletion & optimise watchlist-sync\n\n## New Contributors\n\nMany thanks to those making their first contribution to Seerr in this release:\n\n* [@caillou](https://github.com/caillou)\n* [@Kenshin9977](https://github.com/Kenshin9977)\n* [@MagicLegend](https://github.com/MagicLegend)\n* [@wiiaam](https://github.com/wiiaam)\n* [@mjonkus](https://github.com/mjonkus)\n* [@nova-api](https://github.com/nova-api)\n* [@mreid-tt](https://github.com/mreid-tt)\n* [@DataBitz](https://github.com/DataBitz)\n* [@Hyperion2220](https://github.com/Hyperion2220)\n* [@blassley](https://github.com/blassley)\n* [@JanKleine](https://github.com/JanKleine)\n* [@koiralasandesh](https://github.com/koiralasandesh)\n\n## What's Next\n\nNow that the post-merger feature freeze has ended, the team is resuming active feature development. Stay tuned to our blog for upcoming releases and in-depth looks at what we're building next.\n\nIn the meantime, please upgrade to **v3.1.0** right away, especially if you are using a Plex Media Server configuration. See our [migration guide](https://docs.seerr.dev/migration-guide) if you need help upgrading from Overseerr/Jellyseerr."
  },
  {
    "path": "gen-docs/blog/authors.yml",
    "content": "fallenbagel:\n  name: Fallenbagel\n  page: true\n  title: Developer & Maintainer of Seerr\n  description: Core Maintainer & Developer of Seerr | Full-Stack Software Engineer | MSc Software Engineering Student.\n  url: https://github.com/fallenbagel\n  image_url: https://github.com/fallenbagel.png\n  email: hello@fallenbagel.com\n  socials:\n    github: fallenbagel\n\ngauthier-th:\n  name: Gauthier\n  page: true\n  title: Developer & Maintainer of Seerr\n  description: Core Maintainer & Developer of Seerr | PhD Student in AI at ICB, Dijon\n  url: https://gauthierth.fr\n  image_url: https://github.com/gauthier-th.png\n  email: mail@gauthierth.fr\n  socials:\n    github: gauthier-th\n\nseerr-team:\n  name: Seerr Team\n  title: The team behind Seerr, formerly known as the Jellyseerr and Overseerr teams.\n  url: https://seerr.dev\n  image_url: https://github.com/seerr-team.png\n  socials:\n    github: seerr-team\n"
  },
  {
    "path": "gen-docs/docusaurus.config.ts",
    "content": "import type * as Preset from '@docusaurus/preset-classic';\nimport type { Config } from '@docusaurus/types';\nimport { themes as prismThemes } from 'prism-react-renderer';\n\nconst config: Config = {\n  title: 'Seerr',\n  tagline: 'One Stop Solution for all your media request needs',\n  favicon: 'img/favicon.ico',\n\n  url: 'https://docs.seerr.dev',\n  baseUrl: '/',\n  trailingSlash: false,\n\n  organizationName: 'seerr-team',\n  projectName: 'seerr',\n  deploymentBranch: 'gh-pages',\n\n  onBrokenLinks: 'throw',\n\n  markdown: {\n    hooks: {\n      onBrokenMarkdownLinks: 'warn',\n    },\n  },\n\n  i18n: {\n    defaultLocale: 'en',\n    locales: ['en'],\n  },\n\n  presets: [\n    [\n      'classic',\n      {\n        docs: {\n          sidebarPath: './sidebars.ts',\n          routeBasePath: '/',\n          path: '../docs',\n          editUrl: 'https://github.com/seerr-team/seerr/edit/develop/docs/',\n        },\n        pages: false,\n        theme: {\n          customCss: './src/css/custom.css',\n        },\n      } satisfies Preset.Options,\n    ],\n  ],\n\n  themes: [\n    [\n      '@easyops-cn/docusaurus-search-local',\n      /**  @type {import(\"@easyops-cn/docusaurus-search-local\").PluginOptions}  */\n      {\n        hashed: true,\n        indexBlog: false,\n        docsDir: '../docs',\n        docsRouteBasePath: '/',\n        explicitSearchResultPath: true,\n      },\n    ],\n  ],\n\n  themeConfig: {\n    colorMode: {\n      defaultMode: 'dark',\n      disableSwitch: true,\n      respectPrefersColorScheme: false,\n    },\n    navbar: {\n      logo: {\n        alt: 'Seerr',\n        src: 'img/logo_full.svg',\n      },\n      items: [\n        {\n          to: 'blog',\n          label: 'Blog',\n          position: 'right',\n        },\n        {\n          href: 'https://discord.gg/seerr',\n          label: 'Discord',\n          position: 'right',\n        },\n        {\n          href: 'https://github.com/seerr-team/seerr',\n          label: 'GitHub',\n          position: 'right',\n        },\n      ],\n    },\n    footer: {\n      style: 'dark',\n      links: [\n        {\n          title: 'Docs',\n          items: [\n            {\n              label: 'Documentation',\n              to: '/',\n            },\n          ],\n        },\n        {\n          title: 'Project',\n          items: [\n            {\n              label: 'Blog',\n              to: '/blog',\n            },\n            {\n              label: 'GitHub',\n              href: 'https://github.com/seerr-team/seerr',\n            },\n          ],\n        },\n        {\n          title: 'Community',\n          items: [\n            {\n              label: 'Discord',\n              href: 'https://discord.gg/seerr',\n            },\n            {\n              label: 'Github Discussions',\n              href: 'https://github.com/seerr-team/seerr/discussions',\n            },\n          ],\n        },\n      ],\n      copyright: `Copyright © ${new Date().getFullYear()} Seerr. Built with Docusaurus.`,\n    },\n    prism: {\n      theme: prismThemes.shadesOfPurple,\n      darkTheme: prismThemes.shadesOfPurple,\n      additionalLanguages: [\n        'bash',\n        'powershell',\n        'yaml',\n        'nix',\n        'nginx',\n        'batch',\n      ],\n    },\n  } satisfies Preset.ThemeConfig,\n};\n\nexport default config;\n"
  },
  {
    "path": "gen-docs/package.json",
    "content": "{\n  \"name\": \"gen-docs\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"packageManager\": \"pnpm@10.17.1\",\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\",\n    \"typecheck\": \"tsc\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"3.9.1\",\n    \"@docusaurus/preset-classic\": \"3.9.1\",\n    \"@easyops-cn/docusaurus-search-local\": \"^0.52.1\",\n    \"@mdx-js/react\": \"^3.0.0\",\n    \"clsx\": \"^2.0.0\",\n    \"prism-react-renderer\": \"^2.3.0\",\n    \"react\": \"^18.0.0\",\n    \"react-dom\": \"^18.0.0\",\n    \"tailwindcss\": \"^3.4.4\"\n  },\n  \"devDependencies\": {\n    \"@docusaurus/module-type-aliases\": \"3.9.1\",\n    \"@docusaurus/tsconfig\": \"3.9.1\",\n    \"@docusaurus/types\": \"3.9.1\",\n    \"typescript\": \"~5.2.2\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 3 chrome version\",\n      \"last 3 firefox version\",\n      \"last 5 safari version\"\n    ]\n  },\n  \"engines\": {\n    \"node\": \">=22.0\"\n  }\n}\n"
  },
  {
    "path": "gen-docs/sidebars.ts",
    "content": "import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';\n\n/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n\n The sidebars can be generated from the filesystem, or explicitly defined here.\n\n Create as many sidebars as you want.\n */\nconst sidebars: SidebarsConfig = {\n  // By default, Docusaurus generates a sidebar from the docs folder structure\n  documentationSidebar: [{ type: 'autogenerated', dirName: '.' }],\n\n  // But you can create a sidebar manually\n  /*\n  tutorialSidebar: [\n    'intro',\n    'hello',\n    {\n      type: 'category',\n      label: 'Tutorial',\n      items: ['tutorial-basics/create-a-document'],\n    },\n  ],\n   */\n};\n\nexport default sidebars;\n"
  },
  {
    "path": "gen-docs/src/components/SeerrVersion/index.tsx",
    "content": "import { useEffect, useState } from 'react';\n\nexport const SeerrVersion = () => {\n  const [version, setVersion] = useState<string | null>('0.0.0');\n\n  useEffect(() => {\n    async function fetchVersion() {\n      try {\n        const response = await fetch(\n          'https://raw.githubusercontent.com/seerr-team/seerr/main/package.json'\n        );\n\n        const data = await response.json();\n\n        setVersion(data.version);\n        console.log(data.version);\n      } catch (error) {\n        console.error('Failed to fetch version', error);\n        setVersion('Error fetching version');\n      }\n    }\n    fetchVersion();\n  }, []);\n\n  return version;\n};\n\nexport const NixpkgVersion = () => {\n  const [versions, setVersions] = useState(null);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState(null);\n\n  useEffect(() => {\n    const fetchVersion = async () => {\n      try {\n        const unstableUrl =\n          'https://raw.githubusercontent.com/NixOS/nixpkgs/refs/heads/nixos-unstable/pkgs/by-name/je/jellyseerr/package.nix';\n        const stableUrl =\n          'https://raw.githubusercontent.com/NixOS/nixpkgs/refs/heads/nixos-25.05/pkgs/by-name/je/jellyseerr/package.nix';\n\n        const [unstableResponse, stableResponse] = await Promise.all([\n          fetch(unstableUrl),\n          fetch(stableUrl),\n        ]);\n\n        const unstableData = await unstableResponse.text();\n        const stableData = await stableResponse.text();\n\n        const versionRegex = /version\\s*=\\s*\"([^\"]+)\"/;\n\n        const unstableMatch = unstableData.match(versionRegex);\n        const stableMatch = stableData.match(versionRegex);\n\n        const unstableVersion =\n          unstableMatch && unstableMatch[1] ? unstableMatch[1] : '0.0.0';\n        const stableVersion =\n          stableMatch && stableMatch[1] ? stableMatch[1] : '0.0.0';\n\n        setVersions({ unstable: unstableVersion, stable: stableVersion });\n        setLoading(false);\n      } catch (err) {\n        setError(err.message);\n        setLoading(false);\n      }\n    };\n\n    fetchVersion();\n  }, []);\n\n  if (loading) {\n    return 'Loading...';\n  }\n\n  if (error) {\n    return { error };\n  }\n\n  return versions;\n};\n"
  },
  {
    "path": "gen-docs/src/css/custom.css",
    "content": "/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n/* :root {\n  --ifm-color-scheme: dark;\n  --ifm-background-color: #151d2c;\n  --ifm-navbar-background-color: #151d2c;\n  --ifm-color-content: #fff;\n  --ifm-color-content-secondary: #888f9b;\n  --ifm-color-primary: var(--ifm-color-content);\n  --ifm-hover-overlay: #374151;\n  --ifm-menu-color-background-active: #793ae8;\n  --ifm-color-primary-dark: #1f2b7f;\n  --ifm-color-primary-darker: #16206b;\n  --ifm-color-primary-darkest: #0d1456;\n  --ifm-color-primary-light: #9066e3;\n  --ifm-color-primary-lighter: #a37ff0;\n  --ifm-color-primary-lightest: #b8a3f9;\n  --ifm-code-font-size: 95%;\n  --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);\n} */\n\n/* For readability concerns, you should choose a lighter palette in dark mode. */\n[data-theme='dark'] {\n  --ifm-color-scheme: dark;\n  --ifm-background-color: #151d2c !important;\n  --ifm-navbar-background-color: #151d2c;\n  --ifm-color-content: #fff;\n  --ifm-color-content-secondary: #888f9b;\n  --ifm-color-primary: var(--ifm-color-content);\n  --ifm-hover-overlay: #374151;\n  /* --ifm-menu-color-background-active: #793ae8; */\n  /* --ifm-menu-color-background-active: linear-gradient(\n    90deg,\n    #793ae8 0%,\n    #ff8c00 100%\n  ); */\n  --ifm-color-primary-dark: #1f2b7f;\n  --ifm-color-primary-darker: #16206b;\n  --ifm-color-primary-darkest: #0d1456;\n  --ifm-color-primary-light: #9066e3;\n  --ifm-color-primary-lighter: #a37ff0;\n  --ifm-color-primary-lightest: #b8a3f9;\n  --ifm-code-font-size: 95%;\n  --search-local-modal-background: #121a29;\n  /* --search-local-highlight-color: var(--ifm-hover-overlay); */\n  --search-local-highlight-color: #6366f1;\n  --search-local-hit-color: #fff;\n  --search-local-hit-background: #2d3748;\n  --search-local-hit-active-color: var(--ifm-color-primary);\n  --ifm-input-border-color: #ccc; /* Default border color */\n  --ifm-input-border-focus-color: red; /* Border color when focused */\n  --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);\n  --ifm-navbar-search-input-icon: url('data:image/svg+xml;utf8,<svg fill=\"%23fff\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" height=\"16px\" width=\"16px\"><path d=\"M6.02945,10.20327a4.17382,4.17382,0,1,1,4.17382-4.17382A4.15609,4.15609,0,0,1,6.02945,10.20327Zm9.69195,4.2199L10.8989,9.59979A5.88021,5.88021,0,0,0,12.058,6.02856,6.00467,6.00467,0,1,0,9.59979,10.8989l4.82338,4.82338a.89729.89729,0,0,0,1.29912,0,.89749.89749,0,0,0-.00087-1.29909Z\" /></svg>');\n}\n\n.table-of-contents__link--active,\na:not(\n  .card,\n  .menu__link,\n  .menu__link--sublist,\n  .menu__link--sublist-item,\n  .table-of-contents__link\n) {\n  /* color: #793ae8; */\n  color: #6366f1;\n}\n\n.card {\n  background-color: rgb(31 41 55/0.9);\n}\n\n.theme-admonition a {\n  color: #fff;\n}\n\n.menu__link--active,\n.menu__list-item-collapsible--active {\n  background: linear-gradient(0deg, #8238e9 0%, #5d42e6 100%);\n}\n\n/* .tabs__item--active {\n  background: linear-gradient(0deg, #8238e9 0%, #5d42e6 100%);\n} */\n\n.tabs__item {\n  border-bottom: 1px solid #fff;\n  border-bottom-left-radius: 0;\n  border-bottom-right-radius: 0;\n  padding: 0.5rem 1rem;\n}\n\n.tabs__item--active {\n  /* background: rgba(255, 255, 255, 0.1); */\n  color: #a37ff0;\n  border-bottom: 3px solid #a37ff0;\n}\n\n.footer {\n  background: var(--ifm-navbar-background-color);\n  border-top: 1px solid #2d3748;\n}\n"
  },
  {
    "path": "gen-docs/static/.nojekyll",
    "content": ""
  },
  {
    "path": "gen-docs/static/CNAME",
    "content": "docs.seerr.dev\n"
  },
  {
    "path": "gen-docs/tailwind.config.js",
    "content": "module.exports = {\n  content: ['./src/components/**/*.{ts,tsx}'],\n  theme: {\n    extend: {},\n  },\n  plugins: [],\n};\n"
  },
  {
    "path": "gen-docs/tsconfig.json",
    "content": "{\n  // This file is not used in compilation. It is here just for a nice editor experience.\n  \"extends\": \"@docusaurus/tsconfig\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\"\n  }\n}\n"
  },
  {
    "path": "next-env.d.ts",
    "content": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.\n"
  },
  {
    "path": "next.config.js",
    "content": "/**\n * @type {import('next').NextConfig}\n */\nmodule.exports = {\n  env: {\n    commitTag: process.env.COMMIT_TAG || 'local',\n  },\n  images: {\n    remotePatterns: [\n      { hostname: 'gravatar.com' },\n      { hostname: 'image.tmdb.org' },\n      { hostname: 'artworks.thetvdb.com' },\n      { hostname: 'plex.tv' },\n    ],\n  },\n  webpack(config) {\n    config.module.rules.push({\n      test: /\\.svg$/,\n      issuer: /\\.(js|ts)x?$/,\n      use: ['@svgr/webpack'],\n    });\n\n    return config;\n  },\n  experimental: {\n    scrollRestoration: true,\n    largePageDataBytes: 512 * 1000,\n  },\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"seerr\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"packageManager\": \"pnpm@10.24.0\",\n  \"scripts\": {\n    \"preinstall\": \"npx only-allow pnpm\",\n    \"postinstall\": \"next telemetry disable\",\n    \"dev\": \"nodemon -e ts --watch server --watch seerr-api.yml -e .json,.ts,.yml -x ts-node -r tsconfig-paths/register --files --project server/tsconfig.json server/index.ts\",\n    \"build:server\": \"tsc --project server/tsconfig.json && copyfiles -u 2 server/templates/**/*.{html,pug} dist/templates && tsc-alias -p server/tsconfig.json\",\n    \"build:next\": \"next build\",\n    \"build\": \"pnpm build:next && pnpm build:server\",\n    \"lint\": \"eslint \\\"./server/**/*.{ts,tsx}\\\" \\\"./src/**/*.{ts,tsx}\\\" --cache\",\n    \"lintfix\": \"eslint \\\"./server/**/*.{ts,tsx}\\\" \\\"./src/**/*.{ts,tsx}\\\" --fix\",\n    \"test\": \"node server/test/index.mts\",\n    \"start\": \"NODE_ENV=production node dist/index.js\",\n    \"i18n:extract\": \"ts-node --project server/tsconfig.json src/i18n/extractMessages.ts\",\n    \"migration:generate\": \"ts-node -r tsconfig-paths/register --project server/tsconfig.json ./node_modules/typeorm/cli.js migration:generate -d server/datasource.ts\",\n    \"migration:create\": \"ts-node -r tsconfig-paths/register --project server/tsconfig.json ./node_modules/typeorm/cli.js migration:create -d server/datasource.ts\",\n    \"migration:run\": \"ts-node -r tsconfig-paths/register --project server/tsconfig.json ./node_modules/typeorm/cli.js migration:run -d server/datasource.ts\",\n    \"format\": \"prettier --log-level warn --write --cache .\",\n    \"format:check\": \"prettier --check --cache .\",\n    \"typecheck\": \"pnpm typecheck:server && pnpm typecheck:client\",\n    \"typecheck:server\": \"tsc --project server/tsconfig.json --noEmit\",\n    \"typecheck:client\": \"tsc --noEmit\",\n    \"prepare\": \"node bin/prepare.js\",\n    \"cypress:open\": \"cypress open\",\n    \"cypress:prepare\": \"ts-node -r tsconfig-paths/register --files --project server/tsconfig.json server/scripts/prepareTestDb.ts\",\n    \"cypress:build\": \"pnpm build && pnpm cypress:prepare\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/seerr-team/seerr.git\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@dr.pogodin/csurf\": \"^1.16.6\",\n    \"@fontsource-variable/inter\": \"^5.2.8\",\n    \"@formatjs/intl-displaynames\": \"6.8.13\",\n    \"@formatjs/intl-locale\": \"3.1.1\",\n    \"@formatjs/intl-pluralrules\": \"5.4.6\",\n    \"@formatjs/intl-utils\": \"3.8.4\",\n    \"@headlessui/react\": \"1.7.12\",\n    \"@heroicons/react\": \"2.2.0\",\n    \"@seerr-team/react-tailwindcss-datepicker\": \"^1.3.4\",\n    \"@supercharge/request-ip\": \"1.2.0\",\n    \"@svgr/webpack\": \"8.1.0\",\n    \"@tanem/react-nprogress\": \"5.0.56\",\n    \"@types/ua-parser-js\": \"^0.7.36\",\n    \"@types/wink-jaro-distance\": \"^2.0.2\",\n    \"ace-builds\": \"1.43.4\",\n    \"axios\": \"1.13.3\",\n    \"axios-rate-limit\": \"1.4.0\",\n    \"bcrypt\": \"6.0.0\",\n    \"bowser\": \"2.13.1\",\n    \"connect-typeorm\": \"1.1.4\",\n    \"cookie-parser\": \"1.4.7\",\n    \"copy-to-clipboard\": \"3.3.3\",\n    \"country-flag-icons\": \"1.6.4\",\n    \"cronstrue\": \"2.23.0\",\n    \"date-fns\": \"2.29.3\",\n    \"dns-caching\": \"^0.2.7\",\n    \"email-templates\": \"12.0.3\",\n    \"express\": \"4.21.2\",\n    \"express-openapi-validator\": \"4.13.8\",\n    \"express-rate-limit\": \"6.7.0\",\n    \"express-session\": \"1.18.2\",\n    \"formik\": \"^2.4.9\",\n    \"gravatar-url\": \"3.1.0\",\n    \"http-proxy-agent\": \"^7.0.2\",\n    \"https-proxy-agent\": \"^7.0.6\",\n    \"lodash\": \"4.17.23\",\n    \"mime\": \"3\",\n    \"next\": \"^14.2.35\",\n    \"node-cache\": \"5.1.2\",\n    \"node-gyp\": \"9.3.1\",\n    \"node-schedule\": \"2.1.1\",\n    \"nodemailer\": \"7.0.12\",\n    \"openpgp\": \"6.3.0\",\n    \"pg\": \"8.17.2\",\n    \"pug\": \"3.0.3\",\n    \"react\": \"^18.3.1\",\n    \"react-ace\": \"10.1.0\",\n    \"react-animate-height\": \"2.1.2\",\n    \"react-aria\": \"3.44.0\",\n    \"react-dom\": \"^18.3.1\",\n    \"react-intersection-observer\": \"9.4.3\",\n    \"react-intl\": \"^6.6.8\",\n    \"react-markdown\": \"8.0.5\",\n    \"react-popper-tooltip\": \"4.4.2\",\n    \"react-select\": \"5.10.2\",\n    \"react-spring\": \"9.7.1\",\n    \"react-toast-notifications\": \"2.5.1\",\n    \"react-transition-group\": \"^4.4.5\",\n    \"react-truncate-markup\": \"5.1.2\",\n    \"react-use-clipboard\": \"1.0.9\",\n    \"reflect-metadata\": \"0.1.13\",\n    \"secure-random-password\": \"0.2.3\",\n    \"semver\": \"7.7.3\",\n    \"sharp\": \"^0.33.4\",\n    \"sqlite3\": \"5.1.7\",\n    \"swagger-ui-express\": \"4.6.2\",\n    \"swr\": \"2.3.8\",\n    \"tailwind-merge\": \"^2.6.0\",\n    \"typeorm\": \"0.3.28\",\n    \"ua-parser-js\": \"^1.0.35\",\n    \"undici\": \"^7.18.2\",\n    \"validator\": \"^13.15.23\",\n    \"web-push\": \"3.6.7\",\n    \"wink-jaro-distance\": \"^2.0.0\",\n    \"winston\": \"3.19.0\",\n    \"winston-daily-rotate-file\": \"4.7.1\",\n    \"xml2js\": \"0.5.0\",\n    \"yamljs\": \"0.3.0\",\n    \"yup\": \"0.32.11\",\n    \"zod\": \"4.3.6\"\n  },\n  \"devDependencies\": {\n    \"@commitlint/cli\": \"17.4.4\",\n    \"@commitlint/config-conventional\": \"17.4.4\",\n    \"@eslint/js\": \"9.39.3\",\n    \"@next/eslint-plugin-next\": \"^16.1.6\",\n    \"@tailwindcss/aspect-ratio\": \"^0.4.2\",\n    \"@tailwindcss/forms\": \"^0.5.10\",\n    \"@tailwindcss/typography\": \"^0.5.16\",\n    \"@types/bcrypt\": \"6.0.0\",\n    \"@types/cookie-parser\": \"1.4.10\",\n    \"@types/country-flag-icons\": \"1.2.2\",\n    \"@types/csurf\": \"1.11.5\",\n    \"@types/email-templates\": \"10.0.4\",\n    \"@types/eslint-plugin-jsx-a11y\": \"^6.10.1\",\n    \"@types/express\": \"4.17.17\",\n    \"@types/express-session\": \"1.18.2\",\n    \"@types/lodash\": \"4.17.21\",\n    \"@types/mime\": \"3\",\n    \"@types/node\": \"22.10.5\",\n    \"@types/node-schedule\": \"2.1.8\",\n    \"@types/nodemailer\": \"7\",\n    \"@types/react\": \"^18.3.3\",\n    \"@types/react-dom\": \"^18.3.0\",\n    \"@types/react-transition-group\": \"4.4.12\",\n    \"@types/secure-random-password\": \"0.2.1\",\n    \"@types/semver\": \"7.7.1\",\n    \"@types/supertest\": \"^6.0.3\",\n    \"@types/swagger-ui-express\": \"4.1.8\",\n    \"@types/validator\": \"^13.15.10\",\n    \"@types/web-push\": \"3.6.4\",\n    \"@types/xml2js\": \"0.4.14\",\n    \"@types/yamljs\": \"0.2.31\",\n    \"@types/yup\": \"0.29.14\",\n    \"autoprefixer\": \"^10.4.23\",\n    \"baseline-browser-mapping\": \"^2.8.32\",\n    \"commander\": \"^14.0.3\",\n    \"commitizen\": \"4.3.1\",\n    \"copyfiles\": \"2.4.1\",\n    \"cy-mobile-commands\": \"0.3.0\",\n    \"cypress\": \"14.5.4\",\n    \"cz-conventional-changelog\": \"3.3.0\",\n    \"eslint\": \"9.39.3\",\n    \"eslint-config-prettier\": \"10.1.8\",\n    \"eslint-plugin-formatjs\": \"6.2.0\",\n    \"eslint-plugin-jsx-a11y\": \"6.10.2\",\n    \"eslint-plugin-no-relative-import-paths\": \"1.6.1\",\n    \"eslint-plugin-prettier\": \"4.2.1\",\n    \"eslint-plugin-react\": \"7.37.5\",\n    \"eslint-plugin-react-hooks\": \"7.0.1\",\n    \"globals\": \"^17.3.0\",\n    \"husky\": \"8.0.3\",\n    \"jiti\": \"^2.6.1\",\n    \"lint-staged\": \"13.1.2\",\n    \"nodemon\": \"3.1.11\",\n    \"postcss\": \"^8.5.6\",\n    \"prettier\": \"3.8.1\",\n    \"prettier-plugin-organize-imports\": \"4.3.0\",\n    \"prettier-plugin-tailwindcss\": \"0.6.14\",\n    \"supertest\": \"^7.2.2\",\n    \"tailwindcss\": \"3.4.19\",\n    \"ts-node\": \"10.9.2\",\n    \"tsc-alias\": \"1.8.16\",\n    \"tsconfig-paths\": \"4.2.0\",\n    \"typescript\": \"5.4.5\",\n    \"typescript-eslint\": \"^8.56.1\"\n  },\n  \"engines\": {\n    \"node\": \"^22.0.0\",\n    \"pnpm\": \"^10.0.0\"\n  },\n  \"config\": {\n    \"commitizen\": {\n      \"path\": \"./node_modules/cz-conventional-changelog\"\n    }\n  },\n  \"lint-staged\": {\n    \"**/*.{ts,tsx,js}\": [\n      \"prettier --write\",\n      \"eslint\"\n    ],\n    \"**/*.{json,md,css}\": [\n      \"prettier --write\"\n    ]\n  },\n  \"commitlint\": {\n    \"extends\": [\n      \"@commitlint/config-conventional\"\n    ]\n  },\n  \"pnpm\": {\n    \"onlyBuiltDependencies\": [\n      \"@swc/core\",\n      \"bcrypt\",\n      \"cypress\",\n      \"sharp\",\n      \"sqlite3\"\n    ],\n    \"overrides\": {\n      \"sqlite3>node-gyp\": \"8.4.1\",\n      \"@types/express-session\": \"1.18.2\"\n    }\n  }\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n};\n"
  },
  {
    "path": "public/offline.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#1f2937\" />\n\n    <title>You are offline</title>\n\n    <!-- Inline the page's stylesheet. -->\n    <style>\n      body {\n        font-family: helvetica, arial, sans-serif;\n        margin: 2em;\n        background-color: #111827;\n      }\n\n      h1 {\n        color: #6366f1;\n      }\n\n      p {\n        margin-block: 1rem;\n      }\n\n      button {\n        display: block;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>You are offline</h1>\n\n    <button type=\"button\">↻ Reload</button>\n\n    <!-- Inline the page's JavaScript file. -->\n    <script>\n      // Manual reload feature.\n      document.querySelector('button').addEventListener('click', () => {\n        window.location.reload();\n      });\n\n      // Listen to changes in the network state, reload when online.\n      // This handles the case when the device is completely offline.\n      window.addEventListener('online', () => {\n        window.location.reload();\n      });\n\n      // Check if the server is responding and reload the page if it is.\n      // This handles the case when the device is online, but the server\n      // is offline or misbehaving.\n      async function checkNetworkAndReload() {\n        try {\n          const response = await fetch('.');\n          // Verify we get a valid response from the server\n          if (response.status >= 200 && response.status < 500) {\n            window.location.reload();\n            return;\n          }\n        } catch {\n          // Unable to connect to the server, ignore.\n        }\n        window.setTimeout(checkNetworkAndReload, 2500);\n      }\n\n      checkNetworkAndReload();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "public/robots.txt",
    "content": "User-agent: *\nDisallow: /\n"
  },
  {
    "path": "public/site.webmanifest",
    "content": "{\n  \"name\": \"Seerr\",\n  \"short_name\": \"Seerr\",\n  \"start_url\": \"./\",\n  \"icons\": [\n    {\n      \"src\": \"./android-chrome-192x192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\",\n      \"purpose\": \"any\"\n    },\n    {\n      \"src\": \"./android-chrome-192x192_maskable.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\",\n      \"purpose\": \"maskable\"\n    },\n    {\n      \"src\": \"./android-chrome-512x512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\",\n      \"purpose\": \"any\"\n    },\n    {\n      \"src\": \"./android-chrome-512x512_maskable.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\",\n      \"purpose\": \"maskable\"\n    }\n  ],\n  \"theme_color\": \"#1f2937\",\n  \"background_color\": \"#1f2937\",\n  \"display\": \"standalone\",\n  \"shortcuts\": [\n    {\n      \"name\": \"Discover\",\n      \"url\": \"./\",\n      \"icons\": [\n        {\n          \"src\": \"./sparkles-icon-192x192.png\",\n          \"sizes\": \"192x192\",\n          \"type\": \"image/png\"\n        }\n      ]\n    },\n    {\n      \"name\": \"Requests\",\n      \"url\": \"./requests\",\n      \"icons\": [\n        {\n          \"src\": \"./clock-icon-192x192.png\",\n          \"sizes\": \"192x192\",\n          \"type\": \"image/png\"\n        }\n      ]\n    },\n    {\n      \"name\": \"Profile\",\n      \"url\": \"./profile\",\n      \"icons\": [\n        {\n          \"src\": \"./user-icon-192x192.png\",\n          \"sizes\": \"192x192\",\n          \"type\": \"image/png\"\n        }\n      ]\n    },\n    {\n      \"name\": \"Settings\",\n      \"url\": \"./profile/settings\",\n      \"icons\": [\n        {\n          \"src\": \"./cog-icon-192x192.png\",\n          \"sizes\": \"192x192\",\n          \"type\": \"image/png\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "public/sw.js",
    "content": "/* eslint-disable no-undef */\n// Incrementing OFFLINE_VERSION will kick off the install event and force\n// previously cached resources to be updated from the network.\n// This variable is intentionally declared and unused.\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst OFFLINE_VERSION = 5;\nconst CACHE_NAME = 'offline';\n// Customize this with a different URL if needed.\nconst OFFLINE_URL = '/offline.html';\n\nself.addEventListener('install', (event) => {\n  event.waitUntil(\n    (async () => {\n      const cache = await caches.open(CACHE_NAME);\n      // Setting {cache: 'reload'} in the new request will ensure that the\n      // response isn't fulfilled from the HTTP cache; i.e., it will be from\n      // the network.\n      await cache.add(new Request(OFFLINE_URL, { cache: 'reload' }));\n    })()\n  );\n  // Force the waiting service worker to become the active service worker.\n  self.skipWaiting();\n});\n\nself.addEventListener('activate', (event) => {\n  event.waitUntil(\n    (async () => {\n      // Enable navigation preload if it's supported.\n      // See https://developers.google.com/web/updates/2017/02/navigation-preload\n      if ('navigationPreload' in self.registration) {\n        await self.registration.navigationPreload.enable();\n      }\n    })()\n  );\n\n  // Tell the active service worker to take control of the page immediately.\n  clients.claim();\n});\n\nself.addEventListener('fetch', (event) => {\n  // We only want to call event.respondWith() if this is a navigation request\n  // for an HTML page.\n  if (event.request.mode === 'navigate') {\n    event.respondWith(\n      (async () => {\n        try {\n          // First, try to use the navigation preload response if it's supported.\n          const preloadResponse = await event.preloadResponse;\n          if (preloadResponse) {\n            return preloadResponse;\n          }\n\n          // Always try the network first.\n          const networkResponse = await fetch(event.request);\n          return networkResponse;\n        } catch (error) {\n          // catch is only triggered if an exception is thrown, which is likely\n          // due to a network error.\n          // If fetch() returns a valid HTTP response with a response code in\n          // the 4xx or 5xx range, the catch() will NOT be called.\n          // eslint-disable-next-line no-console\n          console.log('Fetch failed; returning offline page instead.', error);\n\n          const cache = await caches.open(CACHE_NAME);\n          const cachedResponse = await cache.match(OFFLINE_URL);\n          return cachedResponse;\n        }\n      })()\n    );\n  }\n});\n\nself.addEventListener('push', (event) => {\n  const payload = event.data ? event.data.json() : {};\n\n  const options = {\n    body: payload.message,\n    badge: 'badge-128x128.png',\n    icon: payload.image ? payload.image : 'android-chrome-192x192.png',\n    vibrate: [100, 50, 100],\n    data: {\n      dateOfArrival: Date.now(),\n      primaryKey: '2',\n      actionUrl: payload.actionUrl,\n      requestId: payload.requestId,\n    },\n    actions: [],\n  };\n\n  if (payload.actionUrl) {\n    options.actions.push({\n      action: 'view',\n      title: payload.actionUrlTitle ?? 'View',\n    });\n  }\n\n  if (payload.notificationType === 'MEDIA_PENDING') {\n    options.actions.push(\n      {\n        action: 'approve',\n        title: 'Approve',\n      },\n      {\n        action: 'decline',\n        title: 'Decline',\n      }\n    );\n  }\n\n  // Set the badge with the amount of pending requests\n  // Only update the badge if the payload confirms they are the admin\n  if (\n    (payload.notificationType === 'MEDIA_APPROVED' ||\n      payload.notificationType === 'MEDIA_DECLINED') &&\n    payload.isAdmin\n  ) {\n    if ('setAppBadge' in navigator) {\n      navigator.setAppBadge(payload.pendingRequestsCount);\n    }\n    return;\n  }\n\n  if (payload.notificationType === 'MEDIA_PENDING') {\n    if ('setAppBadge' in navigator) {\n      navigator.setAppBadge(payload.pendingRequestsCount);\n    }\n  }\n\n  event.waitUntil(self.registration.showNotification(payload.subject, options));\n});\n\nself.addEventListener(\n  'notificationclick',\n  (event) => {\n    const notificationData = event.notification.data;\n\n    event.notification.close();\n\n    if (event.action === 'approve') {\n      fetch(`/api/v1/request/${notificationData.requestId}/approve`, {\n        method: 'POST',\n      });\n    } else if (event.action === 'decline') {\n      fetch(`/api/v1/request/${notificationData.requestId}/decline`, {\n        method: 'POST',\n      });\n    }\n\n    if (notificationData.actionUrl) {\n      clients.openWindow(notificationData.actionUrl);\n    }\n  },\n  false\n);\n"
  },
  {
    "path": "seerr-api.yml",
    "content": "openapi: '3.0.2'\ninfo:\n  title: 'Seerr API'\n  version: '1.0.0'\n  description: |\n    This is the documentation for the Seerr API backend.\n\n    Two primary authentication methods are supported:\n\n    - **Cookie Authentication**: A valid sign-in to the `/auth/plex` or `/auth/local` will generate a valid authentication cookie.\n    - **API Key Authentication**: Sign-in is also possible by passing an `X-Api-Key` header along with a valid API Key generated by Seerr.\ntags:\n  - name: public\n    description: Public API endpoints requiring no authentication.\n  - name: settings\n    description: Endpoints related to Seerr's settings and configuration.\n  - name: auth\n    description: Endpoints related to logging in or out, and the currently authenticated user.\n  - name: users\n    description: Endpoints related to user management.\n  - name: search\n    description: Endpoints related to search and discovery.\n  - name: request\n    description: Endpoints related to request management.\n  - name: movies\n    description: Endpoints related to retrieving movies and their details.\n  - name: tv\n    description: Endpoints related to retrieving TV series and their details.\n  - name: other\n    description: Endpoints related to other TMDB data\n  - name: person\n    description: Endpoints related to retrieving person details.\n  - name: media\n    description: Endpoints related to media management.\n  - name: collection\n    description: Endpoints related to retrieving collection details.\n  - name: service\n    description: Endpoints related to getting service (Radarr/Sonarr) details.\n  - name: watchlist\n    description: Collection of media to watch later\n  - name: blocklist\n    description: Blocklisted media from discovery page.\nservers:\n  - url: '{server}/api/v1'\n    variables:\n      server:\n        default: http://localhost:5055\n\ncomponents:\n  schemas:\n    Blocklist:\n      type: object\n      properties:\n        tmdbId:\n          type: number\n          example: 1\n        title:\n          type: string\n        media:\n          $ref: '#/components/schemas/MediaInfo'\n        userId:\n          type: number\n          example: 1\n    Watchlist:\n      type: object\n      properties:\n        id:\n          type: integer\n          example: 1\n          readOnly: true\n        tmdbId:\n          type: number\n          example: 1\n        ratingKey:\n          type: string\n        type:\n          type: string\n        title:\n          type: string\n        media:\n          $ref: '#/components/schemas/MediaInfo'\n        createdAt:\n          type: string\n          example: '2020-09-12T10:00:27.000Z'\n          readOnly: true\n        updatedAt:\n          type: string\n          example: '2020-09-12T10:00:27.000Z'\n          readOnly: true\n        requestedBy:\n          $ref: '#/components/schemas/User'\n    User:\n      type: object\n      properties:\n        id:\n          type: integer\n          example: 1\n          readOnly: true\n        email:\n          type: string\n          example: 'hey@itsme.com'\n          readOnly: true\n        username:\n          type: string\n        plexUsername:\n          type: string\n          readOnly: true\n        plexToken:\n          type: string\n          readOnly: true\n        jellyfinAuthToken:\n          type: string\n          readOnly: true\n        userType:\n          type: integer\n          example: 1\n          readOnly: true\n        permissions:\n          type: number\n          example: 0\n        avatar:\n          type: string\n          readOnly: true\n        createdAt:\n          type: string\n          example: '2020-09-02T05:02:23.000Z'\n          readOnly: true\n        updatedAt:\n          type: string\n          example: '2020-09-02T05:02:23.000Z'\n          readOnly: true\n        requestCount:\n          type: number\n          example: 5\n          readOnly: true\n      required:\n        - id\n        - email\n        - createdAt\n        - updatedAt\n    UserSettings:\n      type: object\n      properties:\n        username:\n          type: string\n          nullable: true\n          example: 'Mr User'\n        email:\n          type: string\n          example: 'user@example.com'\n        discordId:\n          type: string\n          nullable: true\n          example: '123456789'\n        locale:\n          type: string\n          nullable: true\n          example: 'en'\n        discoverRegion:\n          type: string\n          nullable: true\n          example: 'US'\n        streamingRegion:\n          type: string\n          nullable: true\n          example: 'US'\n        originalLanguage:\n          type: string\n          nullable: true\n          example: 'en'\n        movieQuotaLimit:\n          type: number\n          nullable: true\n          description: 'Maximum number of movie requests allowed'\n          example: 10\n        movieQuotaDays:\n          type: number\n          nullable: true\n          description: 'Time period in days for movie quota'\n          example: 30\n        tvQuotaLimit:\n          type: number\n          nullable: true\n          description: 'Maximum number of TV requests allowed'\n          example: 5\n        tvQuotaDays:\n          type: number\n          nullable: true\n          description: 'Time period in days for TV quota'\n          example: 14\n        globalMovieQuotaDays:\n          type: number\n          nullable: true\n          description: 'Global movie quota days setting'\n          example: 30\n        globalMovieQuotaLimit:\n          type: number\n          nullable: true\n          description: 'Global movie quota limit setting'\n          example: 10\n        globalTvQuotaLimit:\n          type: number\n          nullable: true\n          description: 'Global TV quota limit setting'\n          example: 5\n        globalTvQuotaDays:\n          type: number\n          nullable: true\n          description: 'Global TV quota days setting'\n          example: 14\n        watchlistSyncMovies:\n          type: boolean\n          nullable: true\n          description: 'Enable watchlist sync for movies'\n          example: true\n        watchlistSyncTv:\n          type: boolean\n          nullable: true\n          description: 'Enable watchlist sync for TV'\n          example: false\n    MainSettings:\n      type: object\n      properties:\n        apiKey:\n          type: string\n          readOnly: true\n        appLanguage:\n          type: string\n          example: en\n        applicationTitle:\n          type: string\n          example: Seerr\n        applicationUrl:\n          type: string\n          example: https://os.example.com\n        hideAvailable:\n          type: boolean\n          example: false\n        partialRequestsEnabled:\n          type: boolean\n          example: false\n        localLogin:\n          type: boolean\n          example: true\n        mediaServerType:\n          type: number\n          example: 1\n        newPlexLogin:\n          type: boolean\n          example: true\n        defaultPermissions:\n          type: number\n          example: 32\n        enableSpecialEpisodes:\n          type: boolean\n          example: false\n    NetworkSettings:\n      type: object\n      properties:\n        csrfProtection:\n          type: boolean\n          example: false\n        forceIpv4First:\n          type: boolean\n          example: false\n        trustProxy:\n          type: boolean\n          example: false\n        proxy:\n          type: object\n          properties:\n            enabled:\n              type: boolean\n              example: false\n            hostname:\n              type: string\n              example: ''\n            port:\n              type: number\n              example: 8080\n            useSsl:\n              type: boolean\n              example: false\n            user:\n              type: string\n              example: ''\n            password:\n              type: string\n              example: ''\n            bypassFilter:\n              type: string\n              example: ''\n            bypassLocalAddresses:\n              type: boolean\n              example: true\n        dnsCache:\n          type: object\n          properties:\n            enabled:\n              type: boolean\n              example: false\n            forceMinTtl:\n              type: number\n              example: 0\n            forceMaxTtl:\n              type: number\n              example: -1\n    PlexLibrary:\n      type: object\n      properties:\n        id:\n          type: string\n        name:\n          type: string\n          example: Movies\n        enabled:\n          type: boolean\n          example: false\n      required:\n        - id\n        - name\n        - enabled\n    PlexSettings:\n      type: object\n      properties:\n        name:\n          type: string\n          example: 'Main Server'\n          readOnly: true\n        machineId:\n          type: string\n          example: '1234123412341234'\n          readOnly: true\n        ip:\n          type: string\n          example: '127.0.0.1'\n        port:\n          type: number\n          example: 32400\n        useSsl:\n          type: boolean\n          nullable: true\n        libraries:\n          type: array\n          readOnly: true\n          items:\n            $ref: '#/components/schemas/PlexLibrary'\n        webAppUrl:\n          type: string\n          nullable: true\n          example: 'https://app.plex.tv/desktop'\n      required:\n        - name\n        - machineId\n        - ip\n        - port\n    PlexConnection:\n      type: object\n      properties:\n        protocol:\n          type: string\n          example: 'https'\n        address:\n          type: string\n          example: '127.0.0.1'\n        port:\n          type: number\n          example: 32400\n        uri:\n          type: string\n          example: 'https://127-0-0-1.2ab6ce1a093d465e910def96cf4e4799.plex.direct:32400'\n        local:\n          type: boolean\n          example: true\n        status:\n          type: number\n          example: 200\n        message:\n          type: string\n          example: 'OK'\n      required:\n        - protocol\n        - address\n        - port\n        - uri\n        - local\n    PlexDevice:\n      type: object\n      properties:\n        name:\n          type: string\n          example: 'My Plex Server'\n        product:\n          type: string\n          example: 'Plex Media Server'\n        productVersion:\n          type: string\n          example: '1.21'\n        platform:\n          type: string\n          example: 'Linux'\n        platformVersion:\n          type: string\n          example: 'default/linux/amd64/17.1/systemd'\n        device:\n          type: string\n          example: 'PC'\n        clientIdentifier:\n          type: string\n          example: '85a943ce-a0cc-4d2a-a4ec-f74f06e40feb'\n        createdAt:\n          type: string\n          example: '2021-01-01T00:00:00.000Z'\n        lastSeenAt:\n          type: string\n          example: '2021-01-01T00:00:00.000Z'\n        provides:\n          type: array\n          items:\n            type: string\n            example: 'server'\n        owned:\n          type: boolean\n          example: true\n        ownerID:\n          type: string\n          example: '12345'\n        home:\n          type: boolean\n          example: true\n        sourceTitle:\n          type: string\n          example: 'xyzabc'\n        accessToken:\n          type: string\n          example: 'supersecretaccesstoken'\n        publicAddress:\n          type: string\n          example: '127.0.0.1'\n        httpsRequired:\n          type: boolean\n          example: true\n        synced:\n          type: boolean\n          example: true\n        relay:\n          type: boolean\n          example: true\n        dnsRebindingProtection:\n          type: boolean\n          example: false\n        natLoopbackSupported:\n          type: boolean\n          example: false\n        publicAddressMatches:\n          type: boolean\n          example: false\n        presence:\n          type: boolean\n          example: true\n        connection:\n          type: array\n          items:\n            $ref: '#/components/schemas/PlexConnection'\n      required:\n        - name\n        - product\n        - productVersion\n        - platform\n        - device\n        - clientIdentifier\n        - createdAt\n        - lastSeenAt\n        - provides\n        - owned\n        - connection\n    JellyfinLibrary:\n      type: object\n      properties:\n        id:\n          type: string\n        name:\n          type: string\n          example: Movies\n        enabled:\n          type: boolean\n          example: false\n      required:\n        - id\n        - name\n        - enabled\n    JellyfinSettings:\n      type: object\n      properties:\n        name:\n          type: string\n          example: 'Main Server'\n          readOnly: true\n        hostname:\n          type: string\n          example: 'http://my.jellyfin.host'\n        externalHostname:\n          type: string\n          example: 'http://my.jellyfin.host'\n        jellyfinForgotPasswordUrl:\n          type: string\n          example: 'http://my.jellyfin.host/web/index.html#!/forgotpassword.html'\n        adminUser:\n          type: string\n          example: 'admin'\n        adminPass:\n          type: string\n          example: 'mypassword'\n        libraries:\n          type: array\n          readOnly: true\n          items:\n            $ref: '#/components/schemas/JellyfinLibrary'\n        serverID:\n          type: string\n          readOnly: true\n    MetadataSettings:\n      type: object\n      properties:\n        settings:\n          type: object\n          properties:\n            tv:\n              type: string\n              enum: [tvdb, tmdb]\n              example: 'tvdb'\n            anime:\n              type: string\n              enum: [tvdb, tmdb]\n              example: 'tvdb'\n    TautulliSettings:\n      type: object\n      properties:\n        hostname:\n          type: string\n          nullable: true\n          example: 'tautulli.example.com'\n        port:\n          type: number\n          nullable: true\n          example: 8181\n        useSsl:\n          type: boolean\n          nullable: true\n        apiKey:\n          type: string\n          nullable: true\n        externalUrl:\n          type: string\n          nullable: true\n    RadarrSettings:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 0\n          readOnly: true\n        name:\n          type: string\n          example: 'Radarr Main'\n        hostname:\n          type: string\n          example: '127.0.0.1'\n        port:\n          type: number\n          example: 7878\n        apiKey:\n          type: string\n          example: 'exampleapikey'\n        useSsl:\n          type: boolean\n          example: false\n        baseUrl:\n          type: string\n        activeProfileId:\n          type: number\n          example: 1\n        activeProfileName:\n          type: string\n          example: 720p/1080p\n        activeDirectory:\n          type: string\n          example: '/movies'\n        is4k:\n          type: boolean\n          example: false\n        minimumAvailability:\n          type: string\n          example: 'In Cinema'\n        isDefault:\n          type: boolean\n          example: false\n        externalUrl:\n          type: string\n          example: http://radarr.example.com\n        syncEnabled:\n          type: boolean\n          example: false\n        preventSearch:\n          type: boolean\n          example: false\n      required:\n        - name\n        - hostname\n        - port\n        - apiKey\n        - useSsl\n        - activeProfileId\n        - activeProfileName\n        - activeDirectory\n        - is4k\n        - minimumAvailability\n        - isDefault\n    SonarrSettings:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 0\n          readOnly: true\n        name:\n          type: string\n          example: 'Sonarr Main'\n        hostname:\n          type: string\n          example: '127.0.0.1'\n        port:\n          type: number\n          example: 8989\n        apiKey:\n          type: string\n          example: 'exampleapikey'\n        useSsl:\n          type: boolean\n          example: false\n        baseUrl:\n          type: string\n        activeProfileId:\n          type: number\n          example: 1\n        activeProfileName:\n          type: string\n          example: 720p/1080p\n        activeDirectory:\n          type: string\n          example: '/tv/'\n        activeLanguageProfileId:\n          type: number\n          example: 1\n        activeAnimeProfileId:\n          type: number\n          nullable: true\n        activeAnimeLanguageProfileId:\n          type: number\n          nullable: true\n        activeAnimeProfileName:\n          type: string\n          example: 720p/1080p\n          nullable: true\n        activeAnimeDirectory:\n          type: string\n          nullable: true\n        is4k:\n          type: boolean\n          example: false\n        enableSeasonFolders:\n          type: boolean\n          example: false\n        isDefault:\n          type: boolean\n          example: false\n        externalUrl:\n          type: string\n          example: http://radarr.example.com\n        syncEnabled:\n          type: boolean\n          example: false\n        preventSearch:\n          type: boolean\n          example: false\n      required:\n        - name\n        - hostname\n        - port\n        - apiKey\n        - useSsl\n        - activeProfileId\n        - activeProfileName\n        - activeDirectory\n        - is4k\n        - enableSeasonFolders\n        - isDefault\n    ServarrTag:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        label:\n          type: string\n          example: A Label\n    PublicSettings:\n      type: object\n      properties:\n        initialized:\n          type: boolean\n          example: false\n    MovieResult:\n      type: object\n      required:\n        - id\n        - mediaType\n        - title\n      properties:\n        id:\n          type: number\n          example: 1234\n        mediaType:\n          type: string\n        popularity:\n          type: number\n          example: 10\n        posterPath:\n          type: string\n        backdropPath:\n          type: string\n        voteCount:\n          type: number\n        voteAverage:\n          type: number\n        genreIds:\n          type: array\n          items:\n            type: number\n        overview:\n          type: string\n          example: 'Overview of the movie'\n        originalLanguage:\n          type: string\n          example: 'en'\n        title:\n          type: string\n          example: Movie Title\n        originalTitle:\n          type: string\n          example: Original Movie Title\n        releaseDate:\n          type: string\n        adult:\n          type: boolean\n          example: false\n        video:\n          type: boolean\n          example: false\n        mediaInfo:\n          $ref: '#/components/schemas/MediaInfo'\n    TvResult:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1234\n        mediaType:\n          type: string\n        popularity:\n          type: number\n          example: 10\n        posterPath:\n          type: string\n        backdropPath:\n          type: string\n        voteCount:\n          type: number\n        voteAverage:\n          type: number\n        genreIds:\n          type: array\n          items:\n            type: number\n        overview:\n          type: string\n          example: 'Overview of the movie'\n        originalLanguage:\n          type: string\n          example: 'en'\n        name:\n          type: string\n          example: TV Show Name\n        originalName:\n          type: string\n          example: Original TV Show Name\n        originCountry:\n          type: array\n          items:\n            type: string\n        firstAirDate:\n          type: string\n        mediaInfo:\n          $ref: '#/components/schemas/MediaInfo'\n    PersonResult:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 12345\n        profilePath:\n          type: string\n        adult:\n          type: boolean\n          example: false\n        mediaType:\n          type: string\n          default: 'person'\n        knownFor:\n          type: array\n          items:\n            oneOf:\n              - $ref: '#/components/schemas/MovieResult'\n              - $ref: '#/components/schemas/TvResult'\n    Genre:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        name:\n          type: string\n          example: Adventure\n    Company:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        logo_path:\n          type: string\n          nullable: true\n        name:\n          type: string\n    ProductionCompany:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        logoPath:\n          type: string\n          nullable: true\n        originCountry:\n          type: string\n        name:\n          type: string\n    Network:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        logoPath:\n          type: string\n          nullable: true\n        originCountry:\n          type: string\n        name:\n          type: string\n    RelatedVideo:\n      type: object\n      properties:\n        url:\n          type: string\n          example: https://www.youtube.com/watch?v=9qhL2_UxXM0/\n        key:\n          type: string\n          example: 9qhL2_UxXM0\n        name:\n          type: string\n          example: Trailer for some movie (1978)\n        size:\n          type: number\n          example: 1080\n        type:\n          type: string\n          example: Trailer\n          enum:\n            - Clip\n            - Teaser\n            - Trailer\n            - Featurette\n            - Opening Credits\n            - Behind the Scenes\n            - Bloopers\n        site:\n          type: string\n          enum:\n            - 'YouTube'\n    MovieDetails:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 123\n          readOnly: true\n        imdbId:\n          type: string\n          example: 'tt123'\n        adult:\n          type: boolean\n        backdropPath:\n          type: string\n        posterPath:\n          type: string\n        budget:\n          type: number\n          example: 1000000\n        genres:\n          type: array\n          items:\n            $ref: '#/components/schemas/Genre'\n        homepage:\n          type: string\n        relatedVideos:\n          type: array\n          items:\n            $ref: '#/components/schemas/RelatedVideo'\n        originalLanguage:\n          type: string\n        originalTitle:\n          type: string\n        overview:\n          type: string\n        popularity:\n          type: number\n        productionCompanies:\n          type: array\n          items:\n            $ref: '#/components/schemas/ProductionCompany'\n        productionCountries:\n          type: array\n          items:\n            type: object\n            properties:\n              iso_3166_1:\n                type: string\n              name:\n                type: string\n        releaseDate:\n          type: string\n        releases:\n          type: object\n          properties:\n            results:\n              type: array\n              items:\n                type: object\n                properties:\n                  iso_3166_1:\n                    type: string\n                    example: 'US'\n                  rating:\n                    type: string\n                    nullable: true\n                  release_dates:\n                    type: array\n                    items:\n                      type: object\n                      properties:\n                        certification:\n                          type: string\n                          example: 'PG-13'\n                        iso_639_1:\n                          type: string\n                          nullable: true\n                        note:\n                          type: string\n                          nullable: true\n                          example: 'Blu ray'\n                        release_date:\n                          type: string\n                          example: '2017-07-12T00:00:00.000Z'\n                        type:\n                          type: number\n                          example: 1\n        revenue:\n          type: number\n          nullable: true\n        runtime:\n          type: number\n        spokenLanguages:\n          type: array\n          items:\n            $ref: '#/components/schemas/SpokenLanguage'\n        status:\n          type: string\n        tagline:\n          type: string\n        title:\n          type: string\n        video:\n          type: boolean\n        voteAverage:\n          type: number\n        voteCount:\n          type: number\n        credits:\n          type: object\n          properties:\n            cast:\n              type: array\n              items:\n                $ref: '#/components/schemas/Cast'\n            crew:\n              type: array\n              items:\n                $ref: '#/components/schemas/Crew'\n        collection:\n          type: object\n          properties:\n            id:\n              type: number\n              example: 1\n            name:\n              type: string\n              example: A collection\n            posterPath:\n              type: string\n            backdropPath:\n              type: string\n        externalIds:\n          $ref: '#/components/schemas/ExternalIds'\n        mediaInfo:\n          $ref: '#/components/schemas/MediaInfo'\n        watchProviders:\n          type: array\n          items:\n            $ref: '#/components/schemas/WatchProviders'\n    Episode:\n      type: object\n      properties:\n        id:\n          type: number\n        name:\n          type: string\n        airDate:\n          type: string\n          nullable: true\n        episodeNumber:\n          type: number\n        overview:\n          type: string\n        productionCode:\n          type: string\n        seasonNumber:\n          type: number\n        showId:\n          type: number\n        stillPath:\n          type: string\n          nullable: true\n        voteAverage:\n          type: number\n        voteCount:\n          type: number\n    Season:\n      type: object\n      properties:\n        id:\n          type: number\n        airDate:\n          type: string\n          nullable: true\n        episodeCount:\n          type: number\n        name:\n          type: string\n        overview:\n          type: string\n        posterPath:\n          type: string\n        seasonNumber:\n          type: number\n        episodes:\n          type: array\n          items:\n            $ref: '#/components/schemas/Episode'\n    TvDetails:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 123\n        backdropPath:\n          type: string\n        posterPath:\n          type: string\n        contentRatings:\n          type: object\n          properties:\n            results:\n              type: array\n              items:\n                type: object\n                properties:\n                  iso_3166_1:\n                    type: string\n                    example: 'US'\n                  rating:\n                    type: string\n                    example: 'TV-14'\n        createdBy:\n          type: array\n          items:\n            type: object\n            properties:\n              id:\n                type: number\n              name:\n                type: string\n              gender:\n                type: number\n              profilePath:\n                type: string\n                nullable: true\n        episodeRunTime:\n          type: array\n          items:\n            type: number\n        firstAirDate:\n          type: string\n        genres:\n          type: array\n          items:\n            $ref: '#/components/schemas/Genre'\n        homepage:\n          type: string\n        inProduction:\n          type: boolean\n        languages:\n          type: array\n          items:\n            type: string\n        lastAirDate:\n          type: string\n        lastEpisodeToAir:\n          $ref: '#/components/schemas/Episode'\n        name:\n          type: string\n        nextEpisodeToAir:\n          $ref: '#/components/schemas/Episode'\n        networks:\n          type: array\n          items:\n            $ref: '#/components/schemas/ProductionCompany'\n        numberOfEpisodes:\n          type: number\n        numberOfSeason:\n          type: number\n        originCountry:\n          type: array\n          items:\n            type: string\n        originalLanguage:\n          type: string\n        originalName:\n          type: string\n        overview:\n          type: string\n        popularity:\n          type: number\n        productionCompanies:\n          type: array\n          items:\n            $ref: '#/components/schemas/ProductionCompany'\n        productionCountries:\n          type: array\n          items:\n            type: object\n            properties:\n              iso_3166_1:\n                type: string\n              name:\n                type: string\n        spokenLanguages:\n          type: array\n          items:\n            $ref: '#/components/schemas/SpokenLanguage'\n        seasons:\n          type: array\n          items:\n            $ref: '#/components/schemas/Season'\n        status:\n          type: string\n        tagline:\n          type: string\n        type:\n          type: string\n        voteAverage:\n          type: number\n        voteCount:\n          type: number\n        credits:\n          type: object\n          properties:\n            cast:\n              type: array\n              items:\n                $ref: '#/components/schemas/Cast'\n            crew:\n              type: array\n              items:\n                $ref: '#/components/schemas/Crew'\n        externalIds:\n          $ref: '#/components/schemas/ExternalIds'\n        keywords:\n          type: array\n          items:\n            $ref: '#/components/schemas/Keyword'\n        mediaInfo:\n          $ref: '#/components/schemas/MediaInfo'\n        watchProviders:\n          type: array\n          items:\n            $ref: '#/components/schemas/WatchProviders'\n    MediaRequest:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 123\n          readOnly: true\n        status:\n          type: number\n          example: 0\n          description: Status of the request. 1 = PENDING APPROVAL, 2 = APPROVED, 3 = DECLINED\n          readOnly: true\n        media:\n          $ref: '#/components/schemas/MediaInfo'\n        createdAt:\n          type: string\n          example: '2020-09-12T10:00:27.000Z'\n          readOnly: true\n        updatedAt:\n          type: string\n          example: '2020-09-12T10:00:27.000Z'\n          readOnly: true\n        requestedBy:\n          $ref: '#/components/schemas/User'\n        modifiedBy:\n          anyOf:\n            - $ref: '#/components/schemas/User'\n            - type: string\n              nullable: true\n        is4k:\n          type: boolean\n          example: false\n        serverId:\n          type: number\n        profileId:\n          type: number\n        rootFolder:\n          type: string\n      required:\n        - id\n        - status\n    MediaInfo:\n      type: object\n      properties:\n        id:\n          type: number\n          readOnly: true\n        tmdbId:\n          type: number\n          readOnly: true\n        tvdbId:\n          type: number\n          readOnly: true\n          nullable: true\n        status:\n          type: number\n          example: 0\n          description: Availability of the media. 1 = `UNKNOWN`, 2 = `PENDING`, 3 = `PROCESSING`, 4 = `PARTIALLY_AVAILABLE`, 5 = `AVAILABLE`, 6 = `DELETED`\n        requests:\n          type: array\n          readOnly: true\n          items:\n            $ref: '#/components/schemas/MediaRequest'\n        createdAt:\n          type: string\n          example: '2020-09-12T10:00:27.000Z'\n          readOnly: true\n        updatedAt:\n          type: string\n          example: '2020-09-12T10:00:27.000Z'\n          readOnly: true\n    Cast:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 123\n        castId:\n          type: number\n          example: 1\n        character:\n          type: string\n          example: Some Character Name\n        creditId:\n          type: string\n        gender:\n          type: number\n        name:\n          type: string\n          example: Some Persons Name\n        order:\n          type: number\n        profilePath:\n          type: string\n          nullable: true\n    Crew:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 123\n        creditId:\n          type: string\n        gender:\n          type: number\n        name:\n          type: string\n          example: Some Persons Name\n        job:\n          type: string\n        department:\n          type: string\n        profilePath:\n          type: string\n          nullable: true\n    ExternalIds:\n      type: object\n      properties:\n        facebookId:\n          type: string\n          nullable: true\n        freebaseId:\n          type: string\n          nullable: true\n        freebaseMid:\n          type: string\n          nullable: true\n        imdbId:\n          type: string\n          nullable: true\n        instagramId:\n          type: string\n          nullable: true\n        tvdbId:\n          type: number\n          nullable: true\n        tvrageId:\n          type: number\n          nullable: true\n        twitterId:\n          type: string\n          nullable: true\n    ServiceProfile:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        name:\n          type: string\n          example: 720p/1080p\n    PageInfo:\n      type: object\n      properties:\n        page:\n          type: number\n          example: 1\n        pages:\n          type: number\n          example: 10\n        results:\n          type: number\n          example: 100\n    DiscordSettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n        options:\n          type: object\n          properties:\n            botUsername:\n              type: string\n            botAvatarUrl:\n              type: string\n            webhookUrl:\n              type: string\n            webhookRoleId:\n              type: string\n            enableMentions:\n              type: boolean\n    SlackSettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n        options:\n          type: object\n          properties:\n            webhookUrl:\n              type: string\n    WebPushSettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n    WebhookSettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n        options:\n          type: object\n          properties:\n            webhookUrl:\n              type: string\n            authHeader:\n              type: string\n            jsonPayload:\n              type: string\n            supportVariables:\n              type: boolean\n              example: false\n    TelegramSettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n        options:\n          type: object\n          properties:\n            botUsername:\n              type: string\n            botAPI:\n              type: string\n            chatId:\n              type: string\n            messageThreadId:\n              type: string\n            sendSilently:\n              type: boolean\n    PushbulletSettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n        options:\n          type: object\n          properties:\n            accessToken:\n              type: string\n            channelTag:\n              type: string\n              nullable: true\n    PushoverSettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n        options:\n          type: object\n          properties:\n            accessToken:\n              type: string\n            userToken:\n              type: string\n            sound:\n              type: string\n    GotifySettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n        options:\n          type: object\n          properties:\n            url:\n              type: string\n            token:\n              type: string\n    NtfySettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n        options:\n          type: object\n          properties:\n            url:\n              type: string\n            topic:\n              type: string\n            authMethodUsernamePassword:\n              type: boolean\n            username:\n              type: string\n            password:\n              type: string\n            authMethodToken:\n              type: boolean\n            token:\n              type: string\n    NotificationEmailSettings:\n      type: object\n      properties:\n        enabled:\n          type: boolean\n          example: false\n        types:\n          type: number\n          example: 2\n        options:\n          type: object\n          properties:\n            emailFrom:\n              type: string\n              example: no-reply@example.com\n            senderName:\n              type: string\n              example: Seerr\n            smtpHost:\n              type: string\n              example: 127.0.0.1\n            smtpPort:\n              type: number\n              example: 465\n            secure:\n              type: boolean\n              example: false\n            ignoreTls:\n              type: boolean\n              example: false\n            requireTls:\n              type: boolean\n              example: false\n            authUser:\n              type: string\n              nullable: true\n            authPass:\n              type: string\n              nullable: true\n            allowSelfSigned:\n              type: boolean\n              example: false\n    Job:\n      type: object\n      properties:\n        id:\n          type: string\n          example: job-name\n        type:\n          type: string\n          enum: [process, command]\n        interval:\n          type: string\n          enum: [short, long, fixed]\n        name:\n          type: string\n          example: A Job Name\n        nextExecutionTime:\n          type: string\n          example: '2020-09-02T05:02:23.000Z'\n        running:\n          type: boolean\n          example: false\n    PersonDetails:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        name:\n          type: string\n        deathday:\n          type: string\n        knownForDepartment:\n          type: string\n        alsoKnownAs:\n          type: array\n          items:\n            type: string\n        gender:\n          type: string\n        biography:\n          type: string\n        popularity:\n          type: string\n        placeOfBirth:\n          type: string\n        profilePath:\n          type: string\n        adult:\n          type: boolean\n        imdbId:\n          type: string\n        homepage:\n          type: string\n    CreditCast:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        originalLanguage:\n          type: string\n        episodeCount:\n          type: number\n        overview:\n          type: string\n        originCountry:\n          type: array\n          items:\n            type: string\n        originalName:\n          type: string\n        voteCount:\n          type: number\n        name:\n          type: string\n        mediaType:\n          type: string\n        popularity:\n          type: number\n        creditId:\n          type: string\n        backdropPath:\n          type: string\n        firstAirDate:\n          type: string\n        voteAverage:\n          type: number\n        genreIds:\n          type: array\n          items:\n            type: number\n        posterPath:\n          type: string\n        originalTitle:\n          type: string\n        video:\n          type: boolean\n        title:\n          type: string\n        adult:\n          type: boolean\n        releaseDate:\n          type: string\n        character:\n          type: string\n        mediaInfo:\n          $ref: '#/components/schemas/MediaInfo'\n    CreditCrew:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        originalLanguage:\n          type: string\n        episodeCount:\n          type: number\n        overview:\n          type: string\n        originCountry:\n          type: array\n          items:\n            type: string\n        originalName:\n          type: string\n        voteCount:\n          type: number\n        name:\n          type: string\n        mediaType:\n          type: string\n        popularity:\n          type: number\n        creditId:\n          type: string\n        backdropPath:\n          type: string\n        firstAirDate:\n          type: string\n        voteAverage:\n          type: number\n        genreIds:\n          type: array\n          items:\n            type: number\n        posterPath:\n          type: string\n        originalTitle:\n          type: string\n        video:\n          type: boolean\n        title:\n          type: string\n        adult:\n          type: boolean\n        releaseDate:\n          type: string\n        department:\n          type: string\n        job:\n          type: string\n        mediaInfo:\n          $ref: '#/components/schemas/MediaInfo'\n    Keyword:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        name:\n          type: string\n          example: 'anime'\n    SpokenLanguage:\n      type: object\n      properties:\n        englishName:\n          type: string\n          example: 'English'\n          nullable: true\n        iso_639_1:\n          type: string\n          example: 'en'\n        name:\n          type: string\n          example: 'English'\n    Collection:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 123\n        name:\n          type: string\n          example: A Movie Collection\n        overview:\n          type: string\n          example: Overview of collection\n        posterPath:\n          type: string\n        backdropPath:\n          type: string\n        parts:\n          type: array\n          items:\n            $ref: '#/components/schemas/MovieResult'\n    SonarrSeries:\n      type: object\n      properties:\n        title:\n          type: string\n          example: COVID-25\n        sortTitle:\n          type: string\n          example: covid 25\n        seasonCount:\n          type: number\n          example: 1\n        status:\n          type: string\n          example: upcoming\n        overview:\n          type: string\n          example: The thread is picked up again by Marianne Schmidt which ...\n        network:\n          type: string\n          example: CBS\n        airTime:\n          type: string\n          example: 02:15\n        images:\n          type: array\n          items:\n            type: object\n            properties:\n              coverType:\n                type: string\n                example: banner\n              url:\n                type: string\n                example: /sonarr/MediaCoverProxy/6467f05d9872726ad08cbf920e5fee4bf69198682260acab8eab5d3c2c958e92/5c8f116c6aa5c.jpg\n        remotePoster:\n          type: string\n          example: https://artworks.thetvdb.com/banners/posters/5c8f116129983.jpg\n        seasons:\n          type: array\n          items:\n            type: object\n            properties:\n              seasonNumber:\n                type: number\n                example: 1\n              monitored:\n                type: boolean\n                example: true\n        year:\n          type: number\n          example: 2015\n        path:\n          type: string\n        profileId:\n          type: number\n        languageProfileId:\n          type: number\n        seasonFolder:\n          type: boolean\n        monitored:\n          type: boolean\n        useSceneNumbering:\n          type: boolean\n        runtime:\n          type: number\n        tvdbId:\n          type: number\n          example: 12345\n        tvRageId:\n          type: number\n        tvMazeId:\n          type: number\n        firstAired:\n          type: string\n        lastInfoSync:\n          type: string\n          nullable: true\n        seriesType:\n          type: string\n        cleanTitle:\n          type: string\n        imdbId:\n          type: string\n        titleSlug:\n          type: string\n        certification:\n          type: string\n        genres:\n          type: array\n          items:\n            type: string\n        tags:\n          type: array\n          items:\n            type: string\n        added:\n          type: string\n        ratings:\n          type: array\n          items:\n            type: object\n            properties:\n              votes:\n                type: number\n              value:\n                type: number\n        qualityProfileId:\n          type: number\n        id:\n          type: number\n          nullable: true\n        rootFolderPath:\n          type: string\n          nullable: true\n        addOptions:\n          type: array\n          items:\n            type: object\n            properties:\n              ignoreEpisodesWithFiles:\n                type: boolean\n                nullable: true\n              ignoreEpisodesWithoutFiles:\n                type: boolean\n                nullable: true\n              searchForMissingEpisodes:\n                type: boolean\n                nullable: true\n    UserSettingsNotifications:\n      type: object\n      properties:\n        notificationTypes:\n          $ref: '#/components/schemas/NotificationAgentTypes'\n        emailEnabled:\n          type: boolean\n        pgpKey:\n          type: string\n          nullable: true\n        discordEnabled:\n          type: boolean\n        discordEnabledTypes:\n          type: number\n          nullable: true\n        discordId:\n          type: string\n          nullable: true\n        pushbulletAccessToken:\n          type: string\n          nullable: true\n        pushoverApplicationToken:\n          type: string\n          nullable: true\n        pushoverUserKey:\n          type: string\n          nullable: true\n        pushoverSound:\n          type: string\n          nullable: true\n        telegramEnabled:\n          type: boolean\n        telegramBotUsername:\n          type: string\n          nullable: true\n        telegramChatId:\n          type: string\n          nullable: true\n        telegramMessageThreadId:\n          type: string\n          nullable: true\n        telegramSendSilently:\n          type: boolean\n          nullable: true\n    NotificationAgentTypes:\n      type: object\n      properties:\n        discord:\n          type: number\n        email:\n          type: number\n        pushbullet:\n          type: number\n        pushover:\n          type: number\n        slack:\n          type: number\n        telegram:\n          type: number\n        webhook:\n          type: number\n        webpush:\n          type: number\n    WatchProviders:\n      type: array\n      items:\n        type: object\n        properties:\n          iso_3166_1:\n            type: string\n          link:\n            type: string\n          buy:\n            type: array\n            items:\n              $ref: '#/components/schemas/WatchProviderDetails'\n          flatrate:\n            items:\n              $ref: '#/components/schemas/WatchProviderDetails'\n    WatchProviderDetails:\n      type: object\n      properties:\n        displayPriority:\n          type: number\n        logoPath:\n          type: string\n        id:\n          type: number\n        name:\n          type: string\n    Issue:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        issueType:\n          type: number\n          example: 1\n        media:\n          $ref: '#/components/schemas/MediaInfo'\n        createdBy:\n          $ref: '#/components/schemas/User'\n        modifiedBy:\n          $ref: '#/components/schemas/User'\n        comments:\n          type: array\n          items:\n            $ref: '#/components/schemas/IssueComment'\n    IssueComment:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        user:\n          $ref: '#/components/schemas/User'\n        message:\n          type: string\n          example: A comment\n    DiscoverSlider:\n      type: object\n      properties:\n        id:\n          type: number\n          example: 1\n        type:\n          type: number\n          example: 1\n        title:\n          type: string\n          nullable: true\n        isBuiltIn:\n          type: boolean\n        enabled:\n          type: boolean\n        data:\n          type: string\n          example: '1234'\n          nullable: true\n      required:\n        - type\n        - enabled\n        - title\n        - data\n    WatchProviderRegion:\n      type: object\n      properties:\n        iso_3166_1:\n          type: string\n        english_name:\n          type: string\n        native_name:\n          type: string\n    OverrideRule:\n      type: object\n      properties:\n        id:\n          type: string\n    Certification:\n      type: object\n      properties:\n        certification:\n          type: string\n          example: 'PG-13'\n        meaning:\n          type: string\n          example: 'Some material may be inappropriate for children under 13.'\n          nullable: true\n        order:\n          type: number\n          example: 3\n          nullable: true\n      required:\n        - certification\n\n    CertificationResponse:\n      type: object\n      properties:\n        certifications:\n          type: object\n          additionalProperties:\n            type: array\n            items:\n              $ref: '#/components/schemas/Certification'\n      example:\n        certifications:\n          US:\n            - certification: 'G'\n              meaning: 'All ages admitted'\n              order: 1\n            - certification: 'PG'\n              meaning: 'Some material may not be suitable for children under 10.'\n              order: 2\n  securitySchemes:\n    cookieAuth:\n      type: apiKey\n      name: connect.sid\n      in: cookie\n    apiKey:\n      type: apiKey\n      in: header\n      name: X-Api-Key\n\npaths:\n  /status:\n    get:\n      summary: Get Seerr status\n      description: Returns the current Seerr status in a JSON object.\n      security: []\n      tags:\n        - public\n      responses:\n        '200':\n          description: Returned status\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  version:\n                    type: string\n                    example: 1.0.0\n                  commitTag:\n                    type: string\n                  updateAvailable:\n                    type: boolean\n                  commitsBehind:\n                    type: number\n                  restartRequired:\n                    type: boolean\n  /status/appdata:\n    get:\n      summary: Get application data volume status\n      description: For Docker installs, returns whether or not the volume mount was configured properly. Always returns true for non-Docker installs.\n      security: []\n      tags:\n        - public\n      responses:\n        '200':\n          description: Application data volume status and path\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  appData:\n                    type: boolean\n                    example: true\n                  appDataPath:\n                    type: string\n                    example: /app/config\n                  appDataPermissions:\n                    type: boolean\n                    example: true\n  /settings/main:\n    get:\n      summary: Get main settings\n      description: Retrieves all main settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MainSettings'\n    post:\n      summary: Update main settings\n      description: Updates main settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/MainSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MainSettings'\n  /settings/network:\n    get:\n      summary: Get network settings\n      description: Retrieves all network settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MainSettings'\n    post:\n      summary: Update network settings\n      description: Updates network settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/NetworkSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/NetworkSettings'\n  /settings/main/regenerate:\n    post:\n      summary: Get main settings with newly-generated API key\n      description: Returns main settings in a JSON object, using the new API key.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MainSettings'\n  /settings/jellyfin:\n    get:\n      summary: Get Jellyfin settings\n      description: Retrieves current Jellyfin settings.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/JellyfinSettings'\n    post:\n      summary: Update Jellyfin settings\n      description: Updates Jellyfin settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/JellyfinSettings'\n      responses:\n        '200':\n          description: 'Values were successfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/JellyfinSettings'\n  /settings/jellyfin/library:\n    get:\n      summary: Get Jellyfin libraries\n      description: Returns a list of Jellyfin libraries in a JSON array.\n      tags:\n        - settings\n      parameters:\n        - in: query\n          name: sync\n          description: Syncs the current libraries with the current Jellyfin server\n          schema:\n            type: string\n            nullable: true\n        - in: query\n          name: enable\n          explode: false\n          allowReserved: true\n          description: Comma separated list of libraries to enable. Any libraries not passed will be disabled!\n          schema:\n            type: string\n            nullable: true\n      responses:\n        '200':\n          description: 'Jellyfin libraries returned'\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/JellyfinLibrary'\n  /settings/jellyfin/users:\n    get:\n      summary: Get Jellyfin Users\n      description: Returns a list of Jellyfin Users in a JSON array.\n      tags:\n        - settings\n        - users\n      responses:\n        '200':\n          description: Jellyfin users returned\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    username:\n                      type: string\n                    id:\n                      type: string\n                    thumb:\n                      type: string\n                    email:\n                      type: string\n  /settings/jellyfin/sync:\n    get:\n      summary: Get status of full Jellyfin library sync\n      description: Returns sync progress in a JSON array.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Status of Jellyfin sync\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  running:\n                    type: boolean\n                    example: false\n                  progress:\n                    type: number\n                    example: 0\n                  total:\n                    type: number\n                    example: 100\n                  currentLibrary:\n                    $ref: '#/components/schemas/JellyfinLibrary'\n                  libraries:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/JellyfinLibrary'\n    post:\n      summary: Start full Jellyfin library sync\n      description: Runs a full Jellyfin library sync and returns the progress in a JSON array.\n      tags:\n        - settings\n      requestBody:\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                cancel:\n                  type: boolean\n                  example: false\n                start:\n                  type: boolean\n                  example: false\n      responses:\n        '200':\n          description: Status of Jellyfin sync\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  running:\n                    type: boolean\n                    example: false\n                  progress:\n                    type: number\n                    example: 0\n                  total:\n                    type: number\n                    example: 100\n                  currentLibrary:\n                    $ref: '#/components/schemas/JellyfinLibrary'\n                  libraries:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/JellyfinLibrary'\n  /settings/plex:\n    get:\n      summary: Get Plex settings\n      description: Retrieves current Plex settings.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PlexSettings'\n    post:\n      summary: Update Plex settings\n      description: Updates Plex settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/PlexSettings'\n      responses:\n        '200':\n          description: 'Values were successfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PlexSettings'\n  /settings/plex/library:\n    get:\n      summary: Get Plex libraries\n      description: Returns a list of Plex libraries in a JSON array.\n      tags:\n        - settings\n      parameters:\n        - in: query\n          name: sync\n          description: Syncs the current libraries with the current Plex server\n          schema:\n            type: string\n            nullable: true\n        - in: query\n          name: enable\n          explode: false\n          allowReserved: true\n          description: Comma separated list of libraries to enable. Any libraries not passed will be disabled!\n          schema:\n            type: string\n            nullable: true\n      responses:\n        '200':\n          description: 'Plex libraries returned'\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/PlexLibrary'\n  /settings/plex/sync:\n    get:\n      summary: Get status of full Plex library scan\n      description: Returns scan progress in a JSON array.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Status of Plex scan\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  running:\n                    type: boolean\n                    example: false\n                  progress:\n                    type: number\n                    example: 0\n                  total:\n                    type: number\n                    example: 100\n                  currentLibrary:\n                    $ref: '#/components/schemas/PlexLibrary'\n                  libraries:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/PlexLibrary'\n    post:\n      summary: Start full Plex library scan\n      description: Runs a full Plex library scan and returns the progress in a JSON array.\n      tags:\n        - settings\n      requestBody:\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                cancel:\n                  type: boolean\n                  example: false\n                start:\n                  type: boolean\n                  example: false\n      responses:\n        '200':\n          description: Status of Plex scan\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  running:\n                    type: boolean\n                    example: false\n                  progress:\n                    type: number\n                    example: 0\n                  total:\n                    type: number\n                    example: 100\n                  currentLibrary:\n                    $ref: '#/components/schemas/PlexLibrary'\n                  libraries:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/PlexLibrary'\n  /settings/plex/devices/servers:\n    get:\n      summary: Gets the user's available Plex servers\n      description: Returns a list of available Plex servers and their connectivity state\n      tags:\n        - settings\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/PlexDevice'\n  /settings/plex/users:\n    get:\n      summary: Get Plex users\n      description: |\n        Returns a list of Plex users in a JSON array.\n\n        Requires the `MANAGE_USERS` permission.\n      tags:\n        - settings\n        - users\n      responses:\n        '200':\n          description: Plex users\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    id:\n                      type: string\n                    title:\n                      type: string\n                    username:\n                      type: string\n                    email:\n                      type: string\n                    thumb:\n                      type: string\n  /settings/metadatas:\n    get:\n      summary: Get Metadata settings\n      description: Retrieves current Metadata settings.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MetadataSettings'\n    put:\n      summary: Update Metadata settings\n      description: Updates Metadata settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/MetadataSettings'\n      responses:\n        '200':\n          description: 'Values were successfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MetadataSettings'\n  /settings/metadatas/test:\n    post:\n      summary: Test Provider configuration\n      description: Tests if the TVDB configuration is valid. Returns a list of available languages on success.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                tmdb:\n                  type: boolean\n                  example: true\n                tvdb:\n                  type: boolean\n                  example: true\n      responses:\n        '200':\n          description: Succesfully connected to TVDB\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  message:\n                    type: string\n                    example: 'Successfully connected to TVDB'\n  /settings/tautulli:\n    get:\n      summary: Get Tautulli settings\n      description: Retrieves current Tautulli settings.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/TautulliSettings'\n    post:\n      summary: Update Tautulli settings\n      description: Updates Tautulli settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/TautulliSettings'\n      responses:\n        '200':\n          description: 'Values were successfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/TautulliSettings'\n  /settings/radarr:\n    get:\n      summary: Get Radarr settings\n      description: Returns all Radarr settings in a JSON array.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: 'Values were returned'\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/RadarrSettings'\n    post:\n      summary: Create Radarr instance\n      description: Creates a new Radarr instance from the request body.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/RadarrSettings'\n      responses:\n        '201':\n          description: 'New Radarr instance created'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RadarrSettings'\n  /settings/radarr/test:\n    post:\n      summary: Test Radarr configuration\n      description: Tests if the Radarr configuration is valid. Returns profiles and root folders on success.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                hostname:\n                  type: string\n                  example: '127.0.0.1'\n                port:\n                  type: number\n                  example: 7878\n                apiKey:\n                  type: string\n                  example: yourapikey\n                useSsl:\n                  type: boolean\n                  example: false\n                baseUrl:\n                  type: string\n              required:\n                - hostname\n                - port\n                - apiKey\n                - useSsl\n      responses:\n        '200':\n          description: Succesfully connected to Radarr instance\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  profiles:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/ServiceProfile'\n  /settings/radarr/{radarrId}:\n    put:\n      summary: Update Radarr instance\n      description: Updates an existing Radarr instance with the provided values.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: radarrId\n          required: true\n          schema:\n            type: integer\n          description: Radarr instance ID\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/RadarrSettings'\n      responses:\n        '200':\n          description: 'Radarr instance updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RadarrSettings'\n    delete:\n      summary: Delete Radarr instance\n      description: Deletes an existing Radarr instance based on the radarrId parameter.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: radarrId\n          required: true\n          schema:\n            type: integer\n          description: Radarr instance ID\n      responses:\n        '200':\n          description: 'Radarr instance updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RadarrSettings'\n  /settings/radarr/{radarrId}/profiles:\n    get:\n      summary: Get available Radarr profiles\n      description: Returns a list of profiles available on the Radarr server instance in a JSON array.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: radarrId\n          required: true\n          schema:\n            type: integer\n          description: Radarr instance ID\n      responses:\n        '200':\n          description: Returned list of profiles\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/ServiceProfile'\n  /settings/sonarr:\n    get:\n      summary: Get Sonarr settings\n      description: Returns all Sonarr settings in a JSON array.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: 'Values were returned'\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/SonarrSettings'\n    post:\n      summary: Create Sonarr instance\n      description: Creates a new Sonarr instance from the request body.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/SonarrSettings'\n      responses:\n        '201':\n          description: 'New Sonarr instance created'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/SonarrSettings'\n  /settings/sonarr/test:\n    post:\n      summary: Test Sonarr configuration\n      description: Tests if the Sonarr configuration is valid. Returns profiles and root folders on success.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                hostname:\n                  type: string\n                  example: '127.0.0.1'\n                port:\n                  type: number\n                  example: 8989\n                apiKey:\n                  type: string\n                  example: yourapikey\n                useSsl:\n                  type: boolean\n                  example: false\n                baseUrl:\n                  type: string\n              required:\n                - hostname\n                - port\n                - apiKey\n                - useSsl\n      responses:\n        '200':\n          description: Succesfully connected to Sonarr instance\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  profiles:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/ServiceProfile'\n  /settings/sonarr/{sonarrId}:\n    put:\n      summary: Update Sonarr instance\n      description: Updates an existing Sonarr instance with the provided values.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: sonarrId\n          required: true\n          schema:\n            type: integer\n          description: Sonarr instance ID\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/SonarrSettings'\n      responses:\n        '200':\n          description: 'Sonarr instance updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/SonarrSettings'\n    delete:\n      summary: Delete Sonarr instance\n      description: Deletes an existing Sonarr instance based on the sonarrId parameter.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: sonarrId\n          required: true\n          schema:\n            type: integer\n          description: Sonarr instance ID\n      responses:\n        '200':\n          description: 'Sonarr instance updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/SonarrSettings'\n  /settings/public:\n    get:\n      summary: Get public settings\n      security: []\n      description: Returns settings that are not protected or sensitive. Mainly used to determine if the application has been configured for the first time.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Public settings returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PublicSettings'\n  /settings/initialize:\n    post:\n      summary: Initialize application\n      description: Sets the app as initialized, allowing the user to navigate to pages other than the setup page.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Public settings returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PublicSettings'\n  /settings/jobs:\n    get:\n      summary: Get scheduled jobs\n      description: Returns list of all scheduled jobs and details about their next execution time in a JSON array.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Scheduled jobs returned\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/Job'\n  /settings/jobs/{jobId}/run:\n    post:\n      summary: Invoke a specific job\n      description: Invokes a specific job to run. Will return the new job status in JSON format.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: jobId\n          required: true\n          schema:\n            type: string\n      responses:\n        '200':\n          description: Invoked job returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Job'\n  /settings/jobs/{jobId}/cancel:\n    post:\n      summary: Cancel a specific job\n      description: Cancels a specific job. Will return the new job status in JSON format.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: jobId\n          required: true\n          schema:\n            type: string\n      responses:\n        '200':\n          description: Canceled job returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Job'\n  /settings/jobs/{jobId}/schedule:\n    post:\n      summary: Modify job schedule\n      description: Re-registers the job with the schedule specified. Will return the job in JSON format.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: jobId\n          required: true\n          schema:\n            type: string\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                schedule:\n                  type: string\n                  example: '0 */5 * * * *'\n      responses:\n        '200':\n          description: Rescheduled job\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Job'\n  /settings/cache:\n    get:\n      summary: Get a list of active caches\n      description: Retrieves a list of all active caches and their current stats.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Caches returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  imageCache:\n                    type: object\n                    properties:\n                      tmdb:\n                        type: object\n                        properties:\n                          size:\n                            type: number\n                            example: 123456\n                          imageCount:\n                            type: number\n                            example: 123\n                      avatar:\n                        type: object\n                        properties:\n                          size:\n                            type: number\n                            example: 123456\n                          imageCount:\n                            type: number\n                            example: 123\n                  dnsCache:\n                    type: object\n                    properties:\n                      stats:\n                        type: object\n                        properties:\n                          size:\n                            type: number\n                            example: 1\n                          maxSize:\n                            type: number\n                            example: 500\n                          hits:\n                            type: number\n                            example: 19\n                          misses:\n                            type: number\n                            example: 1\n                          failures:\n                            type: number\n                            example: 0\n                          ipv4Fallbacks:\n                            type: number\n                            example: 0\n                          hitRate:\n                            type: number\n                            example: 0.95\n                      entries:\n                        type: array\n                        additionalProperties:\n                          type: object\n                          properties:\n                            addresses:\n                              type: object\n                              properties:\n                                ipv4:\n                                  type: number\n                                  example: 1\n                                ipv6:\n                                  type: number\n                                  example: 1\n                            activeAddress:\n                              type: string\n                              example: 127.0.0.1\n                            family:\n                              type: number\n                              example: 4\n                            age:\n                              type: number\n                              example: 10\n                            ttl:\n                              type: number\n                              example: 10\n                            networkErrors:\n                              type: number\n                              example: 0\n                            hits:\n                              type: number\n                              example: 1\n                            misses:\n                              type: number\n                              example: 1\n                  apiCaches:\n                    type: array\n                    items:\n                      type: object\n                      properties:\n                        id:\n                          type: string\n                          example: cache-id\n                        name:\n                          type: string\n                          example: cache name\n                        stats:\n                          type: object\n                          properties:\n                            hits:\n                              type: number\n                            misses:\n                              type: number\n                            keys:\n                              type: number\n                            ksize:\n                              type: number\n                            vsize:\n                              type: number\n  /settings/cache/{cacheId}/flush:\n    post:\n      summary: Flush a specific cache\n      description: Flushes all data from the cache ID provided\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: cacheId\n          required: true\n          schema:\n            type: string\n      responses:\n        '204':\n          description: 'Flushed cache'\n  /settings/cache/dns/{dnsEntry}/flush:\n    post:\n      summary: Flush a specific DNS cache entry\n      description: Flushes a specific DNS cache entry\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: dnsEntry\n          required: true\n          schema:\n            type: string\n      responses:\n        '204':\n          description: 'Flushed dns cache'\n  /settings/logs:\n    get:\n      summary: Returns logs\n      description: Returns list of all log items and details\n      tags:\n        - settings\n      parameters:\n        - in: query\n          name: take\n          schema:\n            type: number\n            nullable: true\n            example: 25\n        - in: query\n          name: skip\n          schema:\n            type: number\n            nullable: true\n            example: 0\n        - in: query\n          name: filter\n          schema:\n            type: string\n            nullable: true\n            enum: [debug, info, warn, error]\n            default: debug\n        - in: query\n          name: search\n          schema:\n            type: string\n            nullable: true\n            example: plex\n      responses:\n        '200':\n          description: Server log returned\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    label:\n                      type: string\n                      example: server\n                    level:\n                      type: string\n                      example: info\n                    message:\n                      type: string\n                      example: Server ready on port 5055\n                    timestamp:\n                      type: string\n                      example: '2020-12-15T16:20:00.069Z'\n  /settings/notifications/email:\n    get:\n      summary: Get email notification settings\n      description: Returns current email notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned email settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/NotificationEmailSettings'\n    post:\n      summary: Update email notification settings\n      description: Updates email notification settings with provided values\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/NotificationEmailSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/NotificationEmailSettings'\n  /settings/notifications/email/test:\n    post:\n      summary: Test email settings\n      description: Sends a test notification to the email agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/NotificationEmailSettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/notifications/discord:\n    get:\n      summary: Get Discord notification settings\n      description: Returns current Discord notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned Discord settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/DiscordSettings'\n    post:\n      summary: Update Discord notification settings\n      description: Updates Discord notification settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/DiscordSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/DiscordSettings'\n  /settings/notifications/discord/test:\n    post:\n      summary: Test Discord settings\n      description: Sends a test notification to the Discord agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/DiscordSettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/notifications/pushbullet:\n    get:\n      summary: Get Pushbullet notification settings\n      description: Returns current Pushbullet notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned Pushbullet settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PushbulletSettings'\n    post:\n      summary: Update Pushbullet notification settings\n      description: Update Pushbullet notification settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/PushbulletSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PushbulletSettings'\n  /settings/notifications/pushbullet/test:\n    post:\n      summary: Test Pushbullet settings\n      description: Sends a test notification to the Pushbullet agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/PushbulletSettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/notifications/pushover:\n    get:\n      summary: Get Pushover notification settings\n      description: Returns current Pushover notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned Pushover settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PushoverSettings'\n    post:\n      summary: Update Pushover notification settings\n      description: Update Pushover notification settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/PushoverSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PushoverSettings'\n  /settings/notifications/pushover/test:\n    post:\n      summary: Test Pushover settings\n      description: Sends a test notification to the Pushover agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/PushoverSettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/notifications/pushover/sounds:\n    get:\n      summary: Get Pushover sounds\n      description: Returns valid Pushover sound options in a JSON array.\n      tags:\n        - settings\n      parameters:\n        - in: query\n          name: token\n          required: true\n          schema:\n            type: string\n            nullable: false\n      responses:\n        '200':\n          description: Returned Pushover settings\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    name:\n                      type: string\n                    description:\n                      type: string\n  /settings/notifications/gotify:\n    get:\n      summary: Get Gotify notification settings\n      description: Returns current Gotify notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned Gotify settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/GotifySettings'\n    post:\n      summary: Update Gotify notification settings\n      description: Update Gotify notification settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/GotifySettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/GotifySettings'\n  /settings/notifications/gotify/test:\n    post:\n      summary: Test Gotify settings\n      description: Sends a test notification to the Gotify agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/GotifySettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/notifications/ntfy:\n    get:\n      summary: Get ntfy.sh notification settings\n      description: Returns current ntfy.sh notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned ntfy.sh settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/NtfySettings'\n    post:\n      summary: Update ntfy.sh notification settings\n      description: Update ntfy.sh notification settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/NtfySettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/NtfySettings'\n  /settings/notifications/ntfy/test:\n    post:\n      summary: Test ntfy.sh settings\n      description: Sends a test notification to the ntfy.sh agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/NtfySettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/notifications/slack:\n    get:\n      summary: Get Slack notification settings\n      description: Returns current Slack notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned slack settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/SlackSettings'\n    post:\n      summary: Update Slack notification settings\n      description: Updates Slack notification settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/SlackSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/SlackSettings'\n  /settings/notifications/slack/test:\n    post:\n      summary: Test Slack settings\n      description: Sends a test notification to the Slack agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/SlackSettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/notifications/telegram:\n    get:\n      summary: Get Telegram notification settings\n      description: Returns current Telegram notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned Telegram settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/TelegramSettings'\n    post:\n      summary: Update Telegram notification settings\n      description: Update Telegram notification settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/TelegramSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/TelegramSettings'\n  /settings/notifications/telegram/test:\n    post:\n      summary: Test Telegram settings\n      description: Sends a test notification to the Telegram agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/TelegramSettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/notifications/webpush:\n    get:\n      summary: Get Web Push notification settings\n      description: Returns current Web Push notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned web push settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/WebPushSettings'\n    post:\n      summary: Update Web Push notification settings\n      description: Updates Web Push notification settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/WebPushSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/WebPushSettings'\n  /settings/notifications/webpush/test:\n    post:\n      summary: Test Web Push settings\n      description: Sends a test notification to the Web Push agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/WebPushSettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/notifications/webhook:\n    get:\n      summary: Get webhook notification settings\n      description: Returns current webhook notification settings in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned webhook settings\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/WebhookSettings'\n    post:\n      summary: Update webhook notification settings\n      description: Updates webhook notification settings with the provided values.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/WebhookSettings'\n      responses:\n        '200':\n          description: 'Values were sucessfully updated'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/WebhookSettings'\n  /settings/notifications/webhook/test:\n    post:\n      summary: Test webhook settings\n      description: Sends a test notification to the webhook agent.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/WebhookSettings'\n      responses:\n        '204':\n          description: Test notification attempted\n  /settings/discover:\n    get:\n      summary: Get all discover sliders\n      description: Returns all discovery sliders. Built-in and custom made.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned all discovery sliders\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/DiscoverSlider'\n    post:\n      summary: Batch update all sliders.\n      description: |\n        Batch update all sliders at once. Should also be used for creation. Will only update sliders provided\n        and will not delete any sliders not present in the request. If a slider is missing a required field,\n        it will be ignored. Requires the `ADMIN` permission.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: array\n              items:\n                $ref: '#/components/schemas/DiscoverSlider'\n      responses:\n        '200':\n          description: Returned all newly updated discovery sliders\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/DiscoverSlider'\n  /settings/discover/{sliderId}:\n    put:\n      summary: Update a single slider\n      description: |\n        Updates a single slider and return the newly updated slider. Requires the `ADMIN` permission.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: sliderId\n          required: true\n          schema:\n            type: number\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                title:\n                  type: string\n                  example: 'Slider Title'\n                type:\n                  type: number\n                  example: 1\n                data:\n                  type: string\n                  example: '1'\n      responses:\n        '200':\n          description: Returns newly added discovery slider\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/DiscoverSlider'\n    delete:\n      summary: Delete slider by ID\n      description: Deletes the slider with the provided sliderId. Requires the `ADMIN` permission.\n      tags:\n        - settings\n      parameters:\n        - in: path\n          name: sliderId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: Slider successfully deleted\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/DiscoverSlider'\n  /settings/discover/add:\n    post:\n      summary: Add a new slider\n      description: |\n        Add a single slider and return the newly created slider. Requires the `ADMIN` permission.\n      tags:\n        - settings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                title:\n                  type: string\n                  example: 'New Slider'\n                type:\n                  type: number\n                  example: 1\n                data:\n                  type: string\n                  example: '1'\n      responses:\n        '200':\n          description: Returns newly added discovery slider\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/DiscoverSlider'\n  /settings/discover/reset:\n    get:\n      summary: Reset all discover sliders\n      description: Resets all discovery sliders to the default values. Requires the `ADMIN` permission.\n      tags:\n        - settings\n      responses:\n        '204':\n          description: All sliders reset to defaults\n  /settings/about:\n    get:\n      summary: Get server stats\n      description: Returns current server stats in a JSON object.\n      tags:\n        - settings\n      responses:\n        '200':\n          description: Returned about settings\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  version:\n                    type: string\n                    example: '1.0.0'\n                  totalRequests:\n                    type: number\n                    example: 100\n                  totalMediaItems:\n                    type: number\n                    example: 100\n                  tz:\n                    type: string\n                    nullable: true\n                    example: Asia/Tokyo\n                  appDataPath:\n                    type: string\n                    example: /app/config\n  /auth/me:\n    get:\n      summary: Get logged-in user\n      description: Returns the currently logged-in user.\n      tags:\n        - auth\n        - users\n      responses:\n        '200':\n          description: Object containing the logged-in user in JSON\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n  /auth/plex:\n    post:\n      summary: Sign in using a Plex token\n      description: Takes an `authToken` (Plex token) to log the user in. Generates a session cookie for use in further requests. If the user does not exist, and there are no other users, then a user will be created with full admin privileges. If a user logs in with access to the main Plex server, they will also have an account created, but without any permissions.\n      security: []\n      tags:\n        - auth\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                authToken:\n                  type: string\n              required:\n                - authToken\n  /auth/jellyfin:\n    post:\n      summary: Sign in using a Jellyfin username and password\n      description: Takes the user's username and password to log the user in. Generates a session cookie for use in further requests. If the user does not exist, and there are no other users, then a user will be created with full admin privileges. If a user logs in with access to the Jellyfin server, they will also have an account created, but without any permissions.\n      security: []\n      tags:\n        - auth\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                username:\n                  type: string\n                password:\n                  type: string\n                hostname:\n                  type: string\n                email:\n                  type: string\n                serverType:\n                  type: number\n              required:\n                - username\n                - password\n  /auth/local:\n    post:\n      summary: Sign in using a local account\n      description: Takes an `email` and a `password` to log the user in. Generates a session cookie for use in further requests.\n      security: []\n      tags:\n        - auth\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                email:\n                  type: string\n                password:\n                  type: string\n              required:\n                - email\n                - password\n  /auth/logout:\n    post:\n      summary: Sign out and clear session cookie\n      description: Completely clear the session cookie and associated values, effectively signing the user out.\n      tags:\n        - auth\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  status:\n                    type: string\n                    example: 'ok'\n  /auth/reset-password:\n    post:\n      summary: Send a reset password email\n      description: Sends a reset password email to the email if the user exists\n      security: []\n      tags:\n        - users\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  status:\n                    type: string\n                    example: 'ok'\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                email:\n                  type: string\n              required:\n                - email\n  /auth/reset-password/{guid}:\n    post:\n      summary: Reset the password for a user\n      description: Resets the password for a user if the given guid is connected to a user\n      security: []\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: guid\n          required: true\n          schema:\n            type: string\n            example: '9afef5a7-ec89-4d5f-9397-261e96970b50'\n      responses:\n        '200':\n          description: OK\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  status:\n                    type: string\n                    example: 'ok'\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                password:\n                  type: string\n              required:\n                - password\n  /user:\n    get:\n      summary: Get all users\n      description: Returns all users in a JSON object.\n      tags:\n        - users\n      parameters:\n        - in: query\n          name: take\n          schema:\n            type: number\n            nullable: true\n            example: 20\n        - in: query\n          name: skip\n          schema:\n            type: number\n            nullable: true\n            example: 0\n        - in: query\n          name: sort\n          schema:\n            type: string\n            enum: [created, updated, requests, displayname]\n            default: created\n        - in: query\n          name: q\n          required: false\n          schema:\n            type: string\n        - in: query\n          name: includeIds\n          required: false\n          schema:\n            type: string\n      responses:\n        '200':\n          description: A JSON array of all users\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  pageInfo:\n                    $ref: '#/components/schemas/PageInfo'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/User'\n    post:\n      summary: Create new user\n      description: |\n        Creates a new user. Requires the `MANAGE_USERS` permission.\n      tags:\n        - users\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                email:\n                  type: string\n                  example: 'hey@itsme.com'\n                username:\n                  type: string\n                permissions:\n                  type: number\n      responses:\n        '201':\n          description: The created user\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n    put:\n      summary: Update batch of users\n      description: |\n        Update users with given IDs with provided values in request `body.settings`. You cannot update users' Plex tokens through this request.\n\n        Requires the `MANAGE_USERS` permission.\n      tags:\n        - users\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                ids:\n                  type: array\n                  items:\n                    type: integer\n                permissions:\n                  type: integer\n      responses:\n        '200':\n          description: Successfully updated user details\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/User'\n  /user/import-from-plex:\n    post:\n      summary: Import all users from Plex\n      description: |\n        Fetches and imports users from the Plex server. If a list of Plex IDs is provided in the request body, only the specified users will be imported. Otherwise, all users will be imported.\n\n        Requires the `MANAGE_USERS` permission.\n      tags:\n        - users\n      requestBody:\n        required: false\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                plexIds:\n                  type: array\n                  items:\n                    type: string\n      responses:\n        '201':\n          description: A list of the newly created users\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/User'\n  /user/import-from-jellyfin:\n    post:\n      summary: Import all users from Jellyfin\n      description: |\n        Fetches and imports users from the Jellyfin server.\n\n        Requires the `MANAGE_USERS` permission.\n      tags:\n        - users\n      requestBody:\n        required: false\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                jellyfinUserIds:\n                  type: array\n                  items:\n                    type: string\n      responses:\n        '201':\n          description: A list of the newly created users\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/User'\n  /user/registerPushSubscription:\n    post:\n      summary: Register a web push /user/registerPushSubscription\n      description: Registers a web push subscription for the logged-in user\n      tags:\n        - users\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                endpoint:\n                  type: string\n                auth:\n                  type: string\n                p256dh:\n                  type: string\n                userAgent:\n                  type: string\n              required:\n                - endpoint\n                - auth\n                - p256dh\n      responses:\n        '204':\n          description: Successfully registered push subscription\n  /user/{userId}/pushSubscriptions:\n    get:\n      summary: Get all web push notification settings for a user\n      description: |\n        Returns all web push notification settings for a user in a JSON object.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: User web push notification settings in JSON\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  endpoint:\n                    type: string\n                  p256dh:\n                    type: string\n                  auth:\n                    type: string\n                  userAgent:\n                    type: string\n  /user/{userId}/pushSubscription/{endpoint}:\n    get:\n      summary: Get web push notification settings for a user\n      description: |\n        Returns web push notification settings for a user in a JSON object.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n        - in: path\n          name: endpoint\n          required: true\n          schema:\n            type: string\n      responses:\n        '200':\n          description: User web push notification settings in JSON\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  endpoint:\n                    type: string\n                  p256dh:\n                    type: string\n                  auth:\n                    type: string\n                  userAgent:\n                    type: string\n    delete:\n      summary: Delete user push subscription by key\n      description: Deletes the user push subscription with the provided key.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n        - in: path\n          name: endpoint\n          required: true\n          schema:\n            type: string\n      responses:\n        '204':\n          description: Successfully removed user push subscription\n  /user/{userId}:\n    get:\n      summary: Get user by ID\n      description: |\n        Retrieves user details in a JSON object. Requires the `MANAGE_USERS` permission.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: Users details in JSON\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n    put:\n      summary: Update a user by user ID\n      description: |\n        Update a user with the provided values. You cannot update a user's Plex token through this request.\n\n        Requires the `MANAGE_USERS` permission.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/User'\n      responses:\n        '200':\n          description: Successfully updated user details\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n    delete:\n      summary: Delete user by ID\n      description: Deletes the user with the provided userId. Requires the `MANAGE_USERS` permission.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: User successfully deleted\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n  /user/{userId}/requests:\n    get:\n      summary: Get requests for a specific user\n      description: |\n        Retrieves a user's requests in a JSON object.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n        - in: query\n          name: take\n          schema:\n            type: number\n            nullable: true\n            example: 20\n        - in: query\n          name: skip\n          schema:\n            type: number\n            nullable: true\n            example: 0\n      responses:\n        '200':\n          description: User's requests returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  pageInfo:\n                    $ref: '#/components/schemas/PageInfo'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MediaRequest'\n  /user/{userId}/quota:\n    get:\n      summary: Get quotas for a specific user\n      description: |\n        Returns quota details for a user in a JSON object. Requires `MANAGE_USERS` permission if viewing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: User quota details in JSON\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  movie:\n                    type: object\n                    properties:\n                      days:\n                        type: number\n                        example: 7\n                      limit:\n                        type: number\n                        example: 10\n                      used:\n                        type: number\n                        example: 6\n                      remaining:\n                        type: number\n                        example: 4\n                      restricted:\n                        type: boolean\n                        example: false\n                  tv:\n                    type: object\n                    properties:\n                      days:\n                        type: number\n                        example: 7\n                      limit:\n                        type: number\n                        example: 10\n                      used:\n                        type: number\n                        example: 6\n                      remaining:\n                        type: number\n                        example: 4\n                      restricted:\n                        type: boolean\n                        example: false\n  /blocklist:\n    get:\n      summary: Returns blocklisted items\n      description: Returns list of all blocklisted media\n      tags:\n        - blocklist\n      parameters:\n        - in: query\n          name: take\n          schema:\n            type: number\n            nullable: true\n            example: 25\n        - in: query\n          name: skip\n          schema:\n            type: number\n            nullable: true\n            example: 0\n        - in: query\n          name: search\n          schema:\n            type: string\n            nullable: true\n            example: dune\n        - in: query\n          name: filter\n          schema:\n            type: string\n            enum: [all, manual, blocklistedTags]\n            default: manual\n      responses:\n        '200':\n          description: Blocklisted items returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  pageInfo:\n                    $ref: '#/components/schemas/PageInfo'\n                  results:\n                    type: array\n                    items:\n                      type: object\n                      properties:\n                        user:\n                          $ref: '#/components/schemas/User'\n                        createdAt:\n                          type: string\n                          example: 2024-04-21T01:55:44.000Z\n                        id:\n                          type: number\n                          example: 1\n                        mediaType:\n                          type: string\n                          example: movie\n                        title:\n                          type: string\n                          example: Dune\n                        tmdbId:\n                          type: number\n                          example: 438631\n    post:\n      summary: Add media to blocklist\n      tags:\n        - blocklist\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/Blocklist'\n      responses:\n        '201':\n          description: Item succesfully blocklisted\n        '412':\n          description: Item has already been blocklisted\n  /blocklist/{tmdbId}:\n    get:\n      summary: Get media from blocklist\n      tags:\n        - blocklist\n      parameters:\n        - in: path\n          name: tmdbId\n          description: tmdbId ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n        - in: query\n          name: mediaType\n          required: true\n          schema:\n            type: string\n            enum:\n              - movie\n              - tv\n      responses:\n        '200':\n          description: Blocklist details in JSON\n    delete:\n      summary: Remove media from blocklist\n      tags:\n        - blocklist\n      parameters:\n        - in: path\n          name: tmdbId\n          description: tmdbId ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n        - in: query\n          name: mediaType\n          required: true\n          schema:\n            type: string\n            enum:\n              - movie\n              - tv\n      responses:\n        '204':\n          description: Succesfully removed media item\n  /blacklist:\n    get:\n      summary: Returns blocklisted items\n      description: |\n        **DEPRECATED**: Use `/blocklist` instead. This endpoint will be deprecated soon.\n      deprecated: true\n      tags:\n        - blocklist\n      parameters:\n        - in: query\n          name: take\n          schema:\n            type: number\n            nullable: true\n            example: 25\n        - in: query\n          name: skip\n          schema:\n            type: number\n            nullable: true\n            example: 0\n        - in: query\n          name: search\n          schema:\n            type: string\n            nullable: true\n            example: dune\n        - in: query\n          name: filter\n          schema:\n            type: string\n            enum: [all, manual, blocklistedTags]\n            default: manual\n      responses:\n        '200':\n          description: Blocklisted items returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  pageInfo:\n                    $ref: '#/components/schemas/PageInfo'\n                  results:\n                    type: array\n                    items:\n                      type: object\n                      properties:\n                        user:\n                          $ref: '#/components/schemas/User'\n                        createdAt:\n                          type: string\n                          example: 2024-04-21T01:55:44.000Z\n                        id:\n                          type: number\n                          example: 1\n                        mediaType:\n                          type: string\n                          example: movie\n                        title:\n                          type: string\n                          example: Dune\n                        tmdbId:\n                          type: number\n                          example: 438631\n    post:\n      summary: Add media to blocklist\n      description: |\n        **DEPRECATED**: Use `/blocklist` instead. This endpoint will be deprecated soon.\n      deprecated: true\n      tags:\n        - blocklist\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/Blocklist'\n      responses:\n        '201':\n          description: Item succesfully blocklisted\n        '412':\n          description: Item has already been blocklisted\n  /blacklist/{tmdbId}:\n    get:\n      summary: Get media from blocklist\n      description: |\n        **DEPRECATED**: Use `/blocklist/{tmdbId}` instead. This endpoint will be deprecated soon.\n      deprecated: true\n      tags:\n        - blocklist\n      parameters:\n        - in: path\n          name: tmdbId\n          description: tmdbId ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n        - in: query\n          name: mediaType\n          required: true\n          schema:\n            type: string\n            enum:\n              - movie\n              - tv\n      responses:\n        '200':\n          description: Blocklist details in JSON\n    delete:\n      summary: Remove media from blocklist\n      description: |\n        **DEPRECATED**: Use `/blocklist/{tmdbId}` instead. This endpoint will be deprecated soon.\n      deprecated: true\n      tags:\n        - blocklist\n      parameters:\n        - in: path\n          name: tmdbId\n          description: tmdbId ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n        - in: query\n          name: mediaType\n          required: true\n          schema:\n            type: string\n            enum:\n              - movie\n              - tv\n      responses:\n        '204':\n          description: Succesfully removed media item\n  /watchlist:\n    post:\n      summary: Add media to watchlist\n      tags:\n        - watchlist\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/Watchlist'\n      responses:\n        '200':\n          description: Watchlist data returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Watchlist'\n  /watchlist/{tmdbId}:\n    delete:\n      summary: Delete watchlist item\n      description: Removes a watchlist item.\n      tags:\n        - watchlist\n      parameters:\n        - in: path\n          name: tmdbId\n          description: tmdbId ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n        - in: query\n          name: mediaType\n          required: true\n          schema:\n            type: string\n            enum:\n              - movie\n              - tv\n      responses:\n        '204':\n          description: Succesfully removed watchlist item\n  /user/{userId}/watchlist:\n    get:\n      summary: Get the Plex watchlist for a specific user\n      description: |\n        Retrieves a user's Plex Watchlist in a JSON object.\n      tags:\n        - users\n        - watchlist\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n      responses:\n        '200':\n          description: Watchlist data returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                  totalPages:\n                    type: number\n                  totalResults:\n                    type: number\n                  results:\n                    type: array\n                    items:\n                      type: object\n                      properties:\n                        tmdbId:\n                          type: number\n                          example: 1\n                        ratingKey:\n                          type: string\n                        type:\n                          type: string\n                        title:\n                          type: string\n  /user/{userId}/settings/main:\n    get:\n      summary: Get general settings for a user\n      description: Returns general settings for a specific user. Requires `MANAGE_USERS` permission if viewing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: User general settings returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserSettings'\n    post:\n      summary: Update general settings for a user\n      description: Updates and returns general settings for a specific user. Requires `MANAGE_USERS` permission if editing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/UserSettings'\n      responses:\n        '200':\n          description: Updated user general settings returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserSettings'\n  /user/{userId}/settings/password:\n    get:\n      summary: Get password page informatiom\n      description: Returns important data for the password page to function correctly. Requires `MANAGE_USERS` permission if viewing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: User password page information returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  hasPassword:\n                    type: boolean\n                    example: true\n    post:\n      summary: Update password for a user\n      description: Updates a user's password. Requires `MANAGE_USERS` permission if editing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                currentPassword:\n                  type: string\n                  nullable: true\n                newPassword:\n                  type: string\n              required:\n                - newPassword\n      responses:\n        '204':\n          description: User password updated\n  /user/{userId}/settings/linked-accounts/plex:\n    post:\n      summary: Link the provided Plex account to the current user\n      description: Logs in to Plex with the provided auth token, then links the associated Plex account with the user's account. Users can only link external accounts to their own account.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                authToken:\n                  type: string\n              required:\n                - authToken\n      responses:\n        '204':\n          description: Linking account succeeded\n        '403':\n          description: Invalid credentials\n        '422':\n          description: Account already linked to a user\n    delete:\n      summary: Remove the linked Plex account for a user\n      description: Removes the linked Plex account for a specific user. Requires `MANAGE_USERS` permission if editing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '204':\n          description: Unlinking account succeeded\n        '400':\n          description: Unlink request invalid\n        '404':\n          description: User does not exist\n  /user/{userId}/settings/linked-accounts/jellyfin:\n    post:\n      summary: Link the provided Jellyfin account to the current user\n      description: Logs in to Jellyfin with the provided credentials, then links the associated Jellyfin account with the user's account. Users can only link external accounts to their own account.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                username:\n                  type: string\n                  example: 'Mr User'\n                password:\n                  type: string\n                  example: 'supersecret'\n      responses:\n        '204':\n          description: Linking account succeeded\n        '403':\n          description: Invalid credentials\n        '422':\n          description: Account already linked to a user\n    delete:\n      summary: Remove the linked Jellyfin account for a user\n      description: Removes the linked Jellyfin account for a specific user. Requires `MANAGE_USERS` permission if editing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '204':\n          description: Unlinking account succeeded\n        '400':\n          description: Unlink request invalid\n        '404':\n          description: User does not exist\n  /user/{userId}/settings/notifications:\n    get:\n      summary: Get notification settings for a user\n      description: Returns notification settings for a specific user. Requires `MANAGE_USERS` permission if viewing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: User notification settings returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserSettingsNotifications'\n    post:\n      summary: Update notification settings for a user\n      description: Updates and returns notification settings for a specific user. Requires `MANAGE_USERS` permission if editing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/UserSettingsNotifications'\n      responses:\n        '200':\n          description: Updated user notification settings returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserSettingsNotifications'\n  /user/{userId}/settings/permissions:\n    get:\n      summary: Get permission settings for a user\n      description: Returns permission settings for a specific user. Requires `MANAGE_USERS` permission if viewing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: User permission settings returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  permissions:\n                    type: number\n                    example: 2\n    post:\n      summary: Update permission settings for a user\n      description: Updates and returns permission settings for a specific user. Requires `MANAGE_USERS` permission if editing other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                permissions:\n                  type: number\n              required:\n                - permissions\n      responses:\n        '200':\n          description: Updated user general settings returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  permissions:\n                    type: number\n                    example: 2\n  /user/{userId}/watch_data:\n    get:\n      summary: Get watch data\n      description: |\n        Returns play count, play duration, and recently watched media.\n\n        Requires the `ADMIN` permission to fetch results for other users.\n      tags:\n        - users\n      parameters:\n        - in: path\n          name: userId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: Users\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  recentlyWatched:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MediaInfo'\n                  playCount:\n                    type: number\n  /search:\n    get:\n      summary: Search for movies, TV shows, or people\n      description: Returns a list of movies, TV shows, or people a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: query\n          required: true\n          schema:\n            type: string\n            example: 'Mulan'\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      anyOf:\n                        - $ref: '#/components/schemas/MovieResult'\n                        - $ref: '#/components/schemas/TvResult'\n                        - $ref: '#/components/schemas/PersonResult'\n  /search/keyword:\n    get:\n      summary: Search for keywords\n      description: Returns a list of TMDB keywords matching the search query\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: query\n          required: true\n          schema:\n            type: string\n            example: 'christmas'\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/Keyword'\n  /search/company:\n    get:\n      summary: Search for companies\n      description: Returns a list of TMDB companies matching the search query. (Will not return origin country)\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: query\n          required: true\n          schema:\n            type: string\n            example: 'Disney'\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/Company'\n  /discover/movies:\n    get:\n      summary: Discover movies\n      description: Returns a list of movies in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n        - in: query\n          name: genre\n          schema:\n            type: string\n            example: 18\n        - in: query\n          name: studio\n          schema:\n            type: number\n            example: 1\n        - in: query\n          name: keywords\n          schema:\n            type: string\n            example: 1,2\n        - in: query\n          name: excludeKeywords\n          schema:\n            type: string\n            example: 3,4\n          description: Comma-separated list of keyword IDs to exclude from results\n        - in: query\n          name: sortBy\n          schema:\n            type: string\n            example: popularity.desc\n        - in: query\n          name: primaryReleaseDateGte\n          schema:\n            type: string\n            example: 2022-01-01\n        - in: query\n          name: primaryReleaseDateLte\n          schema:\n            type: string\n            example: 2023-01-01\n        - in: query\n          name: withRuntimeGte\n          schema:\n            type: number\n            example: 60\n        - in: query\n          name: withRuntimeLte\n          schema:\n            type: number\n            example: 120\n        - in: query\n          name: voteAverageGte\n          schema:\n            type: number\n            example: 7\n        - in: query\n          name: voteAverageLte\n          schema:\n            type: number\n            example: 10\n        - in: query\n          name: voteCountGte\n          schema:\n            type: number\n            example: 7\n        - in: query\n          name: voteCountLte\n          schema:\n            type: number\n            example: 10\n        - in: query\n          name: watchRegion\n          schema:\n            type: string\n            example: US\n        - in: query\n          name: watchProviders\n          schema:\n            type: string\n            example: 8|9\n        - in: query\n          name: certification\n          schema:\n            type: string\n            example: PG-13\n          description: Exact certification to filter by (used when certificationMode is 'exact')\n        - in: query\n          name: certificationGte\n          schema:\n            type: string\n            example: G\n          description: Minimum certification to filter by (used when certificationMode is 'range')\n        - in: query\n          name: certificationLte\n          schema:\n            type: string\n            example: PG-13\n          description: Maximum certification to filter by (used when certificationMode is 'range')\n        - in: query\n          name: certificationCountry\n          schema:\n            type: string\n            example: US\n          description: Country code for the certification system (e.g., US, GB, CA)\n        - in: query\n          name: certificationMode\n          schema:\n            type: string\n            enum: [exact, range]\n            example: exact\n          description: Determines whether to use exact certification matching or a certification range (internal use only, not sent to TMDB API)\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MovieResult'\n  /discover/movies/genre/{genreId}:\n    get:\n      summary: Discover movies by genre\n      description: Returns a list of movies based on the provided genre ID in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: path\n          name: genreId\n          required: true\n          schema:\n            type: string\n            example: '1'\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  genre:\n                    $ref: '#/components/schemas/Genre'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MovieResult'\n  /discover/movies/language/{language}:\n    get:\n      summary: Discover movies by original language\n      description: Returns a list of movies based on the provided ISO 639-1 language code in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: path\n          name: language\n          required: true\n          schema:\n            type: string\n            example: en\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  language:\n                    $ref: '#/components/schemas/SpokenLanguage'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MovieResult'\n  /discover/movies/studio/{studioId}:\n    get:\n      summary: Discover movies by studio\n      description: Returns a list of movies based on the provided studio ID in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: path\n          name: studioId\n          required: true\n          schema:\n            type: string\n            example: '1'\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  studio:\n                    $ref: '#/components/schemas/ProductionCompany'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MovieResult'\n  /discover/movies/upcoming:\n    get:\n      summary: Upcoming movies\n      description: Returns a list of movies in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MovieResult'\n  /discover/tv:\n    get:\n      summary: Discover TV shows\n      description: Returns a list of TV shows in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n        - in: query\n          name: genre\n          schema:\n            type: string\n            example: 18\n        - in: query\n          name: network\n          schema:\n            type: number\n            example: 1\n        - in: query\n          name: keywords\n          schema:\n            type: string\n            example: 1,2\n        - in: query\n          name: excludeKeywords\n          schema:\n            type: string\n            example: 3,4\n          description: Comma-separated list of keyword IDs to exclude from results\n        - in: query\n          name: sortBy\n          schema:\n            type: string\n            example: popularity.desc\n        - in: query\n          name: firstAirDateGte\n          schema:\n            type: string\n            example: 2022-01-01\n        - in: query\n          name: firstAirDateLte\n          schema:\n            type: string\n            example: 2023-01-01\n        - in: query\n          name: withRuntimeGte\n          schema:\n            type: number\n            example: 60\n        - in: query\n          name: withRuntimeLte\n          schema:\n            type: number\n            example: 120\n        - in: query\n          name: voteAverageGte\n          schema:\n            type: number\n            example: 7\n        - in: query\n          name: voteAverageLte\n          schema:\n            type: number\n            example: 10\n        - in: query\n          name: voteCountGte\n          schema:\n            type: number\n            example: 7\n        - in: query\n          name: voteCountLte\n          schema:\n            type: number\n            example: 10\n        - in: query\n          name: watchRegion\n          schema:\n            type: string\n            example: US\n        - in: query\n          name: watchProviders\n          schema:\n            type: string\n            example: 8|9\n        - in: query\n          name: status\n          schema:\n            type: string\n            example: 3|4\n        - in: query\n          name: certification\n          schema:\n            type: string\n            example: TV-14\n          description: Exact certification to filter by (used when certificationMode is 'exact')\n        - in: query\n          name: certificationGte\n          schema:\n            type: string\n            example: TV-PG\n          description: Minimum certification to filter by (used when certificationMode is 'range')\n        - in: query\n          name: certificationLte\n          schema:\n            type: string\n            example: TV-MA\n          description: Maximum certification to filter by (used when certificationMode is 'range')\n        - in: query\n          name: certificationCountry\n          schema:\n            type: string\n            example: US\n          description: Country code for the certification system (e.g., US, GB, CA)\n        - in: query\n          name: certificationMode\n          schema:\n            type: string\n            enum: [exact, range]\n            example: exact\n          description: Determines whether to use exact certification matching or a certification range (internal use only, not sent to TMDB API)\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/TvResult'\n  /discover/tv/language/{language}:\n    get:\n      summary: Discover TV shows by original language\n      description: Returns a list of TV shows based on the provided ISO 639-1 language code in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: path\n          name: language\n          required: true\n          schema:\n            type: string\n            example: en\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  language:\n                    $ref: '#/components/schemas/SpokenLanguage'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/TvResult'\n  /discover/tv/genre/{genreId}:\n    get:\n      summary: Discover TV shows by genre\n      description: Returns a list of TV shows based on the provided genre ID in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: path\n          name: genreId\n          required: true\n          schema:\n            type: string\n            example: '1'\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  genre:\n                    $ref: '#/components/schemas/Genre'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/TvResult'\n  /discover/tv/network/{networkId}:\n    get:\n      summary: Discover TV shows by network\n      description: Returns a list of TV shows based on the provided network ID in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: path\n          name: networkId\n          required: true\n          schema:\n            type: string\n            example: '1'\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  network:\n                    $ref: '#/components/schemas/Network'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/TvResult'\n  /discover/tv/upcoming:\n    get:\n      summary: Discover Upcoming TV shows\n      description: Returns a list of upcoming TV shows in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/TvResult'\n  /discover/trending:\n    get:\n      summary: Trending movies and TV\n      description: Returns a list of movies and TV shows in a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n        - in: query\n          name: mediaType\n          schema:\n            type: string\n            enum:\n              - all\n              - movie\n              - tv\n            default: all\n        - in: query\n          name: timeWindow\n          schema:\n            type: string\n            enum:\n              - day\n              - week\n            default: day\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      anyOf:\n                        - $ref: '#/components/schemas/MovieResult'\n                        - $ref: '#/components/schemas/TvResult'\n                        - $ref: '#/components/schemas/PersonResult'\n  /discover/keyword/{keywordId}/movies:\n    get:\n      summary: Get movies from keyword\n      description: Returns list of movies based on the provided keyword ID a JSON object.\n      tags:\n        - search\n      parameters:\n        - in: path\n          name: keywordId\n          required: true\n          schema:\n            type: number\n            example: 207317\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: List of movies\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MovieResult'\n  /discover/genreslider/movie:\n    get:\n      summary: Get genre slider data for movies\n      description: Returns a list of genres with backdrops attached\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Genre slider data returned\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    id:\n                      type: number\n                      example: 1\n                    backdrops:\n                      type: array\n                      items:\n                        type: string\n                    name:\n                      type: string\n                      example: Genre Name\n  /discover/genreslider/tv:\n    get:\n      summary: Get genre slider data for TV series\n      description: Returns a list of genres with backdrops attached\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Genre slider data returned\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    id:\n                      type: number\n                      example: 1\n                    backdrops:\n                      type: array\n                      items:\n                        type: string\n                    name:\n                      type: string\n                      example: Genre Name\n  /discover/watchlist:\n    get:\n      summary: Get the Plex watchlist.\n      tags:\n        - search\n      parameters:\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n      responses:\n        '200':\n          description: Watchlist data returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                  totalPages:\n                    type: number\n                  totalResults:\n                    type: number\n                  results:\n                    type: array\n                    items:\n                      type: object\n                      properties:\n                        tmdbId:\n                          type: number\n                          example: 1\n                        ratingKey:\n                          type: string\n                        type:\n                          type: string\n                        title:\n                          type: string\n  /request:\n    get:\n      summary: Get all requests\n      description: |\n        Returns all requests if the user has the `ADMIN` or `MANAGE_REQUESTS` permissions. Otherwise, only the logged-in user's requests are returned.\n\n        If the `requestedBy` parameter is specified, only requests from that particular user ID will be returned.\n      tags:\n        - request\n      parameters:\n        - in: query\n          name: take\n          schema:\n            type: number\n            nullable: true\n            example: 20\n        - in: query\n          name: skip\n          schema:\n            type: number\n            nullable: true\n            example: 0\n        - in: query\n          name: filter\n          schema:\n            type: string\n            nullable: true\n            enum:\n              [\n                all,\n                approved,\n                available,\n                pending,\n                processing,\n                unavailable,\n                failed,\n                deleted,\n                completed,\n              ]\n        - in: query\n          name: sort\n          schema:\n            type: string\n            enum: [added, modified]\n            default: added\n        - in: query\n          name: sortDirection\n          schema:\n            type: string\n            enum: [asc, desc]\n            nullable: true\n            default: desc\n        - in: query\n          name: requestedBy\n          schema:\n            type: number\n            nullable: true\n            example: 1\n        - in: query\n          name: mediaType\n          schema:\n            type: string\n            enum: [movie, tv, all]\n            nullable: true\n            default: all\n      responses:\n        '200':\n          description: Requests returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  pageInfo:\n                    $ref: '#/components/schemas/PageInfo'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MediaRequest'\n    post:\n      summary: Create new request\n      description: |\n        Creates a new request with the provided media ID and type. The `REQUEST` permission is required.\n\n        If the user has the `ADMIN` or `AUTO_APPROVE` permissions, their request will be auomatically approved.\n      tags:\n        - request\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                mediaType:\n                  type: string\n                  enum: [movie, tv]\n                  example: movie\n                mediaId:\n                  type: number\n                  example: 123\n                tvdbId:\n                  type: number\n                  example: 123\n                seasons:\n                  oneOf:\n                    - type: array\n                      items:\n                        type: number\n                        minimum: 0\n                    - type: string\n                      enum: [all]\n                is4k:\n                  type: boolean\n                  example: false\n                serverId:\n                  type: number\n                profileId:\n                  type: number\n                rootFolder:\n                  type: string\n                languageProfileId:\n                  type: number\n                userId:\n                  type: number\n                  nullable: true\n              required:\n                - mediaType\n                - mediaId\n      responses:\n        '201':\n          description: Succesfully created the request\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MediaRequest'\n  /request/count:\n    get:\n      summary: Gets request counts\n      description: |\n        Returns the number of requests by status including pending, approved, available, and completed requests.\n      tags:\n        - request\n      responses:\n        '200':\n          description: Request counts returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  total:\n                    type: number\n                  movie:\n                    type: number\n                  tv:\n                    type: number\n                  pending:\n                    type: number\n                  approved:\n                    type: number\n                  declined:\n                    type: number\n                  processing:\n                    type: number\n                  available:\n                    type: number\n                  completed:\n                    type: number\n  /request/{requestId}:\n    get:\n      summary: Get MediaRequest\n      description: Returns a specific MediaRequest in a JSON object.\n      tags:\n        - request\n      parameters:\n        - in: path\n          name: requestId\n          description: Request ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n      responses:\n        '200':\n          description: Succesfully returns request\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MediaRequest'\n    put:\n      summary: Update MediaRequest\n      description: Updates a specific media request and returns the request in a JSON object. Requires the `MANAGE_REQUESTS` permission.\n      tags:\n        - request\n      parameters:\n        - in: path\n          name: requestId\n          description: Request ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                mediaType:\n                  type: string\n                  enum: [movie, tv]\n                seasons:\n                  type: array\n                  items:\n                    type: number\n                    minimum: 0\n                is4k:\n                  type: boolean\n                  example: false\n                serverId:\n                  type: number\n                profileId:\n                  type: number\n                rootFolder:\n                  type: string\n                languageProfileId:\n                  type: number\n                userId:\n                  type: number\n                  nullable: true\n              required:\n                - mediaType\n      responses:\n        '200':\n          description: Succesfully updated request\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MediaRequest'\n    delete:\n      summary: Delete request\n      description: Removes a request. If the user has the `MANAGE_REQUESTS` permission, any request can be removed. Otherwise, only pending requests can be removed.\n      tags:\n        - request\n      parameters:\n        - in: path\n          name: requestId\n          description: Request ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n      responses:\n        '204':\n          description: Succesfully removed request\n  /request/{requestId}/retry:\n    post:\n      summary: Retry failed request\n      description: |\n        Retries a request by resending requests to Sonarr or Radarr.\n\n        Requires the `MANAGE_REQUESTS` permission or `ADMIN`.\n      tags:\n        - request\n      parameters:\n        - in: path\n          name: requestId\n          description: Request ID\n          required: true\n          schema:\n            type: string\n            example: '1'\n      responses:\n        '200':\n          description: Retry triggered\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MediaRequest'\n  /request/{requestId}/{status}:\n    post:\n      summary: Update a request's status\n      description: |\n        Updates a request's status to approved or declined. Also returns the request in a JSON object.\n\n        Requires the `MANAGE_REQUESTS` permission or `ADMIN`.\n      tags:\n        - request\n      parameters:\n        - in: path\n          name: requestId\n          description: Request ID\n          required: true\n          schema:\n            type: string\n            example: '1'\n        - in: path\n          name: status\n          description: New status\n          required: true\n          schema:\n            type: string\n            enum: [approve, decline]\n      responses:\n        '200':\n          description: Request status changed\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MediaRequest'\n  /movie/{movieId}:\n    get:\n      summary: Get movie details\n      description: Returns full movie details in a JSON object.\n      tags:\n        - movies\n      parameters:\n        - in: path\n          name: movieId\n          required: true\n          schema:\n            type: number\n            example: 337401\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Movie details\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MovieDetails'\n  /movie/{movieId}/recommendations:\n    get:\n      summary: Get recommended movies\n      description: Returns list of recommended movies based on provided movie ID in a JSON object.\n      tags:\n        - movies\n      parameters:\n        - in: path\n          name: movieId\n          required: true\n          schema:\n            type: number\n            example: 337401\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: List of movies\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MovieResult'\n  /movie/{movieId}/similar:\n    get:\n      summary: Get similar movies\n      description: Returns list of similar movies based on the provided movieId in a JSON object.\n      tags:\n        - movies\n      parameters:\n        - in: path\n          name: movieId\n          required: true\n          schema:\n            type: number\n            example: 337401\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: List of movies\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MovieResult'\n  /movie/{movieId}/ratings:\n    get:\n      summary: Get movie ratings\n      description: Returns ratings based on the provided movieId in a JSON object.\n      tags:\n        - movies\n      parameters:\n        - in: path\n          name: movieId\n          required: true\n          schema:\n            type: number\n            example: 337401\n      responses:\n        '200':\n          description: Ratings returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  title:\n                    type: string\n                    example: Mulan\n                  year:\n                    type: number\n                    example: 2020\n                  url:\n                    type: string\n                    example: 'http://www.rottentomatoes.com/m/mulan_2020/'\n                  criticsScore:\n                    type: number\n                    example: 85\n                  criticsRating:\n                    type: string\n                    enum: ['Rotten', 'Fresh', 'Certified Fresh']\n                  audienceScore:\n                    type: number\n                    example: 65\n                  audienceRating:\n                    type: string\n                    enum: ['Spilled', 'Upright']\n  /movie/{movieId}/ratingscombined:\n    get:\n      summary: Get RT and IMDB movie ratings combined\n      description: Returns ratings from RottenTomatoes and IMDB based on the provided movieId in a JSON object.\n      tags:\n        - movies\n      parameters:\n        - in: path\n          name: movieId\n          required: true\n          schema:\n            type: number\n            example: 337401\n      responses:\n        '200':\n          description: Ratings returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  rt:\n                    type: object\n                    properties:\n                      title:\n                        type: string\n                        example: Mulan\n                      year:\n                        type: number\n                        example: 2020\n                      url:\n                        type: string\n                        example: 'http://www.rottentomatoes.com/m/mulan_2020/'\n                      criticsScore:\n                        type: number\n                        example: 85\n                      criticsRating:\n                        type: string\n                        enum: ['Rotten', 'Fresh', 'Certified Fresh']\n                      audienceScore:\n                        type: number\n                        example: 65\n                      audienceRating:\n                        type: string\n                        enum: ['Spilled', 'Upright']\n                  imdb:\n                    type: object\n                    properties:\n                      title:\n                        type: string\n                        example: I am Legend\n                      url:\n                        type: string\n                        example: 'https://www.imdb.com/title/tt0480249'\n                      criticsScore:\n                        type: number\n                        example: 6.5\n  /tv/{tvId}:\n    get:\n      summary: Get TV details\n      description: Returns full TV details in a JSON object.\n      tags:\n        - tv\n      parameters:\n        - in: path\n          name: tvId\n          required: true\n          schema:\n            type: number\n            example: 76479\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: TV details\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/TvDetails'\n  /tv/{tvId}/season/{seasonNumber}:\n    get:\n      summary: Get season details and episode list\n      description: Returns season details with a list of episodes in a JSON object.\n      tags:\n        - tv\n      parameters:\n        - in: path\n          name: tvId\n          required: true\n          schema:\n            type: number\n            example: 76479\n        - in: path\n          name: seasonNumber\n          required: true\n          schema:\n            type: number\n            example: 123456\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: TV details\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Season'\n  /tv/{tvId}/recommendations:\n    get:\n      summary: Get recommended TV series\n      description: Returns list of recommended TV series based on the provided tvId in a JSON object.\n      tags:\n        - tv\n      parameters:\n        - in: path\n          name: tvId\n          required: true\n          schema:\n            type: number\n            example: 76479\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: List of TV series\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/TvResult'\n  /tv/{tvId}/similar:\n    get:\n      summary: Get similar TV series\n      description: Returns list of similar TV series based on the provided tvId in a JSON object.\n      tags:\n        - tv\n      parameters:\n        - in: path\n          name: tvId\n          required: true\n          schema:\n            type: number\n            example: 76479\n        - in: query\n          name: page\n          schema:\n            type: number\n            example: 1\n            default: 1\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: List of TV series\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  page:\n                    type: number\n                    example: 1\n                  totalPages:\n                    type: number\n                    example: 20\n                  totalResults:\n                    type: number\n                    example: 200\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/TvResult'\n  /tv/{tvId}/ratings:\n    get:\n      summary: Get TV ratings\n      description: Returns ratings based on provided tvId in a JSON object.\n      tags:\n        - tv\n      parameters:\n        - in: path\n          name: tvId\n          required: true\n          schema:\n            type: number\n            example: 76479\n      responses:\n        '200':\n          description: Ratings returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  title:\n                    type: string\n                    example: The Boys\n                  year:\n                    type: number\n                    example: 2019\n                  url:\n                    type: string\n                    example: 'http://www.rottentomatoes.com/m/mulan_2020/'\n                  criticsScore:\n                    type: number\n                    example: 85\n                  criticsRating:\n                    type: string\n                    enum: ['Rotten', 'Fresh']\n  /person/{personId}:\n    get:\n      summary: Get person details\n      description: Returns person details based on provided personId in a JSON object.\n      tags:\n        - person\n      parameters:\n        - in: path\n          name: personId\n          required: true\n          schema:\n            type: number\n            example: 287\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Returned person\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PersonDetails'\n  /person/{personId}/combined_credits:\n    get:\n      summary: Get combined credits\n      description: Returns the person's combined credits based on the provided personId in a JSON object.\n      tags:\n        - person\n      parameters:\n        - in: path\n          name: personId\n          required: true\n          schema:\n            type: number\n            example: 287\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Returned combined credits\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  cast:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/CreditCast'\n                  crew:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/CreditCrew'\n                  id:\n                    type: number\n  /media:\n    get:\n      summary: Get media\n      description: Returns all media (can be filtered and limited) in a JSON object.\n      tags:\n        - media\n      parameters:\n        - in: query\n          name: take\n          schema:\n            type: number\n            nullable: true\n            example: 20\n        - in: query\n          name: skip\n          schema:\n            type: number\n            nullable: true\n            example: 0\n        - in: query\n          name: filter\n          schema:\n            type: string\n            nullable: true\n            enum:\n              [\n                all,\n                available,\n                partial,\n                allavailable,\n                processing,\n                pending,\n                deleted,\n              ]\n        - in: query\n          name: sort\n          schema:\n            type: string\n            enum: [added, modified, mediaAdded]\n            default: added\n      responses:\n        '200':\n          description: Returned media\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  pageInfo:\n                    $ref: '#/components/schemas/PageInfo'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/MediaInfo'\n  /media/{mediaId}:\n    delete:\n      summary: Delete media item\n      description: Removes a media item. The `MANAGE_REQUESTS` permission is required to perform this action.\n      tags:\n        - media\n      parameters:\n        - in: path\n          name: mediaId\n          description: Media ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n      responses:\n        '204':\n          description: Succesfully removed media item\n  /media/{mediaId}/file:\n    delete:\n      summary: Delete media file\n      description: Removes a media file from radarr/sonarr. The `ADMIN` permission is required to perform this action.\n      tags:\n        - media\n      parameters:\n        - in: path\n          name: mediaId\n          description: Media ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n        - in: query\n          name: is4k\n          description: Whether to remove from 4K service instance (true) or regular service instance (false)\n          required: false\n          example: false\n          schema:\n            type: boolean\n      responses:\n        '204':\n          description: Successfully removed media item\n  /media/{mediaId}/{status}:\n    post:\n      summary: Update media status\n      description: Updates a media item's status and returns the media in JSON format\n      tags:\n        - media\n      parameters:\n        - in: path\n          name: mediaId\n          description: Media ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n        - in: path\n          name: status\n          description: New status\n          required: true\n          example: available\n          schema:\n            type: string\n            enum: [available, partial, processing, pending, unknown, deleted]\n      requestBody:\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                is4k:\n                  type: boolean\n                  example: false\n                  description: |\n                    When true, updates the 4K status field (status4k).\n                    When false or not provided, updates the regular status field (status).\n                    This applies to all status values (available, partial, processing, pending, unknown).\n      responses:\n        '200':\n          description: Returned media\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/MediaInfo'\n  /media/{mediaId}/watch_data:\n    get:\n      summary: Get watch data\n      description: |\n        Returns play count, play duration, and users who have watched the media.\n\n        Requires the `ADMIN` permission.\n      tags:\n        - media\n      parameters:\n        - in: path\n          name: mediaId\n          description: Media ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n      responses:\n        '200':\n          description: Users\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  data:\n                    type: object\n                    properties:\n                      playCount7Days:\n                        type: number\n                      playCount30Days:\n                        type: number\n                      playCount:\n                        type: number\n                      users:\n                        type: array\n                        items:\n                          $ref: '#/components/schemas/User'\n                  data4k:\n                    type: object\n                    properties:\n                      playCount7Days:\n                        type: number\n                      playCount30Days:\n                        type: number\n                      playCount:\n                        type: number\n                      users:\n                        type: array\n                        items:\n                          $ref: '#/components/schemas/User'\n  /collection/{collectionId}:\n    get:\n      summary: Get collection details\n      description: Returns full collection details in a JSON object.\n      tags:\n        - collection\n      parameters:\n        - in: path\n          name: collectionId\n          required: true\n          schema:\n            type: number\n            example: 537982\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Collection details\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Collection'\n  /service/radarr:\n    get:\n      summary: Get non-sensitive Radarr server list\n      description: Returns a list of Radarr server IDs and names in a JSON object.\n      tags:\n        - service\n      responses:\n        '200':\n          description: Request successful\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/RadarrSettings'\n  /service/radarr/{radarrId}:\n    get:\n      summary: Get Radarr server quality profiles and root folders\n      description: Returns a Radarr server's quality profile and root folder details in a JSON object.\n      tags:\n        - service\n      parameters:\n        - in: path\n          name: radarrId\n          required: true\n          schema:\n            type: number\n            example: 0\n      responses:\n        '200':\n          description: Request successful\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  server:\n                    $ref: '#/components/schemas/RadarrSettings'\n                  profiles:\n                    $ref: '#/components/schemas/ServiceProfile'\n  /service/sonarr:\n    get:\n      summary: Get non-sensitive Sonarr server list\n      description: Returns a list of Sonarr server IDs and names in a JSON object.\n      tags:\n        - service\n      responses:\n        '200':\n          description: Request successful\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/SonarrSettings'\n  /service/sonarr/{sonarrId}:\n    get:\n      summary: Get Sonarr server quality profiles and root folders\n      description: Returns a Sonarr server's quality profile and root folder details in a JSON object.\n      tags:\n        - service\n      parameters:\n        - in: path\n          name: sonarrId\n          required: true\n          schema:\n            type: number\n            example: 0\n      responses:\n        '200':\n          description: Request successful\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  server:\n                    $ref: '#/components/schemas/SonarrSettings'\n                  profiles:\n                    $ref: '#/components/schemas/ServiceProfile'\n  /service/sonarr/lookup/{tmdbId}:\n    get:\n      summary: Get series from Sonarr\n      description: Returns a list of series returned by searching for the name in Sonarr.\n      tags:\n        - service\n      parameters:\n        - in: path\n          name: tmdbId\n          required: true\n          schema:\n            type: number\n            example: 0\n      responses:\n        '200':\n          description: Request successful\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/SonarrSeries'\n  /regions:\n    get:\n      summary: Regions supported by TMDB\n      description: Returns a list of regions in a JSON object.\n      tags:\n        - tmdb\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    iso_3166_1:\n                      type: string\n                      example: US\n                    english_name:\n                      type: string\n                      example: United States of America\n  /languages:\n    get:\n      summary: Languages supported by TMDB\n      description: Returns a list of languages in a JSON object.\n      tags:\n        - tmdb\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    iso_639_1:\n                      type: string\n                      example: en\n                    english_name:\n                      type: string\n                      example: English\n                    name:\n                      type: string\n                      example: English\n  /studio/{studioId}:\n    get:\n      summary: Get movie studio details\n      description: Returns movie studio details in a JSON object.\n      tags:\n        - tmdb\n      parameters:\n        - in: path\n          name: studioId\n          required: true\n          schema:\n            type: number\n            example: 2\n      responses:\n        '200':\n          description: Movie studio details\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/ProductionCompany'\n  /network/{networkId}:\n    get:\n      summary: Get TV network details\n      description: Returns TV network details in a JSON object.\n      tags:\n        - tmdb\n      parameters:\n        - in: path\n          name: networkId\n          required: true\n          schema:\n            type: number\n            example: 1\n      responses:\n        '200':\n          description: TV network details\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/ProductionCompany'\n  /genres/movie:\n    get:\n      summary: Get list of official TMDB movie genres\n      description: Returns a list of genres in a JSON array.\n      tags:\n        - tmdb\n      parameters:\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    id:\n                      type: number\n                      example: 10751\n                    name:\n                      type: string\n                      example: Family\n  /genres/tv:\n    get:\n      summary: Get list of official TMDB movie genres\n      description: Returns a list of genres in a JSON array.\n      tags:\n        - tmdb\n      parameters:\n        - in: query\n          name: language\n          schema:\n            type: string\n            example: en\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: object\n                  properties:\n                    id:\n                      type: number\n                      example: 18\n                    name:\n                      type: string\n                      example: Drama\n  /backdrops:\n    get:\n      summary: Get backdrops of trending items\n      description: Returns a list of backdrop image paths in a JSON array.\n      security: []\n      tags:\n        - tmdb\n      responses:\n        '200':\n          description: Results\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  type: string\n  /issue:\n    get:\n      summary: Get all issues\n      description: |\n        Returns a list of issues in JSON format.\n      tags:\n        - issue\n      parameters:\n        - in: query\n          name: take\n          schema:\n            type: number\n            nullable: true\n            example: 20\n        - in: query\n          name: skip\n          schema:\n            type: number\n            nullable: true\n            example: 0\n        - in: query\n          name: sort\n          schema:\n            type: string\n            enum: [added, modified]\n            default: added\n        - in: query\n          name: filter\n          schema:\n            type: string\n            enum: [all, open, resolved]\n            default: open\n        - in: query\n          name: requestedBy\n          schema:\n            type: number\n            nullable: true\n            example: 1\n      responses:\n        '200':\n          description: Issues returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  pageInfo:\n                    $ref: '#/components/schemas/PageInfo'\n                  results:\n                    type: array\n                    items:\n                      $ref: '#/components/schemas/Issue'\n    post:\n      summary: Create new issue\n      description: |\n        Creates a new issue\n      tags:\n        - issue\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                issueType:\n                  type: number\n                message:\n                  type: string\n                mediaId:\n                  type: number\n      responses:\n        '201':\n          description: Succesfully created the issue\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Issue'\n\n  /issue/count:\n    get:\n      summary: Gets issue counts\n      description: |\n        Returns the number of open and closed issues, as well as the number of issues of each type.\n      tags:\n        - issue\n      responses:\n        '200':\n          description: Issue counts returned\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  total:\n                    type: number\n                  video:\n                    type: number\n                  audio:\n                    type: number\n                  subtitles:\n                    type: number\n                  others:\n                    type: number\n                  open:\n                    type: number\n                  closed:\n                    type: number\n  /issue/{issueId}:\n    get:\n      summary: Get issue\n      description: |\n        Returns a single issue in JSON format.\n      tags:\n        - issue\n      parameters:\n        - in: path\n          name: issueId\n          required: true\n          schema:\n            type: number\n            example: 1\n      responses:\n        '200':\n          description: Issues returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Issue'\n    delete:\n      summary: Delete issue\n      description: Removes an issue. If the user has the `MANAGE_ISSUES` permission, any issue can be removed. Otherwise, only a users own issues can be removed.\n      tags:\n        - issue\n      parameters:\n        - in: path\n          name: issueId\n          description: Issue ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n      responses:\n        '204':\n          description: Succesfully removed issue\n  /issue/{issueId}/comment:\n    post:\n      summary: Create a comment\n      description: |\n        Creates a comment and returns associated issue in JSON format.\n      tags:\n        - issue\n      parameters:\n        - in: path\n          name: issueId\n          required: true\n          schema:\n            type: number\n            example: 1\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                message:\n                  type: string\n              required:\n                - message\n      responses:\n        '200':\n          description: Issue returned with new comment\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Issue'\n  /issueComment/{commentId}:\n    get:\n      summary: Get issue comment\n      description: |\n        Returns a single issue comment in JSON format.\n      tags:\n        - issue\n      parameters:\n        - in: path\n          name: commentId\n          required: true\n          schema:\n            type: string\n            example: 1\n      responses:\n        '200':\n          description: Comment returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/IssueComment'\n    put:\n      summary: Update issue comment\n      description: |\n        Updates and returns a single issue comment in JSON format.\n      tags:\n        - issue\n      parameters:\n        - in: path\n          name: commentId\n          required: true\n          schema:\n            type: string\n            example: 1\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              type: object\n              properties:\n                message:\n                  type: string\n      responses:\n        '200':\n          description: Comment updated\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/IssueComment'\n    delete:\n      summary: Delete issue comment\n      description: |\n        Deletes an issue comment. Only users with `MANAGE_ISSUES` or the user who created the comment can perform this action.\n      tags:\n        - issue\n      parameters:\n        - in: path\n          name: commentId\n          description: Issue Comment ID\n          required: true\n          example: '1'\n          schema:\n            type: string\n      responses:\n        '204':\n          description: Succesfully removed issue comment\n  /issue/{issueId}/{status}:\n    post:\n      summary: Update an issue's status\n      description: |\n        Updates an issue's status to approved or declined. Also returns the issue in a JSON object.\n\n        Requires the `MANAGE_ISSUES` permission or `ADMIN`.\n      tags:\n        - issue\n      parameters:\n        - in: path\n          name: issueId\n          description: Issue ID\n          required: true\n          schema:\n            type: string\n            example: '1'\n        - in: path\n          name: status\n          description: New status\n          required: true\n          schema:\n            type: string\n            enum: [open, resolved]\n      responses:\n        '200':\n          description: Issue status changed\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Issue'\n  /keyword/{keywordId}:\n    get:\n      summary: Get keyword\n      description: |\n        Returns a single keyword in JSON format.\n      tags:\n        - other\n      parameters:\n        - in: path\n          name: keywordId\n          required: true\n          schema:\n            type: number\n            example: 1\n      responses:\n        '200':\n          description: Keyword returned (null if not found)\n          content:\n            application/json:\n              schema:\n                nullable: true\n                $ref: '#/components/schemas/Keyword'\n        '500':\n          description: Internal server error\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  message:\n                    type: string\n                    example: 'Unable to retrieve keyword data.'\n  /watchproviders/regions:\n    get:\n      summary: Get watch provider regions\n      description: |\n        Returns a list of all available watch provider regions.\n      tags:\n        - other\n      responses:\n        '200':\n          description: Watch provider regions returned\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/WatchProviderRegion'\n  /watchproviders/movies:\n    get:\n      summary: Get watch provider movies\n      description: |\n        Returns a list of all available watch providers for movies.\n      tags:\n        - other\n      parameters:\n        - in: query\n          name: watchRegion\n          required: true\n          schema:\n            type: string\n            example: US\n      responses:\n        '200':\n          description: Watch providers for movies returned\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/WatchProviderDetails'\n  /watchproviders/tv:\n    get:\n      summary: Get watch provider series\n      description: |\n        Returns a list of all available watch providers for series.\n      tags:\n        - other\n      parameters:\n        - in: query\n          name: watchRegion\n          required: true\n          schema:\n            type: string\n            example: US\n      responses:\n        '200':\n          description: Watch providers for series returned\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/WatchProviderDetails'\n  /certifications/movie:\n    get:\n      summary: Get movie certifications\n      description: Returns list of movie certifications from TMDB.\n      tags:\n        - other\n      security:\n        - cookieAuth: []\n        - apiKey: []\n      responses:\n        '200':\n          description: Movie certifications returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/CertificationResponse'\n        '500':\n          description: Unable to retrieve movie certifications\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  status:\n                    type: number\n                    example: 500\n                  message:\n                    type: string\n                    example: Unable to retrieve movie certifications.\n  /certifications/tv:\n    get:\n      summary: Get TV certifications\n      description: Returns list of TV show certifications from TMDB.\n      tags:\n        - other\n      security:\n        - cookieAuth: []\n        - apiKey: []\n      responses:\n        '200':\n          description: TV certifications returned\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/CertificationResponse'\n        '500':\n          description: Unable to retrieve TV certifications\n          content:\n            application/json:\n              schema:\n                type: object\n                properties:\n                  status:\n                    type: number\n                    example: 500\n                  message:\n                    type: string\n                    example: Unable to retrieve TV certifications.\n  /overrideRule:\n    get:\n      summary: Get override rules\n      description: Returns a list of all override rules with their conditions and settings\n      tags:\n        - overriderule\n      responses:\n        '200':\n          description: Override rules returned\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/OverrideRule'\n    post:\n      summary: Create override rule\n      description: Creates a new Override Rule from the request body.\n      tags:\n        - overriderule\n      responses:\n        '200':\n          description: 'Values were successfully created'\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/OverrideRule'\n  /overrideRule/{ruleId}:\n    put:\n      summary: Update override rule\n      description: Updates an Override Rule from the request body.\n      tags:\n        - overriderule\n      parameters:\n        - in: path\n          name: ruleId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: 'Values were successfully updated'\n          content:\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/OverrideRule'\n    delete:\n      summary: Delete override rule by ID\n      description: Deletes the override rule with the provided ruleId.\n      tags:\n        - overriderule\n      parameters:\n        - in: path\n          name: ruleId\n          required: true\n          schema:\n            type: number\n      responses:\n        '200':\n          description: Override rule successfully deleted\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/OverrideRule'\nsecurity:\n  - cookieAuth: []\n  - apiKey: []\n"
  },
  {
    "path": "server/api/animelist.ts",
    "content": "import logger from '@server/logger';\nimport axios from 'axios';\nimport fs, { promises as fsp } from 'fs';\nimport path from 'path';\nimport xml2js from 'xml2js';\n\nconst UPDATE_INTERVAL_MSEC = 24 * 3600 * 1000; // how often to download new mapping in milliseconds\n// originally at https://raw.githubusercontent.com/ScudLee/anime-lists/master/anime-list.xml\nconst MAPPING_URL =\n  'https://raw.githubusercontent.com/Anime-Lists/anime-lists/master/anime-list.xml';\nconst LOCAL_PATH = process.env.CONFIG_DIRECTORY\n  ? `${process.env.CONFIG_DIRECTORY}/anime-list.xml`\n  : path.join(__dirname, '../../config/anime-list.xml');\n\nconst mappingRegexp = new RegExp(/;[0-9]+-([0-9]+)/g);\n\n// Anime-List xml files are community maintained mappings that Hama agent uses to map AniDB IDs to TVDB/TMDB IDs\n// https://github.com/Anime-Lists/anime-lists/\n\ninterface AnimeMapping {\n  $: {\n    anidbseason: string;\n    tvdbseason: string;\n  };\n  _: string;\n}\n\ninterface Anime {\n  $: {\n    anidbid: number;\n    tvdbid?: string;\n    defaulttvdbseason?: string;\n    tmdbid?: number;\n    imdbid?: string;\n  };\n  'mapping-list'?: {\n    mapping: AnimeMapping[];\n  }[];\n}\n\ninterface AnimeList {\n  'anime-list': {\n    anime: Anime[];\n  };\n}\n\nexport interface AnidbItem {\n  tvdbId?: number;\n  tmdbId?: number;\n  imdbId?: string;\n  tvdbSeason?: number;\n}\n\nclass AnimeListMapping {\n  private syncing = false;\n\n  private mapping: { [anidbId: number]: AnidbItem } = {};\n\n  // mapping file modification date when it was loaded\n  private mappingModified: Date | null = null;\n\n  // each episode in season 0 from TVDB can map to movie\n  private specials: { [tvdbId: number]: { [episode: number]: AnidbItem } } = {};\n\n  public isLoaded = () => Object.keys(this.mapping).length !== 0;\n\n  private loadFromFile = async () => {\n    logger.info('Loading mapping file', { label: 'Anime-List Sync' });\n    try {\n      const mappingStat = await fsp.stat(LOCAL_PATH);\n      const file = await fsp.readFile(LOCAL_PATH);\n      const xml = (await xml2js.parseStringPromise(file)) as AnimeList;\n\n      this.mapping = {};\n      this.specials = {};\n      for (const anime of xml['anime-list'].anime) {\n        // tvdbId can be nonnumber, like 'movie' string\n        let tvdbId: number | undefined;\n        if (anime.$.tvdbid && !isNaN(Number(anime.$.tvdbid))) {\n          tvdbId = Number(anime.$.tvdbid);\n        } else {\n          tvdbId = undefined;\n        }\n\n        let imdbIds: (string | undefined)[];\n        if (anime.$.imdbid) {\n          // if there are multiple imdb entries, then they map to different movies\n          imdbIds = anime.$.imdbid.split(',');\n        } else {\n          // in case there is no imdbid, that's ok as there will be tmdbid\n          imdbIds = [undefined];\n        }\n\n        const tmdbId = anime.$.tmdbid ? Number(anime.$.tmdbid) : undefined;\n        const anidbId = Number(anime.$.anidbid);\n        this.mapping[anidbId] = {\n          // for season 0 ignore tvdbid, because this must be movie/OVA\n          tvdbId: anime.$.defaulttvdbseason === '0' ? undefined : tvdbId,\n          tmdbId: tmdbId,\n          imdbId: imdbIds[0], // this is used for one AniDB -> one imdb movie mapping\n          tvdbSeason: Number(anime.$.defaulttvdbseason),\n        };\n\n        if (tvdbId) {\n          const mappingList = anime['mapping-list'];\n          if (mappingList && mappingList.length != 0) {\n            let imdbIndex = 0;\n            for (const mapping of mappingList[0].mapping) {\n              const text = mapping._;\n              if (text && mapping.$.tvdbseason === '0') {\n                let matches;\n                while ((matches = mappingRegexp.exec(text)) !== null) {\n                  const episode = Number(matches[1]);\n                  if (!this.specials[tvdbId]) {\n                    this.specials[tvdbId] = {};\n                  }\n                  // map next available imdbid to episode in s0\n                  const imdbId =\n                    imdbIndex > imdbIds.length ? undefined : imdbIds[imdbIndex];\n                  if (tmdbId || imdbId) {\n                    this.specials[tvdbId][episode] = {\n                      tmdbId: tmdbId,\n                      imdbId: imdbId,\n                    };\n                    imdbIndex++;\n                  }\n                }\n              }\n            }\n          } else {\n            // some movies do not have mapping-list, so map episode 1,2,3,..to movies\n            // movies must have imdbId or tmdbId\n            const hasImdb = imdbIds.length > 1 || imdbIds[0] !== undefined;\n            if ((hasImdb || tmdbId) && anime.$.defaulttvdbseason === '0') {\n              if (!this.specials[tvdbId]) {\n                this.specials[tvdbId] = {};\n              }\n              // map each imdbid to episode in s0, episode index starts with 1\n              for (let idx = 0; idx < imdbIds.length; idx++) {\n                this.specials[tvdbId][idx + 1] = {\n                  tmdbId: tmdbId,\n                  imdbId: imdbIds[idx],\n                };\n              }\n            }\n          }\n        }\n      }\n      this.mappingModified = mappingStat.mtime;\n      logger.info(\n        `Loaded ${\n          Object.keys(this.mapping).length\n        } AniDB items from mapping file`,\n        { label: 'Anime-List Sync' }\n      );\n    } catch (e) {\n      throw new Error(`Failed to load Anime-List mappings: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  private downloadFile = async () => {\n    logger.info('Downloading latest mapping file', {\n      label: 'Anime-List Sync',\n    });\n    try {\n      const response = await axios.get(MAPPING_URL, {\n        responseType: 'stream',\n      });\n      await new Promise<void>((resolve, reject) => {\n        const writer = fs.createWriteStream(LOCAL_PATH);\n        writer.on('finish', resolve);\n        writer.on('error', reject);\n        response.data.pipe(writer);\n      });\n    } catch (e) {\n      throw new Error(`Failed to download Anime-List mapping: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public sync = async () => {\n    // make sure only one sync runs at a time\n    if (this.syncing) {\n      return;\n    }\n\n    this.syncing = true;\n    try {\n      // check if local file is not \"expired\" yet\n      if (fs.existsSync(LOCAL_PATH)) {\n        const now = new Date();\n        const stat = await fsp.stat(LOCAL_PATH);\n        if (now.getTime() - stat.mtime.getTime() < UPDATE_INTERVAL_MSEC) {\n          if (!this.isLoaded()) {\n            // no need to download, but make sure file is loaded\n            await this.loadFromFile();\n          } else if (\n            this.mappingModified &&\n            stat.mtime.getTime() > this.mappingModified.getTime()\n          ) {\n            // if file has been modified externally since last load, reload it\n            await this.loadFromFile();\n          }\n          return;\n        }\n      }\n      await this.downloadFile();\n      await this.loadFromFile();\n    } finally {\n      this.syncing = false;\n    }\n  };\n\n  public getFromAnidbId = (anidbId: number): AnidbItem | undefined => {\n    return this.mapping[anidbId];\n  };\n\n  public getSpecialEpisode = (\n    tvdbId: number,\n    episode: number\n  ): AnidbItem | undefined => {\n    const episodes = this.specials[tvdbId];\n    return episodes ? episodes[episode] : undefined;\n  };\n}\n\nconst animeList = new AnimeListMapping();\n\nexport default animeList;\n"
  },
  {
    "path": "server/api/externalapi.ts",
    "content": "import { requestInterceptorFunction } from '@server/utils/customProxyAgent';\nimport type { AxiosInstance, AxiosRequestConfig } from 'axios';\nimport axios from 'axios';\nimport rateLimit from 'axios-rate-limit';\nimport type NodeCache from 'node-cache';\n\n// 5 minute default TTL (in seconds)\nconst DEFAULT_TTL = 300;\n\n// 10 seconds default rolling buffer (in ms)\nconst DEFAULT_ROLLING_BUFFER = 10000;\n\nexport interface ExternalAPIOptions {\n  nodeCache?: NodeCache;\n  headers?: Record<string, unknown>;\n  timeout?: number;\n  rateLimit?: {\n    maxRPS: number;\n    maxRequests: number;\n  };\n}\n\nclass ExternalAPI {\n  protected axios: AxiosInstance;\n  private baseUrl: string;\n  private cache?: NodeCache;\n\n  constructor(\n    baseUrl: string,\n    params: Record<string, unknown>,\n    options: ExternalAPIOptions = {}\n  ) {\n    this.axios = axios.create({\n      baseURL: baseUrl,\n      params,\n      timeout: options.timeout,\n      headers: {\n        'Content-Type': 'application/json',\n        Accept: 'application/json',\n        ...options.headers,\n      },\n    });\n    this.axios.interceptors.request.use(requestInterceptorFunction);\n\n    if (options.rateLimit) {\n      this.axios = rateLimit(this.axios, {\n        maxRequests: options.rateLimit.maxRequests,\n        maxRPS: options.rateLimit.maxRPS,\n      });\n    }\n\n    this.baseUrl = baseUrl;\n    this.cache = options.nodeCache;\n  }\n\n  protected async get<T>(\n    endpoint: string,\n    config?: AxiosRequestConfig,\n    ttl?: number\n  ): Promise<T> {\n    const cacheKey = this.serializeCacheKey(endpoint, {\n      ...config?.params,\n      headers: config?.headers,\n    });\n    const cachedItem = this.cache?.get<T>(cacheKey);\n    if (cachedItem) {\n      return cachedItem;\n    }\n\n    const response = await this.axios.get<T>(endpoint, config);\n\n    if (this.cache && ttl !== 0) {\n      this.cache.set(cacheKey, response.data, ttl ?? DEFAULT_TTL);\n    }\n\n    return response.data;\n  }\n\n  protected async post<T>(\n    endpoint: string,\n    data?: Record<string, unknown>,\n    config?: AxiosRequestConfig,\n    ttl?: number\n  ): Promise<T> {\n    const cacheKey = this.serializeCacheKey(endpoint, {\n      config: config?.params,\n      ...(data ? { data } : {}),\n    });\n\n    const cachedItem = this.cache?.get<T>(cacheKey);\n    if (cachedItem) {\n      return cachedItem;\n    }\n\n    const response = await this.axios.post<T>(endpoint, data, config);\n\n    if (this.cache && ttl !== 0) {\n      this.cache.set(cacheKey, response.data, ttl ?? DEFAULT_TTL);\n    }\n\n    return response.data;\n  }\n\n  protected async getRolling<T>(\n    endpoint: string,\n    config?: AxiosRequestConfig,\n    ttl?: number\n  ): Promise<T> {\n    const cacheKey = this.serializeCacheKey(endpoint, {\n      ...config?.params,\n      headers: config?.headers,\n    });\n    const cachedItem = this.cache?.get<T>(cacheKey);\n\n    if (cachedItem) {\n      const keyTtl = this.cache?.getTtl(cacheKey) ?? 0;\n\n      // If the item has passed our rolling check, fetch again in background\n      if (\n        keyTtl - (ttl ?? DEFAULT_TTL) * 1000 <\n        Date.now() - DEFAULT_ROLLING_BUFFER\n      ) {\n        this.axios.get<T>(endpoint, config).then((response) => {\n          this.cache?.set(cacheKey, response.data, ttl ?? DEFAULT_TTL);\n        });\n      }\n      return cachedItem;\n    }\n\n    const response = await this.axios.get<T>(endpoint, config);\n\n    if (this.cache && ttl !== 0) {\n      this.cache.set(cacheKey, response.data, ttl ?? DEFAULT_TTL);\n    }\n\n    return response.data;\n  }\n\n  protected removeCache(endpoint: string, options?: Record<string, unknown>) {\n    const cacheKey = this.serializeCacheKey(endpoint, {\n      ...options,\n    });\n    this.cache?.del(cacheKey);\n  }\n\n  private serializeCacheKey(\n    endpoint: string,\n    options?: Record<string, unknown>\n  ) {\n    if (!options) {\n      return `${this.baseUrl}${endpoint}`;\n    }\n\n    return `${this.baseUrl}${endpoint}${JSON.stringify(options)}`;\n  }\n}\n\nexport default ExternalAPI;\n"
  },
  {
    "path": "server/api/github.ts",
    "content": "import cacheManager from '@server/lib/cache';\nimport logger from '@server/logger';\nimport ExternalAPI from './externalapi';\n\ninterface GitHubRelease {\n  url: string;\n  assets_url: string;\n  upload_url: string;\n  html_url: string;\n  id: number;\n  node_id: string;\n  tag_name: string;\n  target_commitish: string;\n  name: string;\n  draft: boolean;\n  prerelease: boolean;\n  created_at: string;\n  published_at: string;\n  tarball_url: string;\n  zipball_url: string;\n  body: string;\n}\n\ninterface GithubCommit {\n  sha: string;\n  node_id: string;\n  commit: {\n    author: {\n      name: string;\n      email: string;\n      date: string;\n    };\n    committer: {\n      name: string;\n      email: string;\n      date: string;\n    };\n    message: string;\n    tree: {\n      sha: string;\n      url: string;\n    };\n    url: string;\n    comment_count: number;\n    verification: {\n      verified: boolean;\n      reason: string;\n      signature: string;\n      payload: string;\n    };\n  };\n  url: string;\n  html_url: string;\n  comments_url: string;\n  parents: [\n    {\n      sha: string;\n      url: string;\n      html_url: string;\n    },\n  ];\n}\n\nclass GithubAPI extends ExternalAPI {\n  constructor() {\n    super(\n      'https://api.github.com',\n      {},\n      {\n        headers: {\n          'Content-Type': 'application/json',\n          Accept: 'application/json',\n        },\n        nodeCache: cacheManager.getCache('github').data,\n      }\n    );\n  }\n\n  public async getSeerrReleases({\n    take = 20,\n  }: {\n    take?: number;\n  } = {}): Promise<GitHubRelease[]> {\n    try {\n      const data = await this.get<GitHubRelease[]>(\n        '/repos/seerr-team/seerr/releases',\n        {\n          params: {\n            per_page: take,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      logger.warn(\n        \"Failed to retrieve GitHub releases. This may be an issue on GitHub's end. Seerr can't check if it's on the latest version.\",\n        { label: 'GitHub API', errorMessage: e.message }\n      );\n      return [];\n    }\n  }\n\n  public async getSeerrCommits({\n    take = 20,\n    branch = 'develop',\n  }: {\n    take?: number;\n    branch?: string;\n  } = {}): Promise<GithubCommit[]> {\n    try {\n      const data = await this.get<GithubCommit[]>(\n        '/repos/seerr-team/seerr/commits',\n        {\n          params: {\n            per_page: take,\n            branch,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      logger.warn(\n        \"Failed to retrieve GitHub commits. This may be an issue on GitHub's end. Seerr can't check if it's on the latest version.\",\n        { label: 'GitHub API', errorMessage: e.message }\n      );\n      return [];\n    }\n  }\n}\n\nexport default GithubAPI;\n"
  },
  {
    "path": "server/api/jellyfin.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport ExternalAPI from '@server/api/externalapi';\nimport { ApiErrorCode } from '@server/constants/error';\nimport { MediaServerType } from '@server/constants/server';\nimport availabilitySync from '@server/lib/availabilitySync';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { ApiError } from '@server/types/error';\nimport { getAppVersion } from '@server/utils/appVersion';\n\nexport interface JellyfinUserResponse {\n  Name: string;\n  ServerId: string;\n  ServerName: string;\n  Id: string;\n  Configuration: {\n    GroupedFolders: string[];\n  };\n  Policy: {\n    IsAdministrator: boolean;\n  };\n  PrimaryImageTag?: string;\n}\n\nexport interface JellyfinDevice {\n  Id: string;\n  Name: string;\n  LastUserName: string;\n  AppName: string;\n  AppVersion: string;\n  LastUserId: string;\n  DateLastActivity: string;\n  Capabilities: Record<string, unknown>;\n}\n\nexport interface JellyfinDevicesResponse {\n  Items: JellyfinDevice[];\n  TotalRecordCount: number;\n  StartIndex: number;\n}\n\nexport interface JellyfinLoginResponse {\n  User: JellyfinUserResponse;\n  AccessToken: string;\n}\n\nexport interface JellyfinUserListResponse {\n  users: JellyfinUserResponse[];\n}\n\ninterface JellyfinMediaFolder {\n  Name: string;\n  Id: string;\n  Type: string;\n  CollectionType: string;\n}\n\nexport interface JellyfinLibrary {\n  type: 'show' | 'movie';\n  key: string;\n  title: string;\n  agent: string;\n}\n\nexport interface JellyfinLibraryItem {\n  Name: string;\n  Id: string;\n  HasSubtitles: boolean;\n  Type: 'Movie' | 'Episode' | 'Season' | 'Series';\n  LocationType: 'FileSystem' | 'Offline' | 'Remote' | 'Virtual';\n  SeriesName?: string;\n  SeriesId?: string;\n  SeasonId?: string;\n  SeasonName?: string;\n  IndexNumber?: number;\n  IndexNumberEnd?: number;\n  ParentIndexNumber?: number;\n  MediaType: string;\n}\n\nexport interface JellyfinMediaStream {\n  Codec: string;\n  Type: 'Video' | 'Audio' | 'Subtitle';\n  Height?: number;\n  Width?: number;\n  AverageFrameRate?: number;\n  RealFrameRate?: number;\n  Language?: string;\n  DisplayTitle: string;\n}\n\nexport interface JellyfinMediaSource {\n  Protocol: string;\n  Id: string;\n  Path: string;\n  Type: string;\n  VideoType: string;\n  MediaStreams: JellyfinMediaStream[];\n}\n\nexport interface JellyfinLibraryItemExtended extends JellyfinLibraryItem {\n  ProviderIds: {\n    Tmdb?: string;\n    TheMovieDb?: string;\n    Imdb?: string;\n    Tvdb?: string;\n    AniDB?: string;\n  };\n  MediaSources?: JellyfinMediaSource[];\n  Width?: number;\n  Height?: number;\n  IsHD?: boolean;\n  DateCreated?: string;\n}\n\ntype EpisodeReturn<T> = T extends { includeMediaInfo: true }\n  ? JellyfinLibraryItemExtended[]\n  : JellyfinLibraryItem[];\n\nexport interface JellyfinItemsReponse {\n  Items: JellyfinLibraryItemExtended[];\n  TotalRecordCount: number;\n  StartIndex: number;\n}\n\nclass JellyfinAPI extends ExternalAPI {\n  private userId?: string;\n  private mediaServerType: MediaServerType;\n\n  constructor(\n    jellyfinHost: string,\n    authToken?: string | null,\n    deviceId?: string | null\n  ) {\n    const settings = getSettings();\n    const safeDeviceId =\n      deviceId && deviceId.length > 0\n        ? deviceId\n        : Buffer.from('BOT_seerr').toString('base64');\n\n    let authHeaderVal: string;\n    if (authToken) {\n      authHeaderVal = `MediaBrowser Client=\"Seerr\", Device=\"Seerr\", DeviceId=\"${safeDeviceId}\", Version=\"${getAppVersion()}\", Token=\"${authToken}\"`;\n    } else {\n      authHeaderVal = `MediaBrowser Client=\"Seerr\", Device=\"Seerr\", DeviceId=\"${safeDeviceId}\", Version=\"${getAppVersion()}\"`;\n    }\n\n    super(\n      jellyfinHost,\n      {},\n      {\n        headers: {\n          Authorization: authHeaderVal,\n          'Content-Type': 'application/json',\n          Accept: 'application/json',\n        },\n      }\n    );\n\n    this.mediaServerType = settings.main.mediaServerType;\n  }\n\n  public async login(\n    Username?: string,\n    Password?: string,\n    ClientIP?: string\n  ): Promise<JellyfinLoginResponse> {\n    const authenticate = async (useHeaders: boolean) => {\n      const headers =\n        useHeaders && ClientIP ? { 'X-Forwarded-For': ClientIP } : {};\n\n      return this.post<JellyfinLoginResponse>(\n        '/Users/AuthenticateByName',\n        {\n          Username,\n          Pw: Password,\n        },\n        { headers }\n      );\n    };\n\n    try {\n      return await authenticate(true);\n    } catch (e) {\n      logger.debug('Failed to authenticate with headers', {\n        label: 'Jellyfin API',\n        error: e.response?.statusText,\n        ip: ClientIP,\n      });\n\n      if (!e.response?.status) {\n        throw new ApiError(404, ApiErrorCode.InvalidUrl);\n      }\n\n      if (e.response?.status === 401) {\n        throw new ApiError(e.response?.status, ApiErrorCode.InvalidCredentials);\n      }\n    }\n\n    try {\n      return await authenticate(false);\n    } catch (e) {\n      if (e.response?.status === 401) {\n        throw new ApiError(e.response?.status, ApiErrorCode.InvalidCredentials);\n      }\n\n      logger.error(\n        `Something went wrong while authenticating with the Jellyfin server: ${e.message}`,\n        {\n          label: 'Jellyfin API',\n          error: e.response?.status,\n          ip: ClientIP,\n        }\n      );\n\n      throw new ApiError(e.response?.status, ApiErrorCode.Unknown);\n    }\n  }\n\n  public setUserId(userId: string): void {\n    this.userId = userId;\n    return;\n  }\n\n  public async getSystemInfo(): Promise<any> {\n    try {\n      const systemInfoResponse = await this.get<any>('/System/Info');\n\n      return systemInfoResponse;\n    } catch (e) {\n      throw new ApiError(e.response?.status, ApiErrorCode.InvalidAuthToken);\n    }\n  }\n\n  public async getServerName(): Promise<string> {\n    try {\n      const serverResponse = await this.get<JellyfinUserResponse>(\n        '/System/Info/Public'\n      );\n\n      return serverResponse.ServerName;\n    } catch (e) {\n      logger.error(\n        `Something went wrong while getting the server name from the Jellyfin server: ${e.message}`,\n        { label: 'Jellyfin API', error: e.response?.status }\n      );\n\n      throw new ApiError(e.response?.status, ApiErrorCode.Unknown);\n    }\n  }\n\n  public async getUsers(): Promise<JellyfinUserListResponse> {\n    try {\n      const userReponse = await this.get<JellyfinUserResponse[]>(`/Users`);\n\n      return { users: userReponse };\n    } catch (e) {\n      logger.error(\n        `Something went wrong while getting the account from the Jellyfin server: ${e.message}`,\n        { label: 'Jellyfin API', error: e.response?.status }\n      );\n\n      throw new ApiError(e.response?.status, ApiErrorCode.InvalidAuthToken);\n    }\n  }\n\n  public async getUser(): Promise<JellyfinUserResponse> {\n    try {\n      const userReponse = await this.get<JellyfinUserResponse>(\n        `/Users/${this.userId ?? 'Me'}`\n      );\n      return userReponse;\n    } catch (e) {\n      logger.error(\n        `Something went wrong while getting the account from the Jellyfin server: ${e.message}`,\n        { label: 'Jellyfin API', error: e.response?.status }\n      );\n\n      throw new ApiError(e.response?.status, ApiErrorCode.InvalidAuthToken);\n    }\n  }\n\n  public async getLibraries(): Promise<JellyfinLibrary[]> {\n    try {\n      const mediaFolderResponse = await this.get<any>(`/Library/MediaFolders`);\n\n      return this.mapLibraries(mediaFolderResponse.Items);\n    } catch {\n      // fallback to user views to get libraries\n      // this only and maybe/depending on factors affects LDAP users\n      try {\n        const mediaFolderResponse = await this.get<any>(\n          `/Users/${this.userId ?? 'Me'}/Views`\n        );\n\n        return this.mapLibraries(mediaFolderResponse.Items);\n      } catch (e) {\n        logger.error(\n          `Something went wrong while getting libraries from the Jellyfin server: ${e.message}`,\n          {\n            label: 'Jellyfin API',\n            error: e.response?.status,\n          }\n        );\n\n        return [];\n      }\n    }\n  }\n\n  private mapLibraries(mediaFolders: JellyfinMediaFolder[]): JellyfinLibrary[] {\n    const excludedTypes = [\n      'music',\n      'books',\n      'musicvideos',\n      'homevideos',\n      'boxsets',\n    ];\n\n    return mediaFolders\n      .filter((Item: JellyfinMediaFolder) => {\n        return (\n          Item.Type === 'CollectionFolder' &&\n          !excludedTypes.includes(Item.CollectionType)\n        );\n      })\n      .map((Item: JellyfinMediaFolder) => {\n        return <JellyfinLibrary>{\n          key: Item.Id,\n          title: Item.Name,\n          type: Item.CollectionType === 'movies' ? 'movie' : 'show',\n          agent: 'jellyfin',\n        };\n      });\n  }\n\n  public async getLibraryContents(id: string): Promise<JellyfinLibraryItem[]> {\n    try {\n      const libraryItemsResponse = await this.get<any>(\n        `/Items?SortBy=SortName&SortOrder=Ascending&IncludeItemTypes=Series,Movie,Others&Recursive=true&StartIndex=0&ParentId=${id}&collapseBoxSetItems=false`\n      );\n\n      return libraryItemsResponse.Items.filter(\n        (item: JellyfinLibraryItem) => item.LocationType !== 'Virtual'\n      );\n    } catch (e) {\n      logger.error(\n        `Something went wrong while getting library content from the Jellyfin server: ${e.message}`,\n        { label: 'Jellyfin API', error: e?.response?.status }\n      );\n\n      throw new ApiError(e.response?.status, ApiErrorCode.InvalidAuthToken);\n    }\n  }\n\n  public async getRecentlyAdded(id: string): Promise<JellyfinLibraryItem[]> {\n    try {\n      const endpoint =\n        this.mediaServerType === MediaServerType.JELLYFIN\n          ? `/Items/Latest`\n          : `/Users/${this.userId}/Items/Latest`;\n      const itemResponse = await this.get<any>(\n        `${endpoint}?Limit=12&ParentId=${id}${\n          this.mediaServerType === MediaServerType.JELLYFIN\n            ? `&userId=${this.userId ?? 'Me'}`\n            : ''\n        }`\n      );\n\n      return itemResponse;\n    } catch (e) {\n      logger.error(\n        `Something went wrong while getting library content from the Jellyfin server: ${e.message}`,\n        { label: 'Jellyfin API', error: e.response?.status }\n      );\n\n      throw new ApiError(e.response?.status, ApiErrorCode.InvalidAuthToken);\n    }\n  }\n\n  public async getItemData(\n    id: string\n  ): Promise<JellyfinLibraryItemExtended | undefined> {\n    try {\n      const itemResponse = await this.get<JellyfinItemsReponse>(`/Items`, {\n        params: {\n          ids: id,\n          fields: 'ProviderIds,MediaSources,Width,Height,IsHD,DateCreated',\n        },\n      });\n\n      return itemResponse.Items?.[0];\n    } catch (e) {\n      if (availabilitySync.running) {\n        if (e.response?.status === 500) {\n          return undefined;\n        }\n      }\n\n      logger.error(\n        `Something went wrong while getting library content from the Jellyfin server: ${e.message}`,\n        { label: 'Jellyfin API', error: e.response?.status }\n      );\n      throw new ApiError(e.response?.status, ApiErrorCode.InvalidAuthToken);\n    }\n  }\n\n  public async getSeasons(seriesID: string): Promise<JellyfinLibraryItem[]> {\n    try {\n      const seasonResponse = await this.get<any>(`/Shows/${seriesID}/Seasons`);\n\n      return seasonResponse.Items;\n    } catch (e) {\n      logger.error(\n        `Something went wrong while getting the list of seasons from the Jellyfin server: ${e.message}`,\n        { label: 'Jellyfin API', error: e.response?.status }\n      );\n\n      throw new ApiError(e.response?.status, ApiErrorCode.InvalidAuthToken);\n    }\n  }\n\n  public async getEpisodes<\n    T extends { includeMediaInfo?: boolean } | undefined = undefined,\n  >(\n    seriesID: string,\n    seasonID: string,\n    options?: T\n  ): Promise<EpisodeReturn<T>> {\n    try {\n      const episodeResponse = await this.get<any>(\n        `/Shows/${seriesID}/Episodes`,\n        {\n          params: {\n            seasonId: seasonID,\n            ...(options?.includeMediaInfo && { fields: 'MediaSources' }),\n          },\n        }\n      );\n\n      return episodeResponse.Items.filter(\n        (item: JellyfinLibraryItem) => item.LocationType !== 'Virtual'\n      );\n    } catch (e) {\n      logger.error(\n        `Something went wrong while getting the list of episodes from the Jellyfin server: ${e.message}`,\n        { label: 'Jellyfin API', error: e.response?.status }\n      );\n\n      throw new ApiError(e.response?.status, ApiErrorCode.InvalidAuthToken);\n    }\n  }\n\n  public async createApiToken(appName: string): Promise<string> {\n    try {\n      await this.post(`/Auth/Keys?App=${appName}`);\n      const apiKeys = await this.get<any>(`/Auth/Keys`);\n      return apiKeys.Items.reverse().find(\n        (item: any) => item.AppName === appName\n      ).AccessToken;\n    } catch (e) {\n      logger.error(\n        `Something went wrong while creating an API key from the Jellyfin server: ${e.message}`,\n        { label: 'Jellyfin API', error: e.response?.status }\n      );\n\n      throw new ApiError(e.response?.status, ApiErrorCode.InvalidAuthToken);\n    }\n  }\n}\n\nexport default JellyfinAPI;\n"
  },
  {
    "path": "server/api/metadata.ts",
    "content": "import type { TvShowProvider } from '@server/api/provider';\nimport TheMovieDb from '@server/api/themoviedb';\nimport Tvdb from '@server/api/tvdb';\nimport { getSettings, MetadataProviderType } from '@server/lib/settings';\nimport logger from '@server/logger';\n\nexport const getMetadataProvider = async (\n  mediaType: 'movie' | 'tv' | 'anime'\n): Promise<TvShowProvider> => {\n  try {\n    const settings = await getSettings();\n\n    if (mediaType == 'movie') {\n      return new TheMovieDb();\n    }\n\n    if (\n      mediaType == 'tv' &&\n      settings.metadataSettings.tv == MetadataProviderType.TVDB\n    ) {\n      return await Tvdb.getInstance();\n    }\n\n    if (\n      mediaType == 'anime' &&\n      settings.metadataSettings.anime == MetadataProviderType.TVDB\n    ) {\n      return await Tvdb.getInstance();\n    }\n\n    return new TheMovieDb();\n  } catch (e) {\n    logger.error('Failed to get metadata provider', {\n      label: 'Metadata',\n      message: e.message,\n    });\n    return new TheMovieDb();\n  }\n};\n"
  },
  {
    "path": "server/api/plexapi.ts",
    "content": "import ExternalAPI from '@server/api/externalapi';\nimport type { Library, PlexSettings } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\n\ninterface PlexStatusResponse {\n  MediaContainer: {\n    machineIdentifier: string;\n    friendlyName: string;\n  };\n}\n\nexport interface PlexLibraryItem {\n  ratingKey: string;\n  parentRatingKey?: string;\n  grandparentRatingKey?: string;\n  title: string;\n  guid: string;\n  parentGuid?: string;\n  grandparentGuid?: string;\n  addedAt: number;\n  updatedAt: number;\n  Guid?: {\n    id: string;\n  }[];\n  type: 'movie' | 'show' | 'season' | 'episode';\n  Media: Media[];\n}\n\ninterface PlexLibraryResponse {\n  MediaContainer: {\n    totalSize: number;\n    Metadata: PlexLibraryItem[];\n  };\n}\n\nexport interface PlexLibrary {\n  type: 'show' | 'movie';\n  key: string;\n  title: string;\n  agent: string;\n}\n\ninterface PlexLibrariesResponse {\n  MediaContainer: {\n    Directory: PlexLibrary[];\n  };\n}\n\nexport interface PlexMetadata {\n  ratingKey: string;\n  parentRatingKey?: string;\n  guid: string;\n  type: 'movie' | 'show' | 'season';\n  title: string;\n  Guid: {\n    id: string;\n  }[];\n  Children?: {\n    size: 12;\n    Metadata: PlexMetadata[];\n  };\n  index: number;\n  parentIndex?: number;\n  leafCount: number;\n  viewedLeafCount: number;\n  addedAt: number;\n  updatedAt: number;\n  Media: Media[];\n}\n\ninterface Media {\n  id: number;\n  duration: number;\n  bitrate: number;\n  width: number;\n  height: number;\n  aspectRatio: number;\n  audioChannels: number;\n  audioCodec: string;\n  videoCodec: string;\n  videoResolution: string;\n  container: string;\n  videoFrameRate: string;\n  videoProfile: string;\n}\n\ninterface PlexMetadataResponse {\n  MediaContainer: {\n    Metadata: PlexMetadata[];\n  };\n}\n\nclass PlexAPI extends ExternalAPI {\n  constructor({\n    plexToken,\n    plexSettings,\n    timeout,\n  }: {\n    plexToken?: string | null;\n    plexSettings?: PlexSettings;\n    timeout?: number;\n  }) {\n    const settings = getSettings();\n    const settingsPlex = plexSettings ?? settings.plex;\n\n    const protocol = settingsPlex.useSsl ? 'https' : 'http';\n    const baseUrl = `${protocol}://${settingsPlex.ip}:${settingsPlex.port}`;\n\n    super(\n      baseUrl,\n      {},\n      {\n        timeout,\n        headers: {\n          'X-Plex-Token': plexToken ?? '',\n          'X-Plex-Client-Identifier': settings.clientId,\n          'X-Plex-Product': 'Seerr',\n          'X-Plex-Device-Name': 'Seerr',\n          'X-Plex-Platform': 'Seerr',\n        },\n      }\n    );\n  }\n\n  public async getStatus(): Promise<PlexStatusResponse> {\n    return await this.get('/');\n  }\n\n  public async getLibraries(): Promise<PlexLibrary[]> {\n    const response = await this.get<PlexLibrariesResponse>('/library/sections');\n\n    return response.MediaContainer.Directory;\n  }\n\n  public async syncLibraries(): Promise<void> {\n    const settings = getSettings();\n\n    try {\n      const libraries = await this.getLibraries();\n\n      const newLibraries: Library[] = libraries\n        // Remove libraries that are not movie or show\n        .filter(\n          (library) => library.type === 'movie' || library.type === 'show'\n        )\n        // Remove libraries that do not have a metadata agent set (usually personal video libraries)\n        .filter((library) => library.agent !== 'com.plexapp.agents.none')\n        .map((library) => {\n          const existing = settings.plex.libraries.find(\n            (l) => l.id === library.key && l.name === library.title\n          );\n\n          return {\n            id: library.key,\n            name: library.title,\n            enabled: existing?.enabled ?? false,\n            type: library.type,\n            lastScan: existing?.lastScan,\n          };\n        });\n\n      settings.plex.libraries = newLibraries;\n    } catch (e) {\n      logger.error('Failed to fetch Plex libraries', {\n        label: 'Plex API',\n        message: e.message,\n      });\n\n      settings.plex.libraries = [];\n    }\n\n    await settings.save();\n  }\n\n  public async getLibraryContents(\n    id: string,\n    { offset = 0, size = 50 }: { offset?: number; size?: number } = {}\n  ): Promise<{ totalSize: number; items: PlexLibraryItem[] }> {\n    const response = await this.get<PlexLibraryResponse>(\n      `/library/sections/${id}/all?includeGuids=1`,\n      {\n        headers: {\n          'X-Plex-Container-Start': `${offset}`,\n          'X-Plex-Container-Size': `${size}`,\n        },\n      }\n    );\n\n    return {\n      totalSize: response.MediaContainer.totalSize,\n      items: response.MediaContainer.Metadata ?? [],\n    };\n  }\n\n  public async getMetadata(\n    key: string,\n    options: { includeChildren?: boolean } = {}\n  ): Promise<PlexMetadata> {\n    const response = await this.get<PlexMetadataResponse>(\n      `/library/metadata/${key}${\n        options.includeChildren ? '?includeChildren=1' : ''\n      }`\n    );\n\n    return response.MediaContainer.Metadata[0];\n  }\n\n  public async getChildrenMetadata(key: string): Promise<PlexMetadata[]> {\n    const response = await this.get<PlexMetadataResponse>(\n      `/library/metadata/${key}/children`\n    );\n\n    return response.MediaContainer.Metadata;\n  }\n\n  public async getRecentlyAdded(\n    id: string,\n    options: { addedAt: number } = {\n      addedAt: Date.now() - 1000 * 60 * 60,\n    },\n    mediaType: 'movie' | 'show'\n  ): Promise<PlexLibraryItem[]> {\n    const response = await this.get<PlexLibraryResponse>(\n      `/library/sections/${id}/all?type=${\n        mediaType === 'show' ? '4' : '1'\n      }&sort=addedAt%3Adesc&addedAt>>=${Math.floor(options.addedAt / 1000)}`,\n      {\n        headers: {\n          'X-Plex-Container-Start': '0',\n          'X-Plex-Container-Size': '500',\n        },\n      }\n    );\n\n    return response.MediaContainer.Metadata;\n  }\n}\n\nexport default PlexAPI;\n"
  },
  {
    "path": "server/api/plextv.ts",
    "content": "import type { PlexDevice } from '@server/interfaces/api/plexInterfaces';\nimport cacheManager from '@server/lib/cache';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { randomUUID } from 'node:crypto';\nimport xml2js from 'xml2js';\nimport ExternalAPI from './externalapi';\n\ninterface PlexAccountResponse {\n  user: PlexUser;\n}\n\ninterface PlexUser {\n  id: number;\n  uuid: string;\n  email: string;\n  joined_at: string;\n  username: string;\n  title: string;\n  thumb: string;\n  hasPassword: boolean;\n  authToken: string;\n  subscription: {\n    active: boolean;\n    status: string;\n    plan: string;\n    features: string[];\n  };\n  roles: {\n    roles: string[];\n  };\n  entitlements: string[];\n}\n\ninterface ConnectionResponse {\n  $: {\n    protocol: string;\n    address: string;\n    port: string;\n    uri: string;\n    local: string;\n  };\n}\n\ninterface DeviceResponse {\n  $: {\n    name: string;\n    product: string;\n    productVersion: string;\n    platform: string;\n    platformVersion: string;\n    device: string;\n    clientIdentifier: string;\n    createdAt: string;\n    lastSeenAt: string;\n    provides: string;\n    owned: string;\n    accessToken?: string;\n    publicAddress?: string;\n    httpsRequired?: string;\n    synced?: string;\n    relay?: string;\n    dnsRebindingProtection?: string;\n    natLoopbackSupported?: string;\n    publicAddressMatches?: string;\n    presence?: string;\n    ownerID?: string;\n    home?: string;\n    sourceTitle?: string;\n  };\n  Connection: ConnectionResponse[];\n}\n\ninterface ServerResponse {\n  $: {\n    id: string;\n    serverId: string;\n    machineIdentifier: string;\n    name: string;\n    lastSeenAt: string;\n    numLibraries: string;\n    owned: string;\n  };\n}\n\ninterface UsersResponse {\n  MediaContainer: {\n    User: {\n      $: {\n        id: string;\n        title: string;\n        username: string;\n        email: string;\n        thumb: string;\n      };\n      Server: ServerResponse[];\n    }[];\n  };\n}\n\ninterface WatchlistResponse {\n  MediaContainer: {\n    totalSize: number;\n    Metadata?: {\n      ratingKey: string;\n    }[];\n  };\n}\n\ninterface MetadataResponse {\n  MediaContainer: {\n    Metadata: {\n      ratingKey: string;\n      type: 'movie' | 'show';\n      title: string;\n      Guid?: {\n        id: `imdb://tt${number}` | `tmdb://${number}` | `tvdb://${number}`;\n      }[];\n    }[];\n  };\n}\n\nexport interface PlexWatchlistItem {\n  ratingKey: string;\n  tmdbId: number;\n  tvdbId?: number;\n  type: 'movie' | 'show';\n  title: string;\n}\n\nexport interface PlexWatchlistCache {\n  etag: string;\n  response: WatchlistResponse;\n}\n\nclass PlexTvAPI extends ExternalAPI {\n  private authToken: string;\n\n  constructor(authToken: string) {\n    super(\n      'https://plex.tv',\n      {},\n      {\n        headers: {\n          'X-Plex-Token': authToken,\n          'Content-Type': 'application/json',\n          Accept: 'application/json',\n        },\n        nodeCache: cacheManager.getCache('plextv').data,\n      }\n    );\n\n    this.authToken = authToken;\n  }\n\n  public async getDevices(): Promise<PlexDevice[]> {\n    try {\n      const devicesResp = await this.axios.get(\n        '/api/resources?includeHttps=1',\n        {\n          transformResponse: [],\n          responseType: 'text',\n        }\n      );\n      const parsedXml = await xml2js.parseStringPromise(\n        devicesResp.data as DeviceResponse\n      );\n      return parsedXml?.MediaContainer?.Device?.map((pxml: DeviceResponse) => ({\n        name: pxml.$.name,\n        product: pxml.$.product,\n        productVersion: pxml.$.productVersion,\n        platform: pxml.$?.platform,\n        platformVersion: pxml.$?.platformVersion,\n        device: pxml.$?.device,\n        clientIdentifier: pxml.$.clientIdentifier,\n        createdAt: new Date(parseInt(pxml.$?.createdAt, 10) * 1000),\n        lastSeenAt: new Date(parseInt(pxml.$?.lastSeenAt, 10) * 1000),\n        provides: pxml.$.provides.split(','),\n        owned: pxml.$.owned == '1' ? true : false,\n        accessToken: pxml.$?.accessToken,\n        publicAddress: pxml.$?.publicAddress,\n        publicAddressMatches:\n          pxml.$?.publicAddressMatches == '1' ? true : false,\n        httpsRequired: pxml.$?.httpsRequired == '1' ? true : false,\n        synced: pxml.$?.synced == '1' ? true : false,\n        relay: pxml.$?.relay == '1' ? true : false,\n        dnsRebindingProtection:\n          pxml.$?.dnsRebindingProtection == '1' ? true : false,\n        natLoopbackSupported:\n          pxml.$?.natLoopbackSupported == '1' ? true : false,\n        presence: pxml.$?.presence == '1' ? true : false,\n        ownerID: pxml.$?.ownerID,\n        home: pxml.$?.home == '1' ? true : false,\n        sourceTitle: pxml.$?.sourceTitle,\n        connection: pxml?.Connection?.map((conn: ConnectionResponse) => ({\n          protocol: conn.$.protocol,\n          address: conn.$.address,\n          port: parseInt(conn.$.port, 10),\n          uri: conn.$.uri,\n          local: conn.$.local == '1' ? true : false,\n        })),\n      }));\n    } catch (e) {\n      logger.error('Something went wrong getting the devices from plex.tv', {\n        label: 'Plex.tv API',\n        errorMessage: e.message,\n      });\n      throw new Error('Invalid auth token', { cause: e });\n    }\n  }\n\n  public async getUser(): Promise<PlexUser> {\n    try {\n      const account = await this.axios.get<PlexAccountResponse>(\n        '/users/account.json'\n      );\n\n      return account.data.user;\n    } catch (e) {\n      logger.error(\n        `Something went wrong while getting the account from plex.tv: ${e.message}`,\n        { label: 'Plex.tv API' }\n      );\n      throw new Error('Invalid auth token', { cause: e });\n    }\n  }\n\n  public async checkUserAccess(userId: number): Promise<boolean> {\n    const settings = getSettings();\n\n    try {\n      if (!settings.plex.machineId) {\n        throw new Error('Plex is not configured!');\n      }\n\n      const usersResponse = await this.getUsers();\n\n      const users = usersResponse.MediaContainer.User;\n\n      const user = users.find((u) => parseInt(u.$.id) === userId);\n\n      if (!user) {\n        throw new Error(\n          \"This user does not exist on the main Plex account's shared list\"\n        );\n      }\n\n      return !!user.Server?.find(\n        (server) => server.$.machineIdentifier === settings.plex.machineId\n      );\n    } catch (e) {\n      logger.error(`Error checking user access: ${e.message}`);\n      return false;\n    }\n  }\n\n  public async getUsers(): Promise<UsersResponse> {\n    const response = await this.axios.get('/api/users', {\n      transformResponse: [],\n      responseType: 'text',\n    });\n\n    const parsedXml = (await xml2js.parseStringPromise(\n      response.data\n    )) as UsersResponse;\n    return parsedXml;\n  }\n\n  public async getWatchlist({\n    offset = 0,\n    size = 20,\n  }: { offset?: number; size?: number } = {}): Promise<{\n    offset: number;\n    size: number;\n    totalSize: number;\n    items: PlexWatchlistItem[];\n  }> {\n    try {\n      const watchlistCache = cacheManager.getCache('plexwatchlist');\n      let cachedWatchlist = watchlistCache.data.get<PlexWatchlistCache>(\n        this.authToken\n      );\n\n      const response = await this.axios.get<WatchlistResponse>(\n        '/library/sections/watchlist/all',\n        {\n          params: {\n            'X-Plex-Container-Start': offset,\n            'X-Plex-Container-Size': size,\n          },\n          headers: {\n            'If-None-Match': cachedWatchlist?.etag,\n          },\n          baseURL: 'https://discover.provider.plex.tv',\n          validateStatus: (status) => status < 400, // Allow HTTP 304 to return without error\n        }\n      );\n\n      // If we don't recieve HTTP 304, the watchlist has been updated and we need to update the cache.\n      if (response.status >= 200 && response.status <= 299) {\n        cachedWatchlist = {\n          etag: response.headers.etag,\n          response: response.data,\n        };\n\n        watchlistCache.data.set<PlexWatchlistCache>(\n          this.authToken,\n          cachedWatchlist\n        );\n      }\n\n      const watchlistDetails = await Promise.all(\n        (cachedWatchlist?.response.MediaContainer.Metadata ?? []).map(\n          async (watchlistItem) => {\n            let detailedResponse: MetadataResponse;\n            try {\n              detailedResponse = await this.getRolling<MetadataResponse>(\n                `/library/metadata/${watchlistItem.ratingKey}`,\n                {\n                  baseURL: 'https://discover.provider.plex.tv',\n                }\n              );\n            } catch (e) {\n              if (e.response?.status === 404) {\n                logger.warn(\n                  `Item with ratingKey ${watchlistItem.ratingKey} not found, it may have been removed from the server.`,\n                  { label: 'Plex.TV Metadata API' }\n                );\n                return null;\n              } else {\n                throw e;\n              }\n            }\n\n            const metadata = detailedResponse.MediaContainer.Metadata[0];\n\n            const tmdbString = metadata.Guid?.find((guid) =>\n              guid.id.startsWith('tmdb')\n            );\n            const tvdbString = metadata.Guid?.find((guid) =>\n              guid.id.startsWith('tvdb')\n            );\n\n            return {\n              ratingKey: metadata.ratingKey,\n              // This should always be set? But I guess it also cannot be?\n              // We will filter out the 0's afterwards\n              tmdbId: tmdbString ? Number(tmdbString.id.split('//')[1]) : 0,\n              tvdbId: tvdbString\n                ? Number(tvdbString.id.split('//')[1])\n                : undefined,\n              title: metadata.title,\n              type: metadata.type,\n            };\n          }\n        )\n      );\n\n      const filteredList = watchlistDetails.filter(\n        (detail) => detail?.tmdbId\n      ) as PlexWatchlistItem[];\n\n      return {\n        offset,\n        size,\n        totalSize: cachedWatchlist?.response.MediaContainer.totalSize ?? 0,\n        items: filteredList,\n      };\n    } catch (e) {\n      logger.error('Failed to retrieve watchlist items', {\n        label: 'Plex.TV Metadata API',\n        errorMessage: e.message,\n      });\n      return {\n        offset,\n        size,\n        totalSize: 0,\n        items: [],\n      };\n    }\n  }\n\n  public async pingToken() {\n    try {\n      const response = await this.axios.get('/api/v2/ping', {\n        headers: {\n          'X-Plex-Client-Identifier': randomUUID(),\n        },\n      });\n      if (!response?.data?.pong) {\n        throw new Error('No pong response');\n      }\n    } catch (e) {\n      logger.error('Failed to ping token', {\n        label: 'Plex Refresh Token',\n        errorMessage: e.message,\n      });\n    }\n  }\n}\n\nexport default PlexTvAPI;\n"
  },
  {
    "path": "server/api/provider.ts",
    "content": "import type {\n  TmdbSeasonWithEpisodes,\n  TmdbTvDetails,\n} from '@server/api/themoviedb/interfaces';\n\nexport interface TvShowProvider {\n  getTvShow({\n    tvId,\n    language,\n  }: {\n    tvId: number;\n    language?: string;\n  }): Promise<TmdbTvDetails>;\n  getTvSeason({\n    tvId,\n    seasonNumber,\n    language,\n  }: {\n    tvId: number;\n    seasonNumber: number;\n    language?: string;\n  }): Promise<TmdbSeasonWithEpisodes>;\n  getShowByTvdbId({\n    tvdbId,\n    language,\n  }: {\n    tvdbId: number;\n    language?: string;\n  }): Promise<TmdbTvDetails>;\n}\n"
  },
  {
    "path": "server/api/pushover.ts",
    "content": "import ExternalAPI from './externalapi';\n\ninterface PushoverSoundsResponse {\n  sounds: {\n    [name: string]: string;\n  };\n  status: number;\n  request: string;\n}\n\nexport interface PushoverSound {\n  name: string;\n  description: string;\n}\n\nexport const mapSounds = (sounds: {\n  [name: string]: string;\n}): PushoverSound[] =>\n  Object.entries(sounds).map(\n    ([name, description]) =>\n      ({\n        name,\n        description,\n      }) as PushoverSound\n  );\n\nclass PushoverAPI extends ExternalAPI {\n  constructor() {\n    super(\n      'https://api.pushover.net/1',\n      {},\n      {\n        headers: {\n          'Content-Type': 'application/json',\n          Accept: 'application/json',\n        },\n      }\n    );\n  }\n\n  public async getSounds(appToken: string): Promise<PushoverSound[]> {\n    try {\n      const data = await this.get<PushoverSoundsResponse>('/sounds.json', {\n        params: {\n          token: appToken,\n        },\n      });\n\n      return mapSounds(data.sounds);\n    } catch (e) {\n      throw new Error(`[Pushover] Failed to retrieve sounds: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n}\n\nexport default PushoverAPI;\n"
  },
  {
    "path": "server/api/rating/imdbRadarrProxy.ts",
    "content": "import ExternalAPI from '@server/api/externalapi';\nimport cacheManager from '@server/lib/cache';\n\ntype IMDBRadarrProxyResponse = IMDBMovie[];\n\ninterface IMDBMovie {\n  ImdbId: string;\n  Overview: string;\n  Title: string;\n  OriginalTitle: string;\n  TitleSlug: string;\n  Ratings: Rating[];\n  MovieRatings: MovieRatings;\n  Runtime: number;\n  Images: Image[];\n  Genres: string[];\n  Popularity: number;\n  Premier: string;\n  InCinema: string;\n  PhysicalRelease: any;\n  DigitalRelease: string;\n  Year: number;\n  AlternativeTitles: AlternativeTitle[];\n  Translations: Translation[];\n  Recommendations: Recommendation[];\n  Credits: Credits;\n  Studio: string;\n  YoutubeTrailerId: string;\n  Certifications: Certification[];\n  Status: any;\n  Collection: Collection;\n  OriginalLanguage: string;\n  Homepage: string;\n  TmdbId: number;\n}\n\ninterface Rating {\n  Count: number;\n  Value: number;\n  Origin: string;\n  Type: string;\n}\n\ninterface MovieRatings {\n  Tmdb: Tmdb;\n  Imdb: Imdb;\n  Metacritic: Metacritic;\n  RottenTomatoes: RottenTomatoes;\n}\n\ninterface Tmdb {\n  Count: number;\n  Value: number;\n  Type: string;\n}\n\ninterface Imdb {\n  Count: number;\n  Value: number;\n  Type: string;\n}\n\ninterface Metacritic {\n  Count: number;\n  Value: number;\n  Type: string;\n}\n\ninterface RottenTomatoes {\n  Count: number;\n  Value: number;\n  Type: string;\n}\n\ninterface Image {\n  CoverType: string;\n  Url: string;\n}\n\ninterface AlternativeTitle {\n  Title: string;\n  Type: string;\n  Language: string;\n}\n\ninterface Translation {\n  Title: string;\n  Overview: string;\n  Language: string;\n}\n\ninterface Recommendation {\n  TmdbId: number;\n  Title: string;\n}\n\ninterface Credits {\n  Cast: Cast[];\n  Crew: Crew[];\n}\n\ninterface Cast {\n  Name: string;\n  Order: number;\n  Character: string;\n  TmdbId: number;\n  CreditId: string;\n  Images: Image2[];\n}\n\ninterface Image2 {\n  CoverType: string;\n  Url: string;\n}\n\ninterface Crew {\n  Name: string;\n  Job: string;\n  Department: string;\n  TmdbId: number;\n  CreditId: string;\n  Images: Image3[];\n}\n\ninterface Image3 {\n  CoverType: string;\n  Url: string;\n}\n\ninterface Certification {\n  Country: string;\n  Certification: string;\n}\n\ninterface Collection {\n  Name: string;\n  Images: any;\n  Overview: any;\n  Translations: any;\n  Parts: any;\n  TmdbId: number;\n}\n\nexport interface IMDBRating {\n  title: string;\n  url: string;\n  criticsScore: number;\n  criticsScoreCount: number;\n}\n\n/**\n * This is a best-effort API. The IMDB API is technically\n * private and getting access costs money/requires approval.\n *\n * Radarr hosts a public proxy that's in use by all Radarr instances.\n */\nclass IMDBRadarrProxy extends ExternalAPI {\n  constructor() {\n    super('https://api.radarr.video/v1', {\n      headers: {\n        'Content-Type': 'application/json',\n        Accept: 'application/json',\n      },\n      nodeCache: cacheManager.getCache('imdb').data,\n    });\n  }\n\n  /**\n   * Ask the Radarr IMDB Proxy for the movie\n   *\n   * @param IMDBid Id of IMDB movie\n   */\n  public async getMovieRatings(IMDBid: string): Promise<IMDBRating | null> {\n    try {\n      const data = await this.get<IMDBRadarrProxyResponse>(\n        `/movie/imdb/${IMDBid}`\n      );\n\n      if (\n        !data?.length ||\n        data[0].ImdbId !== IMDBid ||\n        !data[0].MovieRatings.Imdb\n      ) {\n        return null;\n      }\n\n      return {\n        title: data[0].Title,\n        url: `https://www.imdb.com/title/${data[0].ImdbId}`,\n        criticsScore: data[0].MovieRatings.Imdb.Value,\n        criticsScoreCount: data[0].MovieRatings.Imdb.Count,\n      };\n    } catch (e) {\n      throw new Error(\n        `[IMDB RADARR PROXY API] Failed to retrieve movie ratings: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n}\n\nexport default IMDBRadarrProxy;\n"
  },
  {
    "path": "server/api/rating/rottentomatoes.ts",
    "content": "import ExternalAPI from '@server/api/externalapi';\nimport cacheManager from '@server/lib/cache';\nimport { getSettings } from '@server/lib/settings';\nimport jaro from 'wink-jaro-distance';\n\ninterface RTAlgoliaSearchResponse {\n  results: {\n    hits: RTAlgoliaHit[];\n    index: 'content_rt' | 'people_rt';\n  }[];\n}\n\ninterface RTAlgoliaHit {\n  emsId: string;\n  emsVersionId: string;\n  tmsId: string;\n  type: string;\n  title: string;\n  titles?: string[];\n  description: string;\n  releaseYear: number;\n  rating: string;\n  genres: string[];\n  updateDate: string;\n  isEmsSearchable: boolean;\n  rtId: number;\n  vanity: string;\n  aka?: string[];\n  posterImageUrl: string;\n  rottenTomatoes?: {\n    audienceScore: number;\n    criticsIconUrl: string;\n    wantToSeeCount: number;\n    audienceIconUrl: string;\n    scoreSentiment: string;\n    certifiedFresh: boolean;\n    criticsScore: number;\n  };\n}\n\nexport interface RTRating {\n  title: string;\n  year: number;\n  criticsRating: 'Certified Fresh' | 'Fresh' | 'Rotten';\n  criticsScore: number;\n  audienceRating?: 'Upright' | 'Spilled';\n  audienceScore?: number;\n  url: string;\n}\n\n// Tunables\nconst INEXACT_TITLE_FACTOR = 0.25;\nconst ALTERNATE_TITLE_FACTOR = 0.8;\nconst PER_YEAR_PENALTY = 0.4;\nconst MINIMUM_SCORE = 0.175;\n\n// Normalization for title comparisons.\n// Lowercase and strip non-alphanumeric (unicode-aware).\nconst norm = (s: string): string =>\n  s.toLowerCase().replace(/[^\\p{L}\\p{N} ]/gu, '');\n\n// Title similarity. 1 if exact, quarter-jaro otherwise.\nconst similarity = (a: string, b: string): number =>\n  a === b ? 1 : jaro(a, b).similarity * INEXACT_TITLE_FACTOR;\n\n// Gets the best similarity score between the searched title and all alternate\n// titles of the search result. Non-main titles are penalized.\nconst t_score = ({ title, titles, aka }: RTAlgoliaHit, s: string): number => {\n  const f = (t: string, i: number) =>\n    similarity(norm(t), norm(s)) * (i ? ALTERNATE_TITLE_FACTOR : 1);\n  return Math.max(...[title].concat(aka || [], titles || []).map(f));\n};\n\n// Year difference to score: 0 -> 1.0, 1 -> 0.6, 2 -> 0.2, 3+ -> 0.0\nconst y_score = (r: RTAlgoliaHit, y?: number): number =>\n  y ? Math.max(0, 1 - Math.abs(r.releaseYear - y) * PER_YEAR_PENALTY) : 1;\n\n// Cut score in half if result has no ratings.\nconst extra_score = (r: RTAlgoliaHit): number => (r.rottenTomatoes ? 1 : 0.5);\n\n// Score search result as product of all subscores\nconst score = (r: RTAlgoliaHit, name: string, year?: number): number =>\n  t_score(r, name) * y_score(r, year) * extra_score(r);\n\n// Score each search result and return the highest scoring result, if any\nconst best = (rs: RTAlgoliaHit[], name: string, year?: number): RTAlgoliaHit =>\n  rs\n    .map((r) => ({ score: score(r, name, year), result: r }))\n    .filter(({ score }) => score > MINIMUM_SCORE)\n    .sort(({ score: a }, { score: b }) => b - a)[0]?.result;\n\n/**\n * This is a best-effort API. The Rotten Tomatoes API is technically\n * private and getting access costs money/requires approval.\n *\n * They do, however, have a \"public\" api that they use to request the\n * data on their own site. We use this to get ratings for movies/tv shows.\n *\n * Unfortunately, we need to do it by searching for the movie name, so it's\n * not always accurate.\n */\nclass RottenTomatoes extends ExternalAPI {\n  constructor() {\n    const settings = getSettings();\n    super(\n      'https://79frdp12pn-dsn.algolia.net/1/indexes/*',\n      {\n        'x-algolia-agent':\n          'Algolia%20for%20JavaScript%20(4.14.3)%3B%20Browser%20(lite)',\n        'x-algolia-api-key': '175588f6e5f8319b27702e4cc4013561',\n        'x-algolia-application-id': '79FRDP12PN',\n      },\n      {\n        headers: {\n          'Content-Type': 'application/json',\n          Accept: 'application/json',\n          'x-algolia-usertoken': settings.clientId,\n        },\n        nodeCache: cacheManager.getCache('rt').data,\n      }\n    );\n  }\n\n  /**\n   * Search the RT algolia api for the movie title\n   *\n   * We compare the release date to make sure its the correct\n   * match. But it's not guaranteed to have results.\n   *\n   * @param name Movie name\n   * @param year Release Year\n   */\n  public async getMovieRatings(\n    name: string,\n    year: number\n  ): Promise<RTRating | null> {\n    try {\n      const filters = encodeURIComponent('isEmsSearchable=1 AND type:\"movie\"');\n      const data = await this.post<RTAlgoliaSearchResponse>('/queries', {\n        requests: [\n          {\n            indexName: 'content_rt',\n            query: name.replace(/\\bthe\\b ?/gi, ''),\n            params: `filters=${filters}&hitsPerPage=20`,\n          },\n        ],\n      });\n\n      const contentResults = data.results.find((r) => r.index === 'content_rt');\n      const movie = best(contentResults?.hits || [], name, year);\n\n      if (!movie?.rottenTomatoes) return null;\n\n      return {\n        title: movie.title,\n        url: `https://www.rottentomatoes.com/m/${movie.vanity}`,\n        criticsRating: movie.rottenTomatoes.certifiedFresh\n          ? 'Certified Fresh'\n          : movie.rottenTomatoes.criticsScore >= 60\n            ? 'Fresh'\n            : 'Rotten',\n        criticsScore: movie.rottenTomatoes.criticsScore,\n        audienceRating:\n          movie.rottenTomatoes.audienceScore >= 60 ? 'Upright' : 'Spilled',\n        audienceScore: movie.rottenTomatoes.audienceScore,\n        year: Number(movie.releaseYear),\n      };\n    } catch (e) {\n      throw new Error(\n        `[RT API] Failed to retrieve movie ratings: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getTVRatings(\n    name: string,\n    year?: number\n  ): Promise<RTRating | null> {\n    try {\n      const filters = encodeURIComponent('isEmsSearchable=1 AND type:\"tv\"');\n      const data = await this.post<RTAlgoliaSearchResponse>('/queries', {\n        requests: [\n          {\n            indexName: 'content_rt',\n            query: name,\n            params: `filters=${filters}&hitsPerPage=20`,\n          },\n        ],\n      });\n\n      const contentResults = data.results.find((r) => r.index === 'content_rt');\n      const tvshow = best(contentResults?.hits || [], name, year);\n\n      if (!tvshow?.rottenTomatoes) return null;\n\n      return {\n        title: tvshow.title,\n        url: `https://www.rottentomatoes.com/tv/${tvshow.vanity}`,\n        criticsRating:\n          tvshow.rottenTomatoes.criticsScore >= 60 ? 'Fresh' : 'Rotten',\n        criticsScore: tvshow.rottenTomatoes.criticsScore,\n        audienceRating:\n          tvshow.rottenTomatoes.audienceScore >= 60 ? 'Upright' : 'Spilled',\n        audienceScore: tvshow.rottenTomatoes.audienceScore,\n        year: Number(tvshow.releaseYear),\n      };\n    } catch (e) {\n      throw new Error(`[RT API] Failed to retrieve tv ratings: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n}\n\nexport default RottenTomatoes;\n"
  },
  {
    "path": "server/api/ratings.ts",
    "content": "import { type IMDBRating } from '@server/api/rating/imdbRadarrProxy';\nimport { type RTRating } from '@server/api/rating/rottentomatoes';\n\nexport interface RatingResponse {\n  rt?: RTRating;\n  imdb?: IMDBRating;\n}\n"
  },
  {
    "path": "server/api/servarr/base.ts",
    "content": "import ExternalAPI from '@server/api/externalapi';\nimport type { AvailableCacheIds } from '@server/lib/cache';\nimport cacheManager from '@server/lib/cache';\nimport { getSettings, type DVRSettings } from '@server/lib/settings';\n\nexport interface SystemStatus {\n  version: string;\n  buildTime: Date;\n  isDebug: boolean;\n  isProduction: boolean;\n  isAdmin: boolean;\n  isUserInteractive: boolean;\n  startupPath: string;\n  appData: string;\n  osName: string;\n  osVersion: string;\n  isNetCore: boolean;\n  isMono: boolean;\n  isLinux: boolean;\n  isOsx: boolean;\n  isWindows: boolean;\n  isDocker: boolean;\n  mode: string;\n  branch: string;\n  authentication: string;\n  sqliteVersion: string;\n  migrationVersion: number;\n  urlBase: string;\n  runtimeVersion: string;\n  runtimeName: string;\n  startTime: Date;\n  packageUpdateMechanism: string;\n}\n\nexport interface RootFolder {\n  id: number;\n  path: string;\n  freeSpace: number;\n  totalSpace: number;\n  unmappedFolders: {\n    name: string;\n    path: string;\n  }[];\n}\n\nexport interface QualityProfile {\n  id: number;\n  name: string;\n}\n\ninterface QueueItem {\n  size: number;\n  title: string;\n  sizeleft: number;\n  timeleft: string;\n  estimatedCompletionTime: string;\n  status: string;\n  trackedDownloadStatus: string;\n  trackedDownloadState: string;\n  downloadId: string;\n  protocol: string;\n  downloadClient: string;\n  indexer: string;\n  id: number;\n}\n\nexport interface Tag {\n  id: number;\n  label: string;\n}\n\ninterface QueueResponse<QueueItemAppendT> {\n  page: number;\n  pageSize: number;\n  sortKey: string;\n  sortDirection: string;\n  totalRecords: number;\n  records: (QueueItem & QueueItemAppendT)[];\n}\n\nclass ServarrBase<QueueItemAppendT> extends ExternalAPI {\n  static buildUrl(settings: DVRSettings, path?: string): string {\n    return `${settings.useSsl ? 'https' : 'http'}://${settings.hostname}:${\n      settings.port\n    }${settings.baseUrl ?? ''}${path}`;\n  }\n\n  protected apiName: string;\n\n  constructor({\n    url,\n    apiKey,\n    cacheName,\n    apiName,\n  }: {\n    url: string;\n    apiKey: string;\n    cacheName: AvailableCacheIds;\n    apiName: string;\n  }) {\n    const timeout = getSettings().network.apiRequestTimeout;\n\n    super(\n      url,\n      {\n        apikey: apiKey,\n      },\n      {\n        nodeCache: cacheManager.getCache(cacheName).data,\n        timeout,\n      }\n    );\n\n    this.apiName = apiName;\n  }\n\n  public getSystemStatus = async (): Promise<SystemStatus> => {\n    try {\n      const response = await this.axios.get<SystemStatus>('/system/status');\n\n      return response.data;\n    } catch (e) {\n      throw new Error(\n        `[${this.apiName}] Failed to retrieve system status: ${e.message}`,\n        { cause: e }\n      );\n    }\n  };\n\n  public getProfiles = async (): Promise<QualityProfile[]> => {\n    try {\n      const data = await this.getRolling<QualityProfile[]>(\n        `/qualityProfile`,\n        undefined,\n        3600\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(\n        `[${this.apiName}] Failed to retrieve profiles: ${e.message}`,\n        { cause: e }\n      );\n    }\n  };\n\n  public getRootFolders = async (): Promise<RootFolder[]> => {\n    try {\n      const data = await this.getRolling<RootFolder[]>(\n        `/rootfolder`,\n        undefined,\n        3600\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(\n        `[${this.apiName}] Failed to retrieve root folders: ${e.message}`,\n        { cause: e }\n      );\n    }\n  };\n\n  public getQueue = async (): Promise<(QueueItem & QueueItemAppendT)[]> => {\n    try {\n      const response = await this.axios.get<QueueResponse<QueueItemAppendT>>(\n        `/queue`,\n        {\n          params: {\n            includeEpisode: true,\n          },\n        }\n      );\n\n      return response.data.records;\n    } catch (e) {\n      throw new Error(\n        `[${this.apiName}] Failed to retrieve queue: ${e.message}`,\n        { cause: e }\n      );\n    }\n  };\n\n  public getTags = async (): Promise<Tag[]> => {\n    try {\n      const response = await this.axios.get<Tag[]>(`/tag`);\n\n      return response.data;\n    } catch (e) {\n      throw new Error(\n        `[${this.apiName}] Failed to retrieve tags: ${e.message}`,\n        { cause: e }\n      );\n    }\n  };\n\n  public createTag = async ({ label }: { label: string }): Promise<Tag> => {\n    try {\n      const response = await this.axios.post<Tag>(`/tag`, {\n        label,\n      });\n\n      return response.data;\n    } catch (e) {\n      throw new Error(`[${this.apiName}] Failed to create tag: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public renameTag = async ({\n    id,\n    label,\n  }: {\n    id: number;\n    label: string;\n  }): Promise<Tag> => {\n    try {\n      const response = await this.axios.put<Tag>(`/tag/${id}`, {\n        id,\n        label,\n      });\n\n      return response.data;\n    } catch (e) {\n      throw new Error(`[${this.apiName}] Failed to rename tag: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  async refreshMonitoredDownloads(): Promise<void> {\n    await this.runCommand('RefreshMonitoredDownloads', {});\n  }\n\n  protected async runCommand(\n    commandName: string,\n    options: Record<string, unknown>\n  ): Promise<void> {\n    try {\n      await this.axios.post(`/command`, {\n        name: commandName,\n        ...options,\n      });\n    } catch (e) {\n      throw new Error(`[${this.apiName}] Failed to run command: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n}\n\nexport default ServarrBase;\n"
  },
  {
    "path": "server/api/servarr/radarr.ts",
    "content": "import logger from '@server/logger';\nimport ServarrBase from './base';\n\nexport interface RadarrMovieOptions {\n  title: string;\n  qualityProfileId: number;\n  minimumAvailability: string;\n  tags: number[];\n  profileId: number;\n  year: number;\n  rootFolderPath: string;\n  tmdbId: number;\n  monitored?: boolean;\n  searchNow?: boolean;\n}\n\nexport interface RadarrMovie {\n  id: number;\n  title: string;\n  isAvailable: boolean;\n  monitored: boolean;\n  tmdbId: number;\n  imdbId: string;\n  titleSlug: string;\n  folderName: string;\n  path: string;\n  profileId: number;\n  qualityProfileId: number;\n  added: string;\n  hasFile: boolean;\n  tags: number[];\n  movieFile?: {\n    id: number;\n    movieId: number;\n    relativePath?: string;\n    path?: string;\n    size: number;\n    dateAdded: string;\n    sceneName?: string;\n    releaseGroup?: string;\n    edition?: string;\n    indexerFlags?: number;\n    mediaInfo: {\n      id: number;\n      audioBitrate: number;\n      audioChannels: number;\n      audioCodec?: string;\n      audioLanguages?: string;\n      audioStreamCount: number;\n      videoBitDepth: number;\n      videoBitrate: number;\n      videoCodec?: string;\n      videoFps: number;\n      videoDynamicRange?: string;\n      videoDynamicRangeType?: string;\n      resolution?: string;\n      runTime?: string;\n      scanType?: string;\n      subtitles?: string;\n    };\n    originalFilePath?: string;\n    qualityCutoffNotMet: boolean;\n  };\n}\n\nclass RadarrAPI extends ServarrBase<{ movieId: number }> {\n  constructor({ url, apiKey }: { url: string; apiKey: string }) {\n    super({ url, apiKey, cacheName: 'radarr', apiName: 'Radarr' });\n  }\n\n  public getMovies = async (): Promise<RadarrMovie[]> => {\n    try {\n      const response = await this.axios.get<RadarrMovie[]>('/movie');\n\n      return response.data;\n    } catch (e) {\n      throw new Error(`[Radarr] Failed to retrieve movies: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public getMovie = async ({ id }: { id: number }): Promise<RadarrMovie> => {\n    try {\n      const response = await this.axios.get<RadarrMovie>(`/movie/${id}`);\n\n      return response.data;\n    } catch (e) {\n      throw new Error(`[Radarr] Failed to retrieve movie: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public async getMovieByTmdbId(id: number): Promise<RadarrMovie> {\n    try {\n      const response = await this.axios.get<RadarrMovie[]>('/movie/lookup', {\n        params: {\n          term: `tmdb:${id}`,\n        },\n      });\n\n      if (!response.data[0]) {\n        throw new Error('Movie not found');\n      }\n\n      return response.data[0];\n    } catch (e) {\n      logger.error('Error retrieving movie by TMDB ID', {\n        label: 'Radarr API',\n        errorMessage: e.message,\n        tmdbId: id,\n      });\n      throw new Error('Movie not found', { cause: e });\n    }\n  }\n\n  public addMovie = async (\n    options: RadarrMovieOptions\n  ): Promise<RadarrMovie> => {\n    try {\n      const movie = await this.getMovieByTmdbId(options.tmdbId);\n\n      if (movie.hasFile) {\n        logger.info(\n          'Title already exists and is available. Skipping add and returning success',\n          {\n            label: 'Radarr',\n            movie,\n          }\n        );\n        return movie;\n      }\n\n      // movie exists in Radarr but is neither downloaded nor monitored\n      if (movie.id && !movie.monitored) {\n        const response = await this.axios.put<RadarrMovie>(`/movie`, {\n          ...movie,\n          title: options.title,\n          qualityProfileId: options.qualityProfileId,\n          profileId: options.profileId,\n          titleSlug: options.tmdbId.toString(),\n          minimumAvailability: options.minimumAvailability,\n          tmdbId: options.tmdbId,\n          year: options.year,\n          tags: Array.from(new Set([...movie.tags, ...options.tags])),\n          rootFolderPath: options.rootFolderPath,\n          monitored: options.monitored,\n          addOptions: {\n            searchForMovie: options.searchNow,\n          },\n        });\n\n        if (response.data.monitored) {\n          logger.info(\n            'Found existing title in Radarr and set it to monitored.',\n            {\n              label: 'Radarr',\n              movieId: response.data.id,\n              movieTitle: response.data.title,\n            }\n          );\n          logger.debug('Radarr update details', {\n            label: 'Radarr',\n            movie: response.data,\n          });\n\n          if (options.searchNow) {\n            this.searchMovie(response.data.id);\n          }\n\n          return response.data;\n        } else {\n          logger.error('Failed to update existing movie in Radarr.', {\n            label: 'Radarr',\n            options,\n          });\n          throw new Error('Failed to update existing movie in Radarr');\n        }\n      }\n\n      if (movie.id) {\n        // Movie exists and is already monitored\n        logger.info('Movie is already monitored in Radarr.', {\n          label: 'Radarr',\n          movieId: movie.id,\n          movieTitle: movie.title,\n          hasFile: movie.hasFile,\n        });\n\n        // If searchNow is requested and movie doesn't have a file, trigger search\n        if (options.searchNow && !movie.hasFile) {\n          logger.info(\n            'Triggering search for existing monitored movie without file',\n            {\n              label: 'Radarr',\n              movieId: movie.id,\n              movieTitle: movie.title,\n            }\n          );\n          this.searchMovie(movie.id);\n        }\n\n        return movie;\n      }\n\n      const response = await this.axios.post<RadarrMovie>(`/movie`, {\n        title: options.title,\n        qualityProfileId: options.qualityProfileId,\n        profileId: options.profileId,\n        titleSlug: options.tmdbId.toString(),\n        minimumAvailability: options.minimumAvailability,\n        tmdbId: options.tmdbId,\n        year: options.year,\n        rootFolderPath: options.rootFolderPath,\n        monitored: options.monitored,\n        tags: options.tags,\n        addOptions: {\n          searchForMovie: options.searchNow,\n        },\n      });\n\n      if (response.data.id) {\n        logger.info('Radarr accepted request', { label: 'Radarr' });\n        logger.debug('Radarr add details', {\n          label: 'Radarr',\n          movie: response.data,\n        });\n      } else {\n        logger.error('Failed to add movie to Radarr', {\n          label: 'Radarr',\n          options,\n        });\n        throw new Error('Failed to add movie to Radarr');\n      }\n      return response.data;\n    } catch (e) {\n      logger.error(\n        'Failed to add movie to Radarr. This might happen if the movie already exists, in which case you can safely ignore this error.',\n        {\n          label: 'Radarr',\n          errorMessage: e.message,\n          options,\n          response: e?.response?.data,\n        }\n      );\n      throw new Error('Failed to add movie to Radarr', { cause: e });\n    }\n  };\n\n  public async searchMovie(movieId: number): Promise<void> {\n    logger.info('Executing movie search command', {\n      label: 'Radarr API',\n      movieId,\n    });\n\n    try {\n      await this.runCommand('MoviesSearch', { movieIds: [movieId] });\n    } catch (e) {\n      logger.error(\n        'Something went wrong while executing Radarr movie search.',\n        {\n          label: 'Radarr API',\n          errorMessage: e.message,\n          movieId,\n        }\n      );\n    }\n  }\n  public removeMovie = async (movieId: number): Promise<void> => {\n    try {\n      const { id, title } = await this.getMovieByTmdbId(movieId);\n      await this.axios.delete(`/movie/${id}`, {\n        params: {\n          deleteFiles: true,\n          addImportExclusion: false,\n        },\n      });\n      logger.info(`[Radarr] Removed movie ${title}`);\n    } catch (e) {\n      throw new Error(`[Radarr] Failed to remove movie: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public clearCache = ({\n    tmdbId,\n    externalId,\n  }: {\n    tmdbId?: number | null;\n    externalId?: number | null;\n  }) => {\n    if (tmdbId) {\n      this.removeCache('/movie/lookup', {\n        term: `tmdb:${tmdbId}`,\n      });\n    }\n    if (externalId) {\n      this.removeCache(`/movie/${externalId}`);\n    }\n  };\n}\n\nexport default RadarrAPI;\n"
  },
  {
    "path": "server/api/servarr/sonarr.ts",
    "content": "import logger from '@server/logger';\nimport ServarrBase from './base';\n\nexport interface SonarrSeason {\n  seasonNumber: number;\n  monitored: boolean;\n  statistics?: {\n    previousAiring?: string;\n    episodeFileCount: number;\n    episodeCount: number;\n    totalEpisodeCount: number;\n    sizeOnDisk: number;\n    percentOfEpisodes: number;\n  };\n}\ninterface EpisodeResult {\n  seriesId: number;\n  episodeFileId: number;\n  seasonNumber: number;\n  episodeNumber: number;\n  title: string;\n  airDate: string;\n  airDateUtc: string;\n  overview: string;\n  hasFile: boolean;\n  monitored: boolean;\n  absoluteEpisodeNumber: number;\n  unverifiedSceneNumbering: boolean;\n  id: number;\n}\n\nexport interface SonarrSeries {\n  title: string;\n  sortTitle: string;\n  seasonCount: number;\n  status: string;\n  overview: string;\n  network: string;\n  airTime: string;\n  images: {\n    coverType: string;\n    url: string;\n  }[];\n  remotePoster: string;\n  seasons: SonarrSeason[];\n  year: number;\n  path: string;\n  profileId: number;\n  languageProfileId: number;\n  seasonFolder: boolean;\n  monitored: boolean;\n  monitorNewItems: 'all' | 'none';\n  useSceneNumbering: boolean;\n  runtime: number;\n  tvdbId: number;\n  tvRageId: number;\n  tvMazeId: number;\n  firstAired: string;\n  lastInfoSync?: string;\n  seriesType: 'standard' | 'daily' | 'anime';\n  cleanTitle: string;\n  imdbId: string;\n  titleSlug: string;\n  certification: string;\n  genres: string[];\n  tags: number[];\n  added: string;\n  ratings: {\n    votes: number;\n    value: number;\n  };\n  qualityProfileId: number;\n  id?: number;\n  rootFolderPath?: string;\n  addOptions?: {\n    ignoreEpisodesWithFiles?: boolean;\n    ignoreEpisodesWithoutFiles?: boolean;\n    searchForMissingEpisodes?: boolean;\n  };\n  statistics: {\n    seasonCount: number;\n    episodeFileCount: number;\n    episodeCount: number;\n    totalEpisodeCount: number;\n    sizeOnDisk: number;\n    releaseGroups: string[];\n    percentOfEpisodes: number;\n  };\n}\n\nexport interface AddSeriesOptions {\n  tvdbid: number;\n  title: string;\n  profileId: number;\n  languageProfileId?: number;\n  seasons: number[];\n  seasonFolder: boolean;\n  rootFolderPath: string;\n  tags?: number[];\n  seriesType: SonarrSeries['seriesType'];\n  monitored?: boolean;\n  monitorNewItems?: SonarrSeries['monitorNewItems'];\n  searchNow?: boolean;\n}\n\nexport interface LanguageProfile {\n  id: number;\n  name: string;\n}\n\nclass SonarrAPI extends ServarrBase<{\n  seriesId: number;\n  episodeId: number;\n  episode: EpisodeResult;\n}> {\n  constructor({ url, apiKey }: { url: string; apiKey: string }) {\n    super({ url, apiKey, apiName: 'Sonarr', cacheName: 'sonarr' });\n  }\n\n  public async getSeries(): Promise<SonarrSeries[]> {\n    try {\n      const response = await this.axios.get<SonarrSeries[]>('/series');\n\n      return response.data;\n    } catch (e) {\n      throw new Error(`[Sonarr] Failed to retrieve series: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getSeriesById(id: number): Promise<SonarrSeries> {\n    try {\n      const response = await this.axios.get<SonarrSeries>(`/series/${id}`);\n\n      return response.data;\n    } catch (e) {\n      throw new Error(\n        `[Sonarr] Failed to retrieve series by ID: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getSeriesByTitle(title: string): Promise<SonarrSeries[]> {\n    try {\n      const response = await this.axios.get<SonarrSeries[]>('/series/lookup', {\n        params: {\n          term: title,\n        },\n      });\n\n      if (!response.data[0]) {\n        throw new Error('No series found');\n      }\n\n      return response.data;\n    } catch (e) {\n      logger.error('Error retrieving series by series title', {\n        label: 'Sonarr API',\n        errorMessage: e.message,\n        title,\n      });\n      throw new Error('No series found', { cause: e });\n    }\n  }\n\n  public async getSeriesByTvdbId(id: number): Promise<SonarrSeries> {\n    try {\n      const response = await this.axios.get<SonarrSeries[]>('/series/lookup', {\n        params: {\n          term: `tvdb:${id}`,\n        },\n      });\n\n      if (!response.data[0]) {\n        throw new Error('Series not found');\n      }\n\n      return response.data[0];\n    } catch (e) {\n      logger.error('Error retrieving series by tvdb ID', {\n        label: 'Sonarr API',\n        errorMessage: e.message,\n        tvdbId: id,\n      });\n      throw new Error('Series not found', { cause: e });\n    }\n  }\n\n  public async addSeries(options: AddSeriesOptions): Promise<SonarrSeries> {\n    try {\n      const series = await this.getSeriesByTvdbId(options.tvdbid);\n\n      // If the series already exists, we will simply just update it\n      if (series.id) {\n        series.monitored = options.monitored ?? series.monitored;\n        series.tags = options.tags\n          ? Array.from(new Set([...series.tags, ...options.tags]))\n          : series.tags;\n        series.seasons = this.buildSeasonList(options.seasons, series.seasons);\n\n        const newSeriesResponse = await this.axios.put<SonarrSeries>(\n          '/series',\n          series\n        );\n\n        if (newSeriesResponse.data.id) {\n          logger.info('Updated existing series in Sonarr.', {\n            label: 'Sonarr',\n            seriesId: newSeriesResponse.data.id,\n            seriesTitle: newSeriesResponse.data.title,\n          });\n          logger.debug('Sonarr update details', {\n            label: 'Sonarr',\n            series: newSeriesResponse.data,\n          });\n\n          try {\n            const episodes = await this.getEpisodes(newSeriesResponse.data.id);\n            const episodeIdsToMonitor = episodes\n              .filter(\n                (ep) =>\n                  options.seasons.includes(ep.seasonNumber) && !ep.monitored\n              )\n              .map((ep) => ep.id);\n\n            if (episodeIdsToMonitor.length > 0) {\n              logger.debug(\n                'Re-monitoring unmonitored episodes for requested seasons.',\n                {\n                  label: 'Sonarr',\n                  seriesId: newSeriesResponse.data.id,\n                  episodeCount: episodeIdsToMonitor.length,\n                }\n              );\n              await this.monitorEpisodes(episodeIdsToMonitor);\n            }\n          } catch (e) {\n            logger.warn('Failed to re-monitor episodes', {\n              label: 'Sonarr',\n              errorMessage: e.message,\n              seriesId: newSeriesResponse.data.id,\n            });\n          }\n\n          if (options.searchNow) {\n            this.searchSeries(newSeriesResponse.data.id);\n          }\n\n          return newSeriesResponse.data;\n        } else {\n          logger.error('Failed to update series in Sonarr', {\n            label: 'Sonarr',\n            options,\n          });\n          throw new Error('Failed to update series in Sonarr');\n        }\n      }\n\n      const createdSeriesResponse = await this.axios.post<SonarrSeries>(\n        '/series',\n        {\n          tvdbId: options.tvdbid,\n          title: options.title,\n          qualityProfileId: options.profileId,\n          languageProfileId: options.languageProfileId,\n          seasons: this.buildSeasonList(\n            options.seasons,\n            series.seasons.map((season) => ({\n              seasonNumber: season.seasonNumber,\n              // We force all seasons to false if its the first request\n              monitored: false,\n            }))\n          ),\n          tags: options.tags,\n          seasonFolder: options.seasonFolder,\n          monitored: options.monitored,\n          monitorNewItems: options.monitorNewItems,\n          rootFolderPath: options.rootFolderPath,\n          seriesType: options.seriesType,\n          addOptions: {\n            ignoreEpisodesWithFiles: true,\n            searchForMissingEpisodes: options.searchNow,\n          },\n        } as Partial<SonarrSeries>\n      );\n\n      if (createdSeriesResponse.data.id) {\n        logger.info('Sonarr accepted request', { label: 'Sonarr' });\n        logger.debug('Sonarr add details', {\n          label: 'Sonarr',\n          series: createdSeriesResponse.data,\n        });\n      } else {\n        logger.error('Failed to add series to Sonarr', {\n          label: 'Sonarr',\n          options,\n        });\n        throw new Error('Failed to add series to Sonarr');\n      }\n\n      return createdSeriesResponse.data;\n    } catch (e) {\n      logger.error('Something went wrong while adding a series to Sonarr.', {\n        label: 'Sonarr API',\n        errorMessage: e.message,\n        options,\n        response: e?.response?.data,\n      });\n      throw new Error('Failed to add series', { cause: e });\n    }\n  }\n\n  public async getLanguageProfiles(): Promise<LanguageProfile[]> {\n    try {\n      const data = await this.getRolling<LanguageProfile[]>(\n        '/languageprofile',\n        undefined,\n        3600\n      );\n\n      return data;\n    } catch (e) {\n      logger.error(\n        'Something went wrong while retrieving Sonarr language profiles.',\n        {\n          label: 'Sonarr API',\n          errorMessage: e.message,\n        }\n      );\n\n      throw new Error('Failed to get language profiles', { cause: e });\n    }\n  }\n\n  public async searchSeries(seriesId: number): Promise<void> {\n    logger.info('Executing series search command.', {\n      label: 'Sonarr API',\n      seriesId,\n    });\n\n    try {\n      await this.runCommand('MissingEpisodeSearch', { seriesId });\n    } catch (e) {\n      logger.error(\n        'Something went wrong while executing Sonarr missing episode search.',\n        {\n          label: 'Sonarr API',\n          errorMessage: e.message,\n          seriesId,\n        }\n      );\n    }\n  }\n\n  public async getEpisodes(seriesId: number): Promise<EpisodeResult[]> {\n    try {\n      const response = await this.axios.get<EpisodeResult[]>('/episode', {\n        params: { seriesId },\n      });\n      return response.data;\n    } catch (e) {\n      logger.error('Failed to retrieve episodes', {\n        label: 'Sonarr API',\n        errorMessage: e.message,\n        seriesId,\n      });\n      throw new Error('Failed to get episodes', { cause: e });\n    }\n  }\n\n  public async monitorEpisodes(episodeIds: number[]): Promise<void> {\n    try {\n      await this.axios.put('/episode/monitor', {\n        episodeIds,\n        monitored: true,\n      });\n    } catch (e) {\n      logger.error('Failed to monitor episodes', {\n        label: 'Sonarr API',\n        errorMessage: e.message,\n        episodeIds,\n      });\n      throw new Error('Failed to monitor episodes', { cause: e });\n    }\n  }\n\n  private buildSeasonList(\n    seasons: number[],\n    existingSeasons?: SonarrSeason[]\n  ): SonarrSeason[] {\n    if (existingSeasons) {\n      const newSeasons = existingSeasons.map((season) => {\n        if (seasons.includes(season.seasonNumber)) {\n          season.monitored = true;\n        }\n        return season;\n      });\n\n      return newSeasons;\n    }\n\n    const newSeasons = seasons.map(\n      (seasonNumber): SonarrSeason => ({\n        seasonNumber,\n        monitored: true,\n      })\n    );\n\n    return newSeasons;\n  }\n  public removeSeries = async (serieId: number): Promise<void> => {\n    try {\n      const { id, title } = await this.getSeriesByTvdbId(serieId);\n      await this.axios.delete(`/series/${id}`, {\n        params: {\n          deleteFiles: true,\n          addImportExclusion: false,\n        },\n      });\n      logger.info(`[Sonarr] Removed series ${title}`);\n    } catch (e) {\n      throw new Error(`[Sonarr] Failed to remove series: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public clearCache = ({\n    tvdbId,\n    externalId,\n    title,\n  }: {\n    tvdbId?: number | null;\n    externalId?: number | null;\n    title?: string | null;\n  }) => {\n    if (tvdbId) {\n      this.removeCache('/series/lookup', {\n        term: `tvdb:${tvdbId}`,\n      });\n    }\n    if (externalId) {\n      this.removeCache(`/series/${externalId}`);\n    }\n    if (title) {\n      this.removeCache('/series/lookup', {\n        term: title,\n      });\n    }\n  };\n}\n\nexport default SonarrAPI;\n"
  },
  {
    "path": "server/api/tautulli.ts",
    "content": "import type { User } from '@server/entity/User';\nimport type { TautulliSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { requestInterceptorFunction } from '@server/utils/customProxyAgent';\nimport type { AxiosInstance } from 'axios';\nimport axios from 'axios';\nimport { uniqWith } from 'lodash';\n\nexport interface TautulliHistoryRecord {\n  date: number;\n  duration: number;\n  friendly_name: string;\n  full_title: string;\n  grandparent_rating_key: number;\n  grandparent_title: string;\n  original_title: string;\n  group_count: number;\n  group_ids?: string;\n  guid: string;\n  ip_address: string;\n  live: number;\n  machine_id: string;\n  media_index: number;\n  media_type: string;\n  originally_available_at: string;\n  parent_media_index: number;\n  parent_rating_key: number;\n  parent_title: string;\n  paused_counter: number;\n  percent_complete: number;\n  platform: string;\n  product: string;\n  player: string;\n  rating_key: number;\n  reference_id?: number;\n  row_id?: number;\n  session_key?: string;\n  started: number;\n  state?: string;\n  stopped: number;\n  thumb: string;\n  title: string;\n  transcode_decision: string;\n  user: string;\n  user_id: number;\n  watched_status: number;\n  year: number;\n}\n\ninterface TautulliHistoryResponse {\n  response: {\n    result: string;\n    message?: string;\n    data: {\n      draw: number;\n      recordsTotal: number;\n      recordsFiltered: number;\n      total_duration: string;\n      filter_duration: string;\n      data: TautulliHistoryRecord[];\n    };\n  };\n}\n\ninterface TautulliWatchStats {\n  query_days: number;\n  total_time: number;\n  total_plays: number;\n}\n\ninterface TautulliWatchStatsResponse {\n  response: {\n    result: string;\n    message?: string;\n    data: TautulliWatchStats[];\n  };\n}\n\ninterface TautulliWatchUser {\n  friendly_name: string;\n  user_id: number;\n  user_thumb: string;\n  username: string;\n  total_plays: number;\n  total_time: number;\n}\n\ninterface TautulliWatchUsersResponse {\n  response: {\n    result: string;\n    message?: string;\n    data: TautulliWatchUser[];\n  };\n}\n\ninterface TautulliInfo {\n  tautulli_install_type: string;\n  tautulli_version: string;\n  tautulli_branch: string;\n  tautulli_commit: string;\n  tautulli_platform: string;\n  tautulli_platform_release: string;\n  tautulli_platform_version: string;\n  tautulli_platform_linux_distro: string;\n  tautulli_platform_device_name: string;\n  tautulli_python_version: string;\n}\n\ninterface TautulliInfoResponse {\n  response: {\n    result: string;\n    message?: string;\n    data: TautulliInfo;\n  };\n}\n\nclass TautulliAPI {\n  private axios: AxiosInstance;\n\n  constructor(settings: TautulliSettings) {\n    this.axios = axios.create({\n      baseURL: `${settings.useSsl ? 'https' : 'http'}://${settings.hostname}:${\n        settings.port\n      }${settings.urlBase ?? ''}`,\n      params: { apikey: settings.apiKey },\n    });\n    this.axios.interceptors.request.use(requestInterceptorFunction);\n  }\n\n  public async getInfo(): Promise<TautulliInfo> {\n    try {\n      return (\n        await this.axios.get<TautulliInfoResponse>('/api/v2', {\n          params: { cmd: 'get_tautulli_info' },\n        })\n      ).data.response.data;\n    } catch (e) {\n      logger.error('Something went wrong fetching Tautulli server info', {\n        label: 'Tautulli API',\n        errorMessage: e.message,\n      });\n      throw new Error(\n        `[Tautulli] Failed to fetch Tautulli server info: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getMediaWatchStats(\n    ratingKey: string\n  ): Promise<TautulliWatchStats[]> {\n    try {\n      return (\n        await this.axios.get<TautulliWatchStatsResponse>('/api/v2', {\n          params: {\n            cmd: 'get_item_watch_time_stats',\n            rating_key: ratingKey,\n            grouping: 1,\n          },\n        })\n      ).data.response.data;\n    } catch (e) {\n      logger.error(\n        'Something went wrong fetching media watch stats from Tautulli',\n        {\n          label: 'Tautulli API',\n          errorMessage: e.message,\n          ratingKey,\n        }\n      );\n      throw new Error(\n        `[Tautulli] Failed to fetch media watch stats: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getMediaWatchUsers(\n    ratingKey: string\n  ): Promise<TautulliWatchUser[]> {\n    try {\n      return (\n        await this.axios.get<TautulliWatchUsersResponse>('/api/v2', {\n          params: {\n            cmd: 'get_item_user_stats',\n            rating_key: ratingKey,\n            grouping: 1,\n          },\n        })\n      ).data.response.data;\n    } catch (e) {\n      logger.error(\n        'Something went wrong fetching media watch users from Tautulli',\n        {\n          label: 'Tautulli API',\n          errorMessage: e.message,\n          ratingKey,\n        }\n      );\n      throw new Error(\n        `[Tautulli] Failed to fetch media watch users: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getUserWatchStats(user: User): Promise<TautulliWatchStats> {\n    try {\n      if (!user.plexId) {\n        throw new Error('User does not have an associated Plex ID');\n      }\n\n      return (\n        await this.axios.get<TautulliWatchStatsResponse>('/api/v2', {\n          params: {\n            cmd: 'get_user_watch_time_stats',\n            user_id: user.plexId,\n            query_days: 0,\n            grouping: 1,\n          },\n        })\n      ).data.response.data[0];\n    } catch (e) {\n      logger.error(\n        'Something went wrong fetching user watch stats from Tautulli',\n        {\n          label: 'Tautulli API',\n          errorMessage: e.message,\n          user: user.displayName,\n        }\n      );\n      throw new Error(\n        `[Tautulli] Failed to fetch user watch stats: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getUserWatchHistory(\n    user: User\n  ): Promise<TautulliHistoryRecord[]> {\n    let results: TautulliHistoryRecord[] = [];\n\n    try {\n      if (!user.plexId) {\n        throw new Error('User does not have an associated Plex ID');\n      }\n\n      const take = 100;\n      let start = 0;\n\n      while (results.length < 20) {\n        const tautulliData = (\n          await this.axios.get<TautulliHistoryResponse>('/api/v2', {\n            params: {\n              cmd: 'get_history',\n              grouping: 1,\n              order_column: 'date',\n              order_dir: 'desc',\n              user_id: user.plexId,\n              media_type: 'movie,episode',\n              length: take,\n              start,\n            },\n          })\n        ).data.response.data.data;\n\n        if (!tautulliData.length) {\n          return results;\n        }\n\n        results = uniqWith(results.concat(tautulliData), (recordA, recordB) =>\n          recordA.grandparent_rating_key && recordB.grandparent_rating_key\n            ? recordA.grandparent_rating_key === recordB.grandparent_rating_key\n            : recordA.parent_rating_key && recordB.parent_rating_key\n              ? recordA.parent_rating_key === recordB.parent_rating_key\n              : recordA.rating_key === recordB.rating_key\n        );\n\n        start += take;\n      }\n\n      return results.slice(0, 20);\n    } catch (e) {\n      logger.error(\n        'Something went wrong fetching user watch history from Tautulli',\n        {\n          label: 'Tautulli API',\n          errorMessage: e.message,\n          user: user.displayName,\n        }\n      );\n      throw new Error(\n        `[Tautulli] Failed to fetch user watch history: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n}\n\nexport default TautulliAPI;\n"
  },
  {
    "path": "server/api/themoviedb/constants.ts",
    "content": "export const ANIME_KEYWORD_ID = 210024;\n"
  },
  {
    "path": "server/api/themoviedb/index.ts",
    "content": "import ExternalAPI from '@server/api/externalapi';\nimport type { TvShowProvider } from '@server/api/provider';\nimport cacheManager from '@server/lib/cache';\nimport { getSettings } from '@server/lib/settings';\nimport { sortBy } from 'lodash';\nimport type {\n  TmdbCollection,\n  TmdbCompanySearchResponse,\n  TmdbExternalIdResponse,\n  TmdbGenre,\n  TmdbGenresResult,\n  TmdbKeyword,\n  TmdbKeywordSearchResponse,\n  TmdbLanguage,\n  TmdbMovieDetails,\n  TmdbNetwork,\n  TmdbPersonCombinedCredits,\n  TmdbPersonDetails,\n  TmdbProductionCompany,\n  TmdbRegion,\n  TmdbSearchMovieResponse,\n  TmdbSearchMultiResponse,\n  TmdbSearchTvResponse,\n  TmdbSeasonWithEpisodes,\n  TmdbTvDetails,\n  TmdbUpcomingMoviesResponse,\n  TmdbWatchProviderDetails,\n  TmdbWatchProviderRegion,\n} from './interfaces';\n\ninterface SearchOptions {\n  query: string;\n  page?: number;\n  includeAdult?: boolean;\n  language?: string;\n}\n\ninterface SingleSearchOptions extends SearchOptions {\n  year?: number;\n}\n\nexport const SortOptionsIterable = [\n  'popularity.desc',\n  'popularity.asc',\n  'release_date.desc',\n  'release_date.asc',\n  'revenue.desc',\n  'revenue.asc',\n  'primary_release_date.desc',\n  'primary_release_date.asc',\n  'original_title.asc',\n  'original_title.desc',\n  'vote_average.desc',\n  'vote_average.asc',\n  'vote_count.desc',\n  'vote_count.asc',\n  'first_air_date.desc',\n  'first_air_date.asc',\n] as const;\n\nexport type SortOptions = (typeof SortOptionsIterable)[number];\n\nexport interface TmdbCertificationResponse {\n  certifications: {\n    [country: string]: {\n      certification: string;\n      meaning?: string;\n      order?: number;\n    }[];\n  };\n}\n\ninterface DiscoverMovieOptions {\n  page?: number;\n  includeAdult?: boolean;\n  includeVideo?: boolean;\n  language?: string;\n  primaryReleaseDateGte?: string;\n  primaryReleaseDateLte?: string;\n  withRuntimeGte?: string;\n  withRuntimeLte?: string;\n  voteAverageGte?: string;\n  voteAverageLte?: string;\n  voteCountGte?: string;\n  voteCountLte?: string;\n  originalLanguage?: string;\n  genre?: string;\n  studio?: string;\n  keywords?: string;\n  excludeKeywords?: string;\n  sortBy?: SortOptions;\n  watchRegion?: string;\n  watchProviders?: string;\n  certification?: string;\n  certificationGte?: string;\n  certificationLte?: string;\n  certificationCountry?: string;\n}\n\ninterface DiscoverTvOptions {\n  page?: number;\n  language?: string;\n  firstAirDateGte?: string;\n  firstAirDateLte?: string;\n  withRuntimeGte?: string;\n  withRuntimeLte?: string;\n  voteAverageGte?: string;\n  voteAverageLte?: string;\n  voteCountGte?: string;\n  voteCountLte?: string;\n  includeEmptyReleaseDate?: boolean;\n  originalLanguage?: string;\n  genre?: string;\n  network?: number;\n  keywords?: string;\n  excludeKeywords?: string;\n  sortBy?: SortOptions;\n  watchRegion?: string;\n  watchProviders?: string;\n  withStatus?: string; // Returning Series: 0 Planned: 1 In Production: 2 Ended: 3 Cancelled: 4 Pilot: 5\n  certification?: string;\n  certificationGte?: string;\n  certificationLte?: string;\n  certificationCountry?: string;\n}\n\nclass TheMovieDb extends ExternalAPI implements TvShowProvider {\n  private locale: string;\n  private discoverRegion?: string;\n  private originalLanguage?: string;\n  constructor({\n    discoverRegion,\n    originalLanguage,\n  }: { discoverRegion?: string; originalLanguage?: string } = {}) {\n    super(\n      'https://api.themoviedb.org/3',\n      {\n        api_key: '431a8708161bcd1f1fbe7536137e61ed',\n      },\n      {\n        nodeCache: cacheManager.getCache('tmdb').data,\n        rateLimit: {\n          maxRequests: 20,\n          maxRPS: 50,\n        },\n      }\n    );\n    this.locale = getSettings().main?.locale || 'en';\n    this.discoverRegion = discoverRegion;\n    this.originalLanguage = originalLanguage;\n  }\n\n  public searchMulti = async ({\n    query,\n    page = 1,\n    includeAdult = false,\n    language = this.locale,\n  }: SearchOptions): Promise<TmdbSearchMultiResponse> => {\n    try {\n      const data = await this.get<TmdbSearchMultiResponse>('/search/multi', {\n        params: { query, page, include_adult: includeAdult, language },\n      });\n\n      return data;\n    } catch {\n      return {\n        page: 1,\n        results: [],\n        total_pages: 1,\n        total_results: 0,\n      };\n    }\n  };\n\n  public searchMovies = async ({\n    query,\n    page = 1,\n    includeAdult = false,\n    language = this.locale,\n    year,\n  }: SingleSearchOptions): Promise<TmdbSearchMovieResponse> => {\n    try {\n      const data = await this.get<TmdbSearchMovieResponse>('/search/movie', {\n        params: {\n          query,\n          page,\n          include_adult: includeAdult,\n          language,\n          primary_release_year: year,\n        },\n      });\n\n      return data;\n    } catch {\n      return {\n        page: 1,\n        results: [],\n        total_pages: 1,\n        total_results: 0,\n      };\n    }\n  };\n\n  public searchTvShows = async ({\n    query,\n    page = 1,\n    includeAdult = false,\n    language = this.locale,\n    year,\n  }: SingleSearchOptions): Promise<TmdbSearchTvResponse> => {\n    try {\n      const data = await this.get<TmdbSearchTvResponse>('/search/tv', {\n        params: {\n          query,\n          page,\n          include_adult: includeAdult,\n          language,\n          first_air_date_year: year,\n        },\n      });\n\n      return data;\n    } catch {\n      return {\n        page: 1,\n        results: [],\n        total_pages: 1,\n        total_results: 0,\n      };\n    }\n  };\n\n  public getPerson = async ({\n    personId,\n    language = this.locale,\n  }: {\n    personId: number;\n    language?: string;\n  }): Promise<TmdbPersonDetails> => {\n    try {\n      const data = await this.get<TmdbPersonDetails>(`/person/${personId}`, {\n        params: { language },\n      });\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch person details: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public getPersonCombinedCredits = async ({\n    personId,\n    language = this.locale,\n  }: {\n    personId: number;\n    language?: string;\n  }): Promise<TmdbPersonCombinedCredits> => {\n    try {\n      const data = await this.get<TmdbPersonCombinedCredits>(\n        `/person/${personId}/combined_credits`,\n        {\n          params: { language },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(\n        `[TMDB] Failed to fetch person combined credits: ${e.message}`,\n        { cause: e }\n      );\n    }\n  };\n\n  public getMovie = async ({\n    movieId,\n    language = this.locale,\n  }: {\n    movieId: number;\n    language?: string;\n  }): Promise<TmdbMovieDetails> => {\n    try {\n      const data = await this.get<TmdbMovieDetails>(\n        `/movie/${movieId}`,\n        {\n          params: {\n            language,\n            append_to_response:\n              'credits,external_ids,videos,keywords,release_dates,watch/providers',\n            include_video_language: language,\n          },\n        },\n        43200\n      );\n\n      if (\n        (!language || !language.startsWith('en')) &&\n        !data.videos?.results?.some((video) => video.type === 'Trailer')\n      ) {\n        try {\n          const fallback = await this.get<TmdbMovieDetails>(\n            `/movie/${movieId}`,\n            {\n              params: {\n                language,\n                append_to_response: 'videos',\n                include_video_language: 'en',\n              },\n            },\n            43200\n          );\n\n          const localizedVideos = data.videos?.results ?? [];\n          const localizedVideoKeys = new Set(\n            localizedVideos.map((video) => video.key)\n          );\n          const englishFallbackTrailers =\n            fallback.videos?.results?.filter(\n              (video) =>\n                video.type === 'Trailer' && !localizedVideoKeys.has(video.key)\n            ) ?? [];\n\n          if (englishFallbackTrailers.length > 0) {\n            data.videos = {\n              ...(data.videos ?? { results: [] }),\n              results: [...localizedVideos, ...englishFallbackTrailers],\n            };\n          }\n        } catch {\n          // Ignore trailer fallback failures; return the original data.\n        }\n      }\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch movie details: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public getTvShow = async ({\n    tvId,\n    language = this.locale,\n  }: {\n    tvId: number;\n    language?: string;\n  }): Promise<TmdbTvDetails> => {\n    try {\n      const data = await this.get<TmdbTvDetails>(\n        `/tv/${tvId}`,\n        {\n          params: {\n            language,\n            append_to_response:\n              'aggregate_credits,credits,external_ids,keywords,videos,content_ratings,watch/providers',\n            include_video_language: language,\n          },\n        },\n        43200\n      );\n\n      if (\n        (!language || !language.startsWith('en')) &&\n        !data.videos?.results?.some((video) => video.type === 'Trailer')\n      ) {\n        try {\n          const fallback = await this.get<TmdbTvDetails>(\n            `/tv/${tvId}`,\n            {\n              params: {\n                language,\n                append_to_response: 'videos',\n                include_video_language: 'en',\n              },\n            },\n            43200\n          );\n\n          const localizedVideos = data.videos?.results ?? [];\n          const localizedVideoKeys = new Set(\n            localizedVideos.map((video) => video.key)\n          );\n          const englishFallbackTrailers =\n            fallback.videos?.results?.filter(\n              (video) =>\n                video.type === 'Trailer' && !localizedVideoKeys.has(video.key)\n            ) ?? [];\n\n          if (englishFallbackTrailers.length > 0) {\n            data.videos = {\n              ...(data.videos ?? { results: [] }),\n              results: [...localizedVideos, ...englishFallbackTrailers],\n            };\n          }\n        } catch {\n          // Ignore trailer fallback failures; return the original data.\n        }\n      }\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch TV show details: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public getTvSeason = async ({\n    tvId,\n    seasonNumber,\n    language,\n  }: {\n    tvId: number;\n    seasonNumber: number;\n    language?: string;\n  }): Promise<TmdbSeasonWithEpisodes> => {\n    try {\n      const data = await this.get<TmdbSeasonWithEpisodes>(\n        `/tv/${tvId}/season/${seasonNumber}`,\n        {\n          params: {\n            language,\n            append_to_response: 'external_ids',\n          },\n        }\n      );\n\n      data.episodes = data.episodes.map((episode) => {\n        if (episode.still_path) {\n          episode.still_path = `https://image.tmdb.org/t/p/original/${episode.still_path}`;\n        }\n        return episode;\n      });\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch TV show details: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public async getMovieRecommendations({\n    movieId,\n    page = 1,\n    language = this.locale,\n  }: {\n    movieId: number;\n    page?: number;\n    language?: string;\n  }): Promise<TmdbSearchMovieResponse> {\n    try {\n      const data = await this.get<TmdbSearchMovieResponse>(\n        `/movie/${movieId}/recommendations`,\n        {\n          params: {\n            page,\n            language,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch discover movies: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getMovieSimilar({\n    movieId,\n    page = 1,\n    language = this.locale,\n  }: {\n    movieId: number;\n    page?: number;\n    language?: string;\n  }): Promise<TmdbSearchMovieResponse> {\n    try {\n      const data = await this.get<TmdbSearchMovieResponse>(\n        `/movie/${movieId}/similar`,\n        {\n          params: {\n            page,\n            language,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch discover movies: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getMoviesByKeyword({\n    keywordId,\n    page = 1,\n    language = this.locale,\n  }: {\n    keywordId: number;\n    page?: number;\n    language?: string;\n  }): Promise<TmdbSearchMovieResponse> {\n    try {\n      const data = await this.get<TmdbSearchMovieResponse>(\n        `/keyword/${keywordId}/movies`,\n        {\n          params: {\n            page,\n            language,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(\n        `[TMDB] Failed to fetch movies by keyword: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getTvRecommendations({\n    tvId,\n    page = 1,\n    language = this.locale,\n  }: {\n    tvId: number;\n    page?: number;\n    language?: string;\n  }): Promise<TmdbSearchTvResponse> {\n    try {\n      const data = await this.get<TmdbSearchTvResponse>(\n        `/tv/${tvId}/recommendations`,\n        {\n          params: {\n            page,\n            language,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(\n        `[TMDB] Failed to fetch TV recommendations: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getTvSimilar({\n    tvId,\n    page = 1,\n    language = this.locale,\n  }: {\n    tvId: number;\n    page?: number;\n    language?: string;\n  }): Promise<TmdbSearchTvResponse> {\n    try {\n      const data = await this.get<TmdbSearchTvResponse>(`/tv/${tvId}/similar`, {\n        params: {\n          page,\n          language,\n        },\n      });\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch TV similar: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public getDiscoverMovies = async ({\n    sortBy = 'popularity.desc',\n    page = 1,\n    includeAdult = false,\n    includeVideo = true,\n    language = this.locale,\n    primaryReleaseDateGte,\n    primaryReleaseDateLte,\n    originalLanguage,\n    genre,\n    studio,\n    keywords,\n    excludeKeywords,\n    withRuntimeGte,\n    withRuntimeLte,\n    voteAverageGte,\n    voteAverageLte,\n    voteCountGte,\n    voteCountLte,\n    watchProviders,\n    watchRegion,\n    certification,\n    certificationGte,\n    certificationLte,\n    certificationCountry,\n  }: DiscoverMovieOptions = {}): Promise<TmdbSearchMovieResponse> => {\n    try {\n      const defaultFutureDate = new Date(\n        Date.now() + 1000 * 60 * 60 * 24 * (365 * 1.5)\n      )\n        .toISOString()\n        .split('T')[0];\n\n      const defaultPastDate = new Date('1900-01-01')\n        .toISOString()\n        .split('T')[0];\n\n      const data = await this.get<TmdbSearchMovieResponse>('/discover/movie', {\n        params: {\n          sort_by: sortBy,\n          page,\n          include_adult: includeAdult,\n          include_video: includeVideo,\n          language,\n          region: this.discoverRegion || '',\n          with_original_language:\n            originalLanguage && originalLanguage !== 'all'\n              ? originalLanguage\n              : originalLanguage === 'all'\n                ? undefined\n                : this.originalLanguage,\n          // Set our release date values, but check if one is set and not the other,\n          // so we can force a past date or a future date. TMDB Requires both values if one is set!\n          'primary_release_date.gte':\n            !primaryReleaseDateGte && primaryReleaseDateLte\n              ? defaultPastDate\n              : primaryReleaseDateGte,\n          'primary_release_date.lte':\n            !primaryReleaseDateLte && primaryReleaseDateGte\n              ? defaultFutureDate\n              : primaryReleaseDateLte,\n          with_genres: genre,\n          with_companies: studio,\n          with_keywords: keywords,\n          without_keywords: excludeKeywords,\n          'with_runtime.gte': withRuntimeGte,\n          'with_runtime.lte': withRuntimeLte,\n          'vote_average.gte': voteAverageGte,\n          'vote_average.lte': voteAverageLte,\n          'vote_count.gte': voteCountGte,\n          'vote_count.lte': voteCountLte,\n          watch_region: watchRegion,\n          with_watch_providers: watchProviders,\n          certification: certification,\n          'certification.gte': certificationGte,\n          'certification.lte': certificationLte,\n          certification_country: certificationCountry,\n        },\n      });\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch discover movies: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public getDiscoverTv = async ({\n    sortBy = 'popularity.desc',\n    page = 1,\n    language = this.locale,\n    firstAirDateGte,\n    firstAirDateLte,\n    includeEmptyReleaseDate = false,\n    originalLanguage,\n    genre,\n    network,\n    keywords,\n    excludeKeywords,\n    withRuntimeGte,\n    withRuntimeLte,\n    voteAverageGte,\n    voteAverageLte,\n    voteCountGte,\n    voteCountLte,\n    watchProviders,\n    watchRegion,\n    withStatus,\n    certification,\n    certificationGte,\n    certificationLte,\n    certificationCountry,\n  }: DiscoverTvOptions = {}): Promise<TmdbSearchTvResponse> => {\n    try {\n      const defaultFutureDate = new Date(\n        Date.now() + 1000 * 60 * 60 * 24 * (365 * 1.5)\n      )\n        .toISOString()\n        .split('T')[0];\n\n      const defaultPastDate = new Date('1900-01-01')\n        .toISOString()\n        .split('T')[0];\n\n      const data = await this.get<TmdbSearchTvResponse>('/discover/tv', {\n        params: {\n          sort_by: sortBy,\n          page,\n          language,\n          region: this.discoverRegion || '',\n          // Set our release date values, but check if one is set and not the other,\n          // so we can force a past date or a future date. TMDB Requires both values if one is set!\n          'first_air_date.gte':\n            !firstAirDateGte && firstAirDateLte\n              ? defaultPastDate\n              : firstAirDateGte,\n          'first_air_date.lte':\n            !firstAirDateLte && firstAirDateGte\n              ? defaultFutureDate\n              : firstAirDateLte,\n          with_original_language:\n            originalLanguage && originalLanguage !== 'all'\n              ? originalLanguage\n              : originalLanguage === 'all'\n                ? undefined\n                : this.originalLanguage,\n          include_null_first_air_dates: includeEmptyReleaseDate,\n          with_genres: genre,\n          with_networks: network,\n          with_keywords: keywords,\n          without_keywords: excludeKeywords,\n          'with_runtime.gte': withRuntimeGte,\n          'with_runtime.lte': withRuntimeLte,\n          'vote_average.gte': voteAverageGte,\n          'vote_average.lte': voteAverageLte,\n          'vote_count.gte': voteCountGte,\n          'vote_count.lte': voteCountLte,\n          with_watch_providers: watchProviders,\n          watch_region: watchRegion,\n          with_status: withStatus,\n          certification: certification,\n          'certification.gte': certificationGte,\n          'certification.lte': certificationLte,\n          certification_country: certificationCountry,\n        },\n      });\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch discover TV: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public getUpcomingMovies = async ({\n    page = 1,\n    language = this.locale,\n  }: {\n    page: number;\n    language: string;\n  }): Promise<TmdbUpcomingMoviesResponse> => {\n    try {\n      const data = await this.get<TmdbUpcomingMoviesResponse>(\n        '/movie/upcoming',\n        {\n          params: {\n            page,\n            language,\n            region: this.discoverRegion,\n            originalLanguage: this.originalLanguage,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch upcoming movies: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public getAllTrending = async ({\n    page = 1,\n    timeWindow = 'day',\n    language = this.locale,\n  }: {\n    page?: number;\n    timeWindow?: 'day' | 'week';\n    language?: string;\n  } = {}): Promise<TmdbSearchMultiResponse> => {\n    try {\n      const data = await this.get<TmdbSearchMultiResponse>(\n        `/trending/all/${timeWindow}`,\n        {\n          params: {\n            page,\n            language,\n            region: this.discoverRegion,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch all trending: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public getMovieTrending = async ({\n    page = 1,\n    timeWindow = 'day',\n    language = this.locale,\n  }: {\n    page?: number;\n    timeWindow?: 'day' | 'week';\n    language?: string;\n  } = {}): Promise<TmdbSearchMovieResponse> => {\n    try {\n      const data = await this.get<TmdbSearchMovieResponse>(\n        `/trending/movie/${timeWindow}`,\n        {\n          params: {\n            page,\n            language,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch all trending: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public getTvTrending = async ({\n    page = 1,\n    timeWindow = 'day',\n    language = this.locale,\n  }: {\n    page?: number;\n    timeWindow?: 'day' | 'week';\n    language?: string;\n  } = {}): Promise<TmdbSearchTvResponse> => {\n    try {\n      const data = await this.get<TmdbSearchTvResponse>(\n        `/trending/tv/${timeWindow}`,\n        {\n          params: {\n            page,\n            language,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch all trending: ${e.message}`, {\n        cause: e,\n      });\n    }\n  };\n\n  public async getByExternalId({\n    externalId,\n    type,\n    language = this.locale,\n  }:\n    | {\n        externalId: string;\n        type: 'imdb';\n        language?: string;\n      }\n    | {\n        externalId: number;\n        type: 'tvdb';\n        language?: string;\n      }): Promise<TmdbExternalIdResponse> {\n    try {\n      const data = await this.get<TmdbExternalIdResponse>(\n        `/find/${externalId}`,\n        {\n          params: {\n            external_source: type === 'imdb' ? 'imdb_id' : 'tvdb_id',\n            language,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to find by external ID: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getMediaByImdbId({\n    imdbId,\n    language = this.locale,\n  }: {\n    imdbId: string;\n    language?: string;\n  }): Promise<TmdbMovieDetails | TmdbTvDetails> {\n    try {\n      const extResponse = await this.getByExternalId({\n        externalId: imdbId,\n        type: 'imdb',\n      });\n\n      if (extResponse.movie_results[0]) {\n        const movie = await this.getMovie({\n          movieId: extResponse.movie_results[0].id,\n          language,\n        });\n\n        return movie;\n      }\n\n      if (extResponse.tv_results[0]) {\n        const tvshow = await this.getTvShow({\n          tvId: extResponse.tv_results[0].id,\n          language,\n        });\n\n        return tvshow;\n      }\n\n      throw new Error(`No movie or show returned from API for ID ${imdbId}`);\n    } catch (e) {\n      throw new Error(\n        `[TMDB] Failed to find media using external IMDb ID: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getShowByTvdbId({\n    tvdbId,\n    language = this.locale,\n  }: {\n    tvdbId: number;\n    language?: string;\n  }): Promise<TmdbTvDetails> {\n    try {\n      const extResponse = await this.getByExternalId({\n        externalId: tvdbId,\n        type: 'tvdb',\n      });\n\n      if (extResponse.tv_results[0]) {\n        const tvshow = await this.getTvShow({\n          tvId: extResponse.tv_results[0].id,\n          language,\n        });\n\n        return tvshow;\n      }\n\n      throw new Error(`No show returned from API for ID ${tvdbId}`);\n    } catch (e) {\n      throw new Error(\n        `[TMDB] Failed to get TV show using the external TVDB ID: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getCollection({\n    collectionId,\n    language = this.locale,\n  }: {\n    collectionId: number;\n    language?: string;\n  }): Promise<TmdbCollection> {\n    try {\n      const data = await this.get<TmdbCollection>(\n        `/collection/${collectionId}`,\n        {\n          params: {\n            language,\n          },\n        }\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch collection: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getRegions(): Promise<TmdbRegion[]> {\n    try {\n      const data = await this.get<TmdbRegion[]>(\n        '/configuration/countries',\n        {},\n        86400 // 24 hours\n      );\n\n      const regions = sortBy(data, 'english_name');\n\n      return regions;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch countries: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getLanguages(): Promise<TmdbLanguage[]> {\n    try {\n      const data = await this.get<TmdbLanguage[]>(\n        '/configuration/languages',\n        {},\n        86400 // 24 hours\n      );\n\n      const languages = sortBy(data, 'english_name');\n\n      return languages;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch langauges: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getStudio(studioId: number): Promise<TmdbProductionCompany> {\n    try {\n      const data = await this.get<TmdbProductionCompany>(\n        `/company/${studioId}`\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch movie studio: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getNetwork(networkId: number): Promise<TmdbNetwork> {\n    try {\n      const data = await this.get<TmdbNetwork>(`/network/${networkId}`);\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch TV network: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getMovieGenres({\n    language = this.locale,\n  }: {\n    language?: string;\n  } = {}): Promise<TmdbGenre[]> {\n    try {\n      const data = await this.get<TmdbGenresResult>(\n        '/genre/movie/list',\n        {\n          params: {\n            language,\n          },\n        },\n        86400 // 24 hours\n      );\n\n      if (\n        !language.startsWith('en') &&\n        data.genres.some((genre) => !genre.name)\n      ) {\n        const englishData = await this.get<TmdbGenresResult>(\n          '/genre/movie/list',\n          {\n            params: {\n              language: 'en',\n            },\n          },\n          86400 // 24 hours\n        );\n\n        data.genres\n          .filter((genre) => !genre.name)\n          .forEach((genre) => {\n            genre.name =\n              englishData.genres.find(\n                (englishGenre) => englishGenre.id === genre.id\n              )?.name ?? '';\n          });\n      }\n\n      const movieGenres = sortBy(\n        data.genres.filter((genre) => genre.name),\n        'name'\n      );\n\n      return movieGenres;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch movie genres: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getTvGenres({\n    language = this.locale,\n  }: {\n    language?: string;\n  } = {}): Promise<TmdbGenre[]> {\n    try {\n      const data = await this.get<TmdbGenresResult>(\n        '/genre/tv/list',\n        {\n          params: {\n            language,\n          },\n        },\n        86400 // 24 hours\n      );\n\n      if (\n        !language.startsWith('en') &&\n        data.genres.some((genre) => !genre.name)\n      ) {\n        const englishData = await this.get<TmdbGenresResult>(\n          '/genre/tv/list',\n          {\n            params: {\n              language: 'en',\n            },\n          },\n          86400 // 24 hours\n        );\n\n        data.genres\n          .filter((genre) => !genre.name)\n          .forEach((genre) => {\n            genre.name =\n              englishData.genres.find(\n                (englishGenre) => englishGenre.id === genre.id\n              )?.name ?? '';\n          });\n      }\n\n      const tvGenres = sortBy(\n        data.genres.filter((genre) => genre.name),\n        'name'\n      );\n\n      return tvGenres;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to fetch TV genres: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public getMovieCertifications =\n    async (): Promise<TmdbCertificationResponse> => {\n      try {\n        const data = await this.get<TmdbCertificationResponse>(\n          '/certification/movie/list',\n          {},\n          604800 // 7 days\n        );\n\n        return data;\n      } catch (e) {\n        throw new Error(`[TMDB] Failed to fetch movie certifications: ${e}`, {\n          cause: e,\n        });\n      }\n    };\n\n  public getTvCertifications = async (): Promise<TmdbCertificationResponse> => {\n    try {\n      const data = await this.get<TmdbCertificationResponse>(\n        '/certification/tv/list',\n        {},\n        604800 // 7 days\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(\n        `[TMDB] Failed to fetch TV certifications: ${e.message}`,\n        { cause: e }\n      );\n    }\n  };\n\n  public async getKeywordDetails({\n    keywordId,\n  }: {\n    keywordId: number;\n  }): Promise<TmdbKeyword | null> {\n    try {\n      const data = await this.get<TmdbKeyword>(\n        `/keyword/${keywordId}`,\n        undefined,\n        604800 // 7 days\n      );\n\n      return data;\n    } catch (e) {\n      if (e.response?.status === 404) {\n        return null;\n      }\n      throw new Error(`[TMDB] Failed to fetch keyword: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async searchKeyword({\n    query,\n    page = 1,\n  }: {\n    query: string;\n    page?: number;\n  }): Promise<TmdbKeywordSearchResponse> {\n    try {\n      const data = await this.get<TmdbKeywordSearchResponse>(\n        '/search/keyword',\n        {\n          params: {\n            query,\n            page,\n          },\n        },\n        86400 // 24 hours\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to search keyword: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async searchCompany({\n    query,\n    page = 1,\n  }: {\n    query: string;\n    page?: number;\n  }): Promise<TmdbCompanySearchResponse> {\n    try {\n      const data = await this.get<TmdbCompanySearchResponse>(\n        '/search/company',\n        {\n          params: {\n            query,\n            page,\n          },\n        },\n        86400 // 24 hours\n      );\n\n      return data;\n    } catch (e) {\n      throw new Error(`[TMDB] Failed to search companies: ${e.message}`, {\n        cause: e,\n      });\n    }\n  }\n\n  public async getAvailableWatchProviderRegions({\n    language,\n  }: {\n    language?: string;\n  }) {\n    try {\n      const data = await this.get<{ results: TmdbWatchProviderRegion[] }>(\n        '/watch/providers/regions',\n        {\n          params: {\n            language: language ?? this.originalLanguage,\n          },\n        },\n        86400 // 24 hours\n      );\n\n      return data.results;\n    } catch (e) {\n      throw new Error(\n        `[TMDB] Failed to fetch available watch regions: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getMovieWatchProviders({\n    language,\n    watchRegion,\n  }: {\n    language?: string;\n    watchRegion: string;\n  }) {\n    try {\n      const data = await this.get<{ results: TmdbWatchProviderDetails[] }>(\n        '/watch/providers/movie',\n        {\n          params: {\n            language: language ?? this.originalLanguage,\n            watch_region: watchRegion,\n          },\n        },\n        86400 // 24 hours\n      );\n\n      return data.results;\n    } catch (e) {\n      throw new Error(\n        `[TMDB] Failed to fetch movie watch providers: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n\n  public async getTvWatchProviders({\n    language,\n    watchRegion,\n  }: {\n    language?: string;\n    watchRegion: string;\n  }) {\n    try {\n      const data = await this.get<{ results: TmdbWatchProviderDetails[] }>(\n        '/watch/providers/tv',\n        {\n          params: {\n            language: language ?? this.originalLanguage,\n            watch_region: watchRegion,\n          },\n        },\n        86400 // 24 hours\n      );\n\n      return data.results;\n    } catch (e) {\n      throw new Error(\n        `[TMDB] Failed to fetch TV watch providers: ${e.message}`,\n        { cause: e }\n      );\n    }\n  }\n}\n\nexport default TheMovieDb;\n"
  },
  {
    "path": "server/api/themoviedb/interfaces.ts",
    "content": "interface TmdbMediaResult {\n  id: number;\n  media_type: string;\n  popularity: number;\n  poster_path?: string;\n  backdrop_path?: string;\n  vote_count: number;\n  vote_average: number;\n  genre_ids: number[];\n  overview: string;\n  original_language: string;\n}\n\nexport interface TmdbMovieResult extends TmdbMediaResult {\n  media_type: 'movie';\n  title: string;\n  original_title: string;\n  release_date: string;\n  adult: boolean;\n  video: boolean;\n}\n\nexport interface TmdbTvResult extends TmdbMediaResult {\n  media_type: 'tv';\n  name: string;\n  original_name: string;\n  origin_country: string[];\n  first_air_date: string;\n}\n\nexport interface TmdbCollectionResult {\n  id: number;\n  media_type: 'collection';\n  title: string;\n  original_title: string;\n  adult: boolean;\n  poster_path?: string;\n  backdrop_path?: string;\n  overview: string;\n  original_language: string;\n}\n\nexport interface TmdbPersonResult {\n  id: number;\n  name: string;\n  popularity: number;\n  profile_path?: string;\n  adult: boolean;\n  media_type: 'person';\n  known_for: (TmdbMovieResult | TmdbTvResult)[];\n}\n\ninterface TmdbPaginatedResponse {\n  page: number;\n  total_results: number;\n  total_pages: number;\n}\n\nexport interface TmdbSearchMultiResponse extends TmdbPaginatedResponse {\n  results: (\n    | TmdbMovieResult\n    | TmdbTvResult\n    | TmdbPersonResult\n    | TmdbCollectionResult\n  )[];\n}\n\nexport interface TmdbSearchMovieResponse extends TmdbPaginatedResponse {\n  results: TmdbMovieResult[];\n}\n\nexport interface TmdbSearchTvResponse extends TmdbPaginatedResponse {\n  results: TmdbTvResult[];\n}\n\nexport interface TmdbUpcomingMoviesResponse extends TmdbPaginatedResponse {\n  dates: {\n    maximum: string;\n    minimum: string;\n  };\n  results: TmdbMovieResult[];\n}\n\nexport interface TmdbExternalIdResponse {\n  movie_results: TmdbMovieResult[];\n  tv_results: TmdbTvResult[];\n  person_results: TmdbPersonResult[];\n}\n\nexport interface TmdbCreditCast {\n  cast_id: number;\n  character: string;\n  credit_id: string;\n  gender?: number;\n  id: number;\n  name: string;\n  order: number;\n  profile_path?: string;\n}\n\nexport interface TmdbAggregateCreditCast extends TmdbCreditCast {\n  roles: {\n    credit_id: string;\n    character: string;\n    episode_count: number;\n  }[];\n}\n\nexport interface TmdbCreditCrew {\n  credit_id: string;\n  gender?: number;\n  id: number;\n  name: string;\n  profile_path?: string;\n  job: string;\n  department: string;\n}\n\nexport interface TmdbExternalIds {\n  imdb_id?: string;\n  freebase_mid?: string;\n  freebase_id?: string;\n  tvdb_id?: number;\n  tvrage_id?: string;\n  facebook_id?: string;\n  instagram_id?: string;\n  twitter_id?: string;\n}\n\nexport interface TmdbProductionCompany {\n  id: number;\n  logo_path?: string;\n  name: string;\n  origin_country: string;\n  homepage?: string;\n  headquarters?: string;\n  description?: string;\n}\n\nexport interface TmdbMovieDetails {\n  id: number;\n  imdb_id?: string;\n  adult: boolean;\n  backdrop_path?: string;\n  poster_path?: string;\n  budget: number;\n  genres: {\n    id: number;\n    name: string;\n  }[];\n  homepage?: string;\n  original_language: string;\n  original_title: string;\n  overview?: string;\n  popularity: number;\n  production_companies: TmdbProductionCompany[];\n  production_countries: {\n    iso_3166_1: string;\n    name: string;\n  }[];\n  release_date: string;\n  release_dates: TmdbMovieReleaseResult;\n  revenue: number;\n  runtime?: number;\n  spoken_languages: {\n    iso_639_1: string;\n    name: string;\n  }[];\n  status: string;\n  tagline?: string;\n  title: string;\n  video: boolean;\n  vote_average: number;\n  vote_count: number;\n  credits: {\n    cast: TmdbCreditCast[];\n    crew: TmdbCreditCrew[];\n  };\n  belongs_to_collection?: {\n    id: number;\n    name: string;\n    poster_path?: string;\n    backdrop_path?: string;\n  };\n  external_ids: TmdbExternalIds;\n  videos: TmdbVideoResult;\n  'watch/providers'?: {\n    id: number;\n    results?: { [iso_3166_1: string]: TmdbWatchProviders };\n  };\n  keywords: {\n    keywords: TmdbKeyword[];\n  };\n}\n\nexport interface TmdbVideo {\n  id: string;\n  key: string;\n  name: string;\n  site: 'YouTube';\n  size: number;\n  type:\n    | 'Clip'\n    | 'Teaser'\n    | 'Trailer'\n    | 'Featurette'\n    | 'Opening Credits'\n    | 'Behind the Scenes'\n    | 'Bloopers';\n}\n\nexport interface TmdbTvEpisodeResult {\n  id: number;\n  air_date: string | null;\n  episode_number: number;\n  name: string;\n  overview: string;\n  production_code: string;\n  season_number: number;\n  show_id: number;\n  still_path: string;\n  vote_average: number;\n  vote_count: number;\n}\n\nexport interface TmdbTvSeasonResult {\n  id: number;\n  air_date: string;\n  episode_count: number;\n  name: string;\n  overview: string;\n  poster_path?: string;\n  season_number: number;\n}\n\nexport interface TmdbTvDetails {\n  id: number;\n  backdrop_path?: string;\n  content_ratings: TmdbTvRatingResult;\n  created_by: {\n    id: number;\n    credit_id: string;\n    name: string;\n    gender: number;\n    profile_path?: string;\n  }[];\n  episode_run_time: number[];\n  first_air_date: string;\n  genres: {\n    id: number;\n    name: string;\n  }[];\n  homepage: string;\n  in_production: boolean;\n  languages: string[];\n  last_air_date: string;\n  last_episode_to_air?: TmdbTvEpisodeResult;\n  name: string;\n  next_episode_to_air?: TmdbTvEpisodeResult;\n  networks: TmdbNetwork[];\n  number_of_episodes: number;\n  number_of_seasons: number;\n  origin_country: string[];\n  original_language: string;\n  original_name: string;\n  overview: string;\n  popularity: number;\n  poster_path?: string;\n  production_companies: {\n    id: number;\n    logo_path?: string;\n    name: string;\n    origin_country: string;\n  }[];\n  production_countries: {\n    iso_3166_1: string;\n    name: string;\n  }[];\n  spoken_languages: {\n    english_name: string;\n    iso_639_1: string;\n    name: string;\n  }[];\n  seasons: TmdbTvSeasonResult[];\n  status: string;\n  tagline?: string;\n  type: string;\n  vote_average: number;\n  vote_count: number;\n  aggregate_credits: {\n    cast: TmdbAggregateCreditCast[];\n  };\n  credits: {\n    crew: TmdbCreditCrew[];\n  };\n  external_ids: TmdbExternalIds;\n  keywords: {\n    results: TmdbKeyword[];\n  };\n  videos: TmdbVideoResult;\n  'watch/providers'?: {\n    id: number;\n    results?: { [iso_3166_1: string]: TmdbWatchProviders };\n  };\n}\n\nexport interface TmdbVideoResult {\n  results: TmdbVideo[];\n}\n\nexport interface TmdbTvRatingResult {\n  results: TmdbRating[];\n}\n\nexport interface TmdbRating {\n  iso_3166_1: string;\n  rating: string;\n}\n\nexport interface TmdbMovieReleaseResult {\n  results: TmdbRelease[];\n}\n\nexport interface TmdbRelease extends TmdbRating {\n  release_dates: {\n    certification: string;\n    iso_639_1?: string;\n    note?: string;\n    release_date: string;\n    type: number;\n  }[];\n}\n\nexport interface TmdbKeyword {\n  id: number;\n  name: string;\n}\n\nexport interface TmdbPersonDetails {\n  id: number;\n  name: string;\n  birthday: string;\n  deathday: string;\n  known_for_department: string;\n  also_known_as?: string[];\n  gender: number;\n  biography: string;\n  popularity: number;\n  place_of_birth?: string;\n  profile_path?: string;\n  adult: boolean;\n  imdb_id?: string;\n  homepage?: string;\n}\n\nexport interface TmdbPersonCredit {\n  id: number;\n  original_language: string;\n  episode_count: number;\n  overview: string;\n  origin_country: string[];\n  original_name: string;\n  vote_count: number;\n  name: string;\n  media_type?: string;\n  popularity: number;\n  credit_id: string;\n  backdrop_path?: string;\n  first_air_date: string;\n  vote_average: number;\n  genre_ids?: number[];\n  poster_path?: string;\n  original_title: string;\n  video?: boolean;\n  title: string;\n  adult: boolean;\n  release_date: string;\n}\n\nexport interface TmdbPersonCreditCast extends TmdbPersonCredit {\n  character: string;\n}\n\nexport interface TmdbPersonCreditCrew extends TmdbPersonCredit {\n  department: string;\n  job: string;\n}\n\nexport interface TmdbPersonCombinedCredits {\n  id: number;\n  cast: TmdbPersonCreditCast[];\n  crew: TmdbPersonCreditCrew[];\n}\n\nexport interface TmdbSeasonWithEpisodes extends Omit<\n  TmdbTvSeasonResult,\n  'episode_count'\n> {\n  episodes: TmdbTvEpisodeResult[];\n  external_ids: TmdbExternalIds;\n}\n\nexport interface TmdbCollection {\n  id: number;\n  name: string;\n  overview?: string;\n  poster_path?: string;\n  backdrop_path?: string;\n  parts: TmdbMovieResult[];\n}\n\nexport interface TmdbRegion {\n  iso_3166_1: string;\n  english_name: string;\n}\n\nexport interface TmdbLanguage {\n  iso_639_1: string;\n  english_name: string;\n  name: string;\n}\n\nexport interface TmdbGenresResult {\n  genres: TmdbGenre[];\n}\n\nexport interface TmdbGenre {\n  id: number;\n  name: string;\n}\n\nexport interface TmdbNetwork {\n  id: number;\n  name: string;\n  headquarters?: string;\n  homepage?: string;\n  logo_path?: string;\n  origin_country?: string;\n}\n\nexport interface TmdbWatchProviders {\n  link?: string;\n  buy?: TmdbWatchProviderDetails[];\n  flatrate?: TmdbWatchProviderDetails[];\n}\n\nexport interface TmdbWatchProviderDetails {\n  display_priority?: number;\n  logo_path?: string;\n  provider_id: number;\n  provider_name: string;\n}\n\nexport interface TmdbKeywordSearchResponse extends TmdbPaginatedResponse {\n  results: TmdbKeyword[];\n}\n\n// We have production companies, but the company search results return less data\nexport interface TmdbCompany {\n  id: number;\n  logo_path?: string;\n  name: string;\n}\n\nexport interface TmdbCompanySearchResponse extends TmdbPaginatedResponse {\n  results: TmdbCompany[];\n}\n\nexport interface TmdbWatchProviderRegion {\n  iso_3166_1: string;\n  english_name: string;\n  native_name: string;\n}\n"
  },
  {
    "path": "server/api/tvdb/index.ts",
    "content": "import ExternalAPI from '@server/api/externalapi';\nimport type { TvShowProvider } from '@server/api/provider';\nimport TheMovieDb from '@server/api/themoviedb';\nimport type {\n  TmdbSeasonWithEpisodes,\n  TmdbTvDetails,\n  TmdbTvEpisodeResult,\n  TmdbTvSeasonResult,\n} from '@server/api/themoviedb/interfaces';\nimport {\n  convertTmdbLanguageToTvdbWithFallback,\n  type TvdbBaseResponse,\n  type TvdbEpisode,\n  type TvdbLoginResponse,\n  type TvdbSeasonDetails,\n  type TvdbTvDetails,\n} from '@server/api/tvdb/interfaces';\nimport cacheManager, { type AvailableCacheIds } from '@server/lib/cache';\nimport logger from '@server/logger';\n\ninterface TvdbConfig {\n  baseUrl: string;\n  maxRequestsPerSecond: number;\n  maxRequests: number;\n  cachePrefix: AvailableCacheIds;\n}\n\nconst DEFAULT_CONFIG: TvdbConfig = {\n  baseUrl: 'https://api4.thetvdb.com/v4',\n  maxRequestsPerSecond: 50,\n  maxRequests: 20,\n  cachePrefix: 'tvdb' as const,\n};\n\nconst enum TvdbIdStatus {\n  INVALID = -1,\n}\n\ntype TvdbId = number;\ntype ValidTvdbId = Exclude<TvdbId, TvdbIdStatus.INVALID>;\n\nclass Tvdb extends ExternalAPI implements TvShowProvider {\n  static instance: Tvdb;\n  private readonly tmdb: TheMovieDb;\n  private static readonly DEFAULT_CACHE_TTL = 43200;\n  private static readonly DEFAULT_LANGUAGE = 'eng';\n  private token: string;\n  private pin?: string;\n\n  constructor(pin?: string) {\n    const finalConfig = { ...DEFAULT_CONFIG };\n    super(\n      finalConfig.baseUrl,\n      {},\n      {\n        nodeCache: cacheManager.getCache(finalConfig.cachePrefix).data,\n        rateLimit: {\n          maxRequests: finalConfig.maxRequests,\n          maxRPS: finalConfig.maxRequestsPerSecond,\n        },\n      }\n    );\n    this.pin = pin;\n    this.tmdb = new TheMovieDb();\n  }\n\n  public static async getInstance(): Promise<Tvdb> {\n    if (!this.instance) {\n      this.instance = new Tvdb();\n      await this.instance.login();\n    }\n\n    return this.instance;\n  }\n\n  private async refreshToken(): Promise<void> {\n    try {\n      if (!this.token) {\n        await this.login();\n        return;\n      }\n\n      const base64Url = this.token.split('.')[1];\n      const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');\n      const payload = JSON.parse(Buffer.from(base64, 'base64').toString());\n\n      if (!payload.exp) {\n        await this.login();\n      }\n\n      const now = Math.floor(Date.now() / 1000);\n      const diff = payload.exp - now;\n\n      // refresh token 1 week before expiration\n      if (diff < 604800) {\n        await this.login();\n      }\n    } catch (error) {\n      this.handleError('Failed to refresh token', error);\n    }\n  }\n\n  public async test(): Promise<void> {\n    try {\n      await this.login();\n    } catch (error) {\n      this.handleError('Login failed', error);\n      throw error;\n    }\n  }\n\n  async login(): Promise<TvdbLoginResponse> {\n    let body: { apiKey: string; pin?: string } = {\n      apiKey: 'd00d9ecb-a9d0-4860-958a-74b14a041405',\n    };\n\n    if (this.pin) {\n      body = {\n        ...body,\n        pin: this.pin,\n      };\n    }\n\n    const response = await this.post<TvdbBaseResponse<TvdbLoginResponse>>(\n      '/login',\n      {\n        ...body,\n      }\n    );\n\n    this.token = response.data.token;\n\n    return response.data;\n  }\n\n  public async getShowByTvdbId({\n    tvdbId,\n    language,\n  }: {\n    tvdbId: number;\n    language?: string;\n  }): Promise<TmdbTvDetails> {\n    try {\n      const tmdbTvShow = await this.tmdb.getShowByTvdbId({\n        tvdbId: tvdbId,\n        language,\n      });\n\n      try {\n        await this.refreshToken();\n\n        const validTvdbId = this.getTvdbIdFromTmdb(tmdbTvShow);\n\n        if (this.isValidTvdbId(validTvdbId)) {\n          return this.enrichTmdbShowWithTvdbData(tmdbTvShow, validTvdbId);\n        }\n\n        return tmdbTvShow;\n      } catch {\n        return tmdbTvShow;\n      }\n    } catch (error) {\n      this.handleError('Failed to fetch TV show details', error);\n      throw error;\n    }\n  }\n\n  public async getTvShow({\n    tvId,\n    language,\n  }: {\n    tvId: number;\n    language?: string;\n  }): Promise<TmdbTvDetails> {\n    try {\n      const tmdbTvShow = await this.tmdb.getTvShow({ tvId, language });\n\n      try {\n        await this.refreshToken();\n\n        const tvdbId = this.getTvdbIdFromTmdb(tmdbTvShow);\n\n        if (this.isValidTvdbId(tvdbId)) {\n          return await this.enrichTmdbShowWithTvdbData(tmdbTvShow, tvdbId);\n        }\n\n        return tmdbTvShow;\n      } catch (error) {\n        this.handleError('Failed to fetch TV show details', error);\n        return tmdbTvShow;\n      }\n    } catch (error) {\n      this.handleError('Failed to fetch TV show details', error);\n      return this.tmdb.getTvShow({ tvId, language });\n    }\n  }\n\n  public async getTvSeason({\n    tvId,\n    seasonNumber,\n    language = Tvdb.DEFAULT_LANGUAGE,\n  }: {\n    tvId: number;\n    seasonNumber: number;\n    language?: string;\n  }): Promise<TmdbSeasonWithEpisodes> {\n    try {\n      const tmdbTvShow = await this.tmdb.getTvShow({ tvId, language });\n\n      try {\n        await this.refreshToken();\n\n        const tvdbId = this.getTvdbIdFromTmdb(tmdbTvShow);\n\n        if (!this.isValidTvdbId(tvdbId)) {\n          return await this.tmdb.getTvSeason({ tvId, seasonNumber, language });\n        }\n\n        return await this.getTvdbSeasonData(\n          tvdbId,\n          seasonNumber,\n          tvId,\n          language\n        );\n      } catch (error) {\n        this.handleError('Failed to fetch TV season details', error);\n        return await this.tmdb.getTvSeason({ tvId, seasonNumber, language });\n      }\n    } catch (error) {\n      logger.error(\n        `[TVDB] Failed to fetch TV season details: ${error.message}`\n      );\n      throw error;\n    }\n  }\n\n  private async enrichTmdbShowWithTvdbData(\n    tmdbTvShow: TmdbTvDetails,\n    tvdbId: ValidTvdbId\n  ): Promise<TmdbTvDetails> {\n    try {\n      await this.refreshToken();\n\n      const tvdbData = await this.fetchTvdbShowData(tvdbId);\n      const seasons = this.processSeasons(tvdbData);\n\n      if (!seasons.length) {\n        return tmdbTvShow;\n      }\n\n      return { ...tmdbTvShow, seasons };\n    } catch (error) {\n      logger.error(\n        `Failed to enrich TMDB show with TVDB data: ${error.message} token: ${this.token}`\n      );\n      return tmdbTvShow;\n    }\n  }\n\n  private async fetchTvdbShowData(tvdbId: number): Promise<TvdbTvDetails> {\n    const resp = await this.get<TvdbBaseResponse<TvdbTvDetails>>(\n      `/series/${tvdbId}/extended?meta=episodes&short=true`,\n      {\n        headers: {\n          Authorization: `Bearer ${this.token}`,\n        },\n      },\n      Tvdb.DEFAULT_CACHE_TTL\n    );\n\n    return resp.data;\n  }\n\n  private processSeasons(tvdbData: TvdbTvDetails): TmdbTvSeasonResult[] {\n    if (!tvdbData || !tvdbData.seasons || !tvdbData.episodes) {\n      return [];\n    }\n\n    const seasons = tvdbData.seasons\n      .filter((season) => season.type && season.type.type === 'official')\n      .sort((a, b) => a.number - b.number)\n      .map((season) => this.createSeasonData(season, tvdbData))\n      .filter(\n        (season) => season && season.season_number >= 0\n      ) as TmdbTvSeasonResult[];\n\n    return seasons;\n  }\n\n  private createSeasonData(\n    season: TvdbSeasonDetails,\n    tvdbData: TvdbTvDetails\n  ): TmdbTvSeasonResult {\n    const seasonNumber = season.number ?? -1;\n    if (seasonNumber < 0) {\n      return {\n        id: 0,\n        episode_count: 0,\n        name: '',\n        overview: '',\n        season_number: -1,\n        poster_path: '',\n        air_date: '',\n      };\n    }\n\n    const episodeCount = tvdbData.episodes.filter(\n      (episode) => episode.seasonNumber === season.number\n    ).length;\n\n    return {\n      id: tvdbData.id,\n      episode_count: episodeCount,\n      name: `${season.number}`,\n      overview: '',\n      season_number: season.number,\n      poster_path: '',\n      air_date: '',\n    };\n  }\n\n  private async getTvdbSeasonData(\n    tvdbId: number,\n    seasonNumber: number,\n    tvId: number,\n    language: string = Tvdb.DEFAULT_LANGUAGE\n  ): Promise<TmdbSeasonWithEpisodes> {\n    const tvdbData = await this.fetchTvdbShowData(tvdbId);\n\n    if (!tvdbData) {\n      logger.error(`Failed to fetch TVDB data for ID: ${tvdbId}`);\n      return this.createEmptySeasonResponse(tvId);\n    }\n\n    // get season id\n    const season = tvdbData.seasons.find(\n      (season) =>\n        season.number === seasonNumber &&\n        season.type.type &&\n        season.type.type === 'official'\n    );\n\n    if (!season) {\n      logger.error(\n        `Failed to find season ${seasonNumber} for TVDB ID: ${tvdbId}`\n      );\n      return this.createEmptySeasonResponse(tvId);\n    }\n\n    const wantedTranslation = convertTmdbLanguageToTvdbWithFallback(\n      language,\n      Tvdb.DEFAULT_LANGUAGE\n    );\n\n    // check if translation is available for the season\n    const availableTranslation = season.nameTranslations.filter(\n      (translation) =>\n        translation === wantedTranslation ||\n        translation === Tvdb.DEFAULT_LANGUAGE\n    );\n\n    if (!availableTranslation) {\n      return this.getSeasonWithOriginalLanguage(\n        tvdbId,\n        tvId,\n        seasonNumber,\n        season\n      );\n    }\n\n    return this.getSeasonWithTranslation(\n      tvdbId,\n      tvId,\n      seasonNumber,\n      season,\n      wantedTranslation\n    );\n  }\n\n  private async getSeasonWithTranslation(\n    tvdbId: number,\n    tvId: number,\n    seasonNumber: number,\n    season: TvdbSeasonDetails,\n    language: string\n  ): Promise<TmdbSeasonWithEpisodes> {\n    if (!season) {\n      logger.error(\n        `Failed to find season ${seasonNumber} for TVDB ID: ${tvdbId}`\n      );\n      return this.createEmptySeasonResponse(tvId);\n    }\n\n    const allEpisodes = [] as TvdbEpisode[];\n    let page = 0;\n    // Limit to max 50 pages to avoid infinite loops.\n    // 50 pages with 500 items per page = 25_000 episodes in a series which should be more than enough\n    const maxPages = 50;\n\n    while (page < maxPages) {\n      const resp = await this.get<TvdbBaseResponse<TvdbSeasonDetails>>(\n        `/series/${tvdbId}/episodes/default/${language}`,\n        {\n          headers: {\n            Authorization: `Bearer ${this.token}`,\n          },\n          params: {\n            page: page,\n          },\n        }\n      );\n\n      if (!resp?.data?.episodes) {\n        logger.warn(\n          `No episodes found for TVDB ID: ${tvdbId} on page ${page} for season ${seasonNumber}`\n        );\n        break;\n      }\n\n      const { episodes } = resp.data;\n\n      if (!episodes) {\n        logger.debug(\n          `No more episodes found for TVDB ID: ${tvdbId} on page ${page} for season ${seasonNumber}`\n        );\n        break;\n      }\n\n      allEpisodes.push(...episodes);\n\n      const hasNextPage = resp.links?.next && episodes.length > 0;\n\n      if (!hasNextPage) {\n        break;\n      }\n\n      page++;\n    }\n\n    if (page >= maxPages) {\n      logger.warn(\n        `Reached max pages (${maxPages}) for TVDB ID: ${tvdbId} on season ${seasonNumber} with language ${language}. There might be more episodes available.`\n      );\n    }\n\n    const episodes = this.processEpisodes(\n      { ...season, episodes: allEpisodes },\n      seasonNumber,\n      tvId\n    );\n\n    return {\n      episodes,\n      external_ids: { tvdb_id: tvdbId },\n      name: '',\n      overview: '',\n      id: season.id,\n      air_date: season.firstAired,\n      season_number: episodes.length,\n    };\n  }\n\n  private async getSeasonWithOriginalLanguage(\n    tvdbId: number,\n    tvId: number,\n    seasonNumber: number,\n    season: TvdbSeasonDetails\n  ): Promise<TmdbSeasonWithEpisodes> {\n    if (!season) {\n      logger.error(\n        `Failed to find season ${seasonNumber} for TVDB ID: ${tvdbId}`\n      );\n      return this.createEmptySeasonResponse(tvId);\n    }\n\n    const resp = await this.get<TvdbBaseResponse<TvdbSeasonDetails>>(\n      `/seasons/${season.id}/extended`,\n      {\n        headers: {\n          Authorization: `Bearer ${this.token}`,\n        },\n      }\n    );\n\n    const seasons = resp.data;\n\n    const episodes = this.processEpisodes(seasons, seasonNumber, tvId);\n\n    return {\n      episodes,\n      external_ids: { tvdb_id: tvdbId },\n      name: '',\n      overview: '',\n      id: seasons.id,\n      air_date: seasons.firstAired,\n      season_number: episodes.length,\n    };\n  }\n\n  private processEpisodes(\n    tvdbSeason: TvdbSeasonDetails,\n    seasonNumber: number,\n    tvId: number\n  ): TmdbTvEpisodeResult[] {\n    if (!tvdbSeason || !tvdbSeason.episodes) {\n      logger.error('No episodes found in TVDB season data');\n      return [];\n    }\n\n    return tvdbSeason.episodes\n      .filter((episode) => episode.seasonNumber === seasonNumber)\n      .map((episode, index) => this.createEpisodeData(episode, index, tvId));\n  }\n\n  private createEpisodeData(\n    episode: TvdbEpisode,\n    index: number,\n    tvId: number\n  ): TmdbTvEpisodeResult {\n    return {\n      id: episode.id,\n      air_date: episode.aired,\n      episode_number: episode.number,\n      name: episode.name || `Episode ${index + 1}`,\n      overview: episode.overview || '',\n      season_number: episode.seasonNumber,\n      production_code: '',\n      show_id: tvId,\n      still_path:\n        episode.image && !episode.image.startsWith('https://')\n          ? 'https://artworks.thetvdb.com' + episode.image\n          : '',\n      vote_average: 1,\n      vote_count: 1,\n    };\n  }\n\n  private createEmptySeasonResponse(tvId: number): TmdbSeasonWithEpisodes {\n    return {\n      episodes: [],\n      external_ids: { tvdb_id: tvId },\n      name: '',\n      overview: '',\n      id: 0,\n      air_date: '',\n      season_number: 0,\n    };\n  }\n\n  private getTvdbIdFromTmdb(tmdbTvShow: TmdbTvDetails): TvdbId {\n    return tmdbTvShow?.external_ids?.tvdb_id ?? TvdbIdStatus.INVALID;\n  }\n\n  private isValidTvdbId(tvdbId: TvdbId): tvdbId is ValidTvdbId {\n    return tvdbId !== TvdbIdStatus.INVALID;\n  }\n\n  private handleError(context: string, error: Error): void {\n    throw new Error(`[TVDB] ${context}: ${error.message}`);\n  }\n}\n\nexport default Tvdb;\n"
  },
  {
    "path": "server/api/tvdb/interfaces.ts",
    "content": "import { type AvailableLocale } from '@server/types/languages';\n\nexport interface TvdbBaseResponse<T> {\n  data: T;\n  errors: string;\n  links?: TvdbPagination;\n}\n\nexport interface TvdbPagination {\n  prev?: string;\n  self: string;\n  next?: string;\n  totalItems: number;\n  pageSize: number;\n}\n\nexport interface TvdbLoginResponse {\n  token: string;\n}\n\ninterface TvDetailsAliases {\n  language: string;\n  name: string;\n}\n\ninterface TvDetailsStatus {\n  id: number;\n  name: string;\n  recordType: string;\n  keepUpdated: boolean;\n}\n\nexport interface TvdbTvDetails {\n  id: number;\n  name: string;\n  slug: string;\n  image: string;\n  nameTranslations: string[];\n  overwiewTranslations: string[];\n  aliases: TvDetailsAliases[];\n  firstAired: Date;\n  lastAired: Date;\n  nextAired: Date | string;\n  score: number;\n  status: TvDetailsStatus;\n  originalCountry: string;\n  originalLanguage: string;\n  defaultSeasonType: string;\n  isOrderRandomized: boolean;\n  lastUpdated: Date;\n  averageRuntime: number;\n  seasons: TvdbSeasonDetails[];\n  episodes: TvdbEpisode[];\n}\n\ninterface TvdbCompanyType {\n  companyTypeId: number;\n  companyTypeName: string;\n}\n\ninterface TvdbParentCompany {\n  id?: number;\n  name?: string;\n  relation?: {\n    id?: number;\n    typeName?: string;\n  };\n}\n\ninterface TvdbCompany {\n  id: number;\n  name: string;\n  slug: string;\n  nameTranslations?: string[];\n  overviewTranslations?: string[];\n  aliases?: string[];\n  country: string;\n  primaryCompanyType: number;\n  activeDate: string;\n  inactiveDate?: string;\n  companyType: TvdbCompanyType;\n  parentCompany: TvdbParentCompany;\n  tagOptions?: string[];\n}\n\ninterface TvdbType {\n  id: number;\n  name: string;\n  type: string;\n  alternateName?: string;\n}\n\ninterface TvdbArtwork {\n  id: number;\n  image: string;\n  thumbnail: string;\n  language: string;\n  type: number;\n  score: number;\n  width: number;\n  height: number;\n  includesText: boolean;\n}\n\nexport interface TvdbEpisode {\n  id: number;\n  seriesId: number;\n  name: string;\n  aired: string;\n  runtime: number;\n  nameTranslations: string[];\n  overview?: string;\n  overviewTranslations: string[];\n  image: string;\n  imageType: number;\n  isMovie: number;\n  seasons?: string[];\n  number: number;\n  absoluteNumber: number;\n  seasonNumber: number;\n  lastUpdated: string;\n  finaleType?: string;\n  year: string;\n}\n\nexport interface TvdbSeasonDetails {\n  id: number;\n  seriesId: number;\n  type: TvdbType;\n  number: number;\n  nameTranslations: string[];\n  overviewTranslations: string[];\n  image: string;\n  imageType: number;\n  companies: {\n    studio: TvdbCompany[];\n    network: TvdbCompany[];\n    production: TvdbCompany[];\n    distributor: TvdbCompany[];\n    special_effects: TvdbCompany[];\n  };\n  lastUpdated: string;\n  year: string;\n  episodes: TvdbEpisode[];\n  trailers: string[];\n  artwork: TvdbArtwork[];\n  tagOptions?: string[];\n  firstAired: string;\n}\n\nexport interface TvdbEpisodeTranslation {\n  name: string;\n  overview: string;\n  language: string;\n}\n\nconst TMDB_TO_TVDB_MAPPING: Record<string, string> & {\n  [key in AvailableLocale]: string;\n} = {\n  ar: 'ara', // Arabic\n  bg: 'bul', // Bulgarian\n  ca: 'cat', // Catalan\n  cs: 'ces', // Czech\n  da: 'dan', // Danish\n  de: 'deu', // German\n  el: 'ell', // Greek\n  en: 'eng', // English\n  es: 'spa', // Spanish\n  fi: 'fin', // Finnish\n  fr: 'fra', // French\n  he: 'heb', // Hebrew\n  hi: 'hin', // Hindi\n  hr: 'hrv', // Croatian\n  hu: 'hun', // Hungarian\n  it: 'ita', // Italian\n  ja: 'jpn', // Japanese\n  ko: 'kor', // Korean\n  lb: 'ltz', // Luxembourgish\n  lt: 'lit', // Lithuanian\n  nl: 'nld', // Dutch\n  pl: 'pol', // Polish\n  ro: 'ron', // Romanian\n  ru: 'rus', // Russian\n  sq: 'sqi', // Albanian\n  sr: 'srp', // Serbian\n  sv: 'swe', // Swedish\n  tr: 'tur', // Turkish\n  uk: 'ukr', // Ukrainian\n  vi: 'vie', // Vietnamese\n\n  'es-MX': 'spa', // Spanish (Latin America) -> Spanish\n  'nb-NO': 'nor', // Norwegian Bokmål -> Norwegian\n  'pt-BR': 'pt', // Portuguese (Brazil) -> Portuguese - Brazil (from TVDB data)\n  'pt-PT': 'por', // Portuguese (Portugal) -> Portuguese - Portugal (from TVDB data)\n  'zh-CN': 'zho', // Chinese (Simplified) -> Chinese - China\n  'zh-TW': 'zhtw', // Chinese (Traditional) -> Chinese - Taiwan\n};\n\nexport function convertTMDBToTVDB(tmdbCode: string): string | null {\n  const normalizedCode = tmdbCode.toLowerCase();\n\n  return (\n    TMDB_TO_TVDB_MAPPING[tmdbCode] ||\n    TMDB_TO_TVDB_MAPPING[normalizedCode] ||\n    null\n  );\n}\n\nexport function convertTmdbLanguageToTvdbWithFallback(\n  tmdbCode: string,\n  fallback: string\n): string {\n  // First try exact match\n  const tvdbCode = convertTMDBToTVDB(tmdbCode);\n  if (tvdbCode) return tvdbCode;\n\n  return tvdbCode || fallback || 'eng'; // Default to English if no match found\n}\n"
  },
  {
    "path": "server/constants/discover.ts",
    "content": "import type DiscoverSlider from '@server/entity/DiscoverSlider';\n\nexport enum DiscoverSliderType {\n  RECENTLY_ADDED = 1,\n  RECENT_REQUESTS,\n  PLEX_WATCHLIST,\n  TRENDING,\n  POPULAR_MOVIES,\n  MOVIE_GENRES,\n  UPCOMING_MOVIES,\n  STUDIOS,\n  POPULAR_TV,\n  TV_GENRES,\n  UPCOMING_TV,\n  NETWORKS,\n  TMDB_MOVIE_KEYWORD,\n  TMDB_MOVIE_GENRE,\n  TMDB_TV_KEYWORD,\n  TMDB_TV_GENRE,\n  TMDB_SEARCH,\n  TMDB_STUDIO,\n  TMDB_NETWORK,\n  TMDB_MOVIE_STREAMING_SERVICES,\n  TMDB_TV_STREAMING_SERVICES,\n}\n\nexport const defaultSliders: Partial<DiscoverSlider>[] = [\n  {\n    type: DiscoverSliderType.RECENTLY_ADDED,\n    enabled: true,\n    isBuiltIn: true,\n    order: 0,\n  },\n  {\n    type: DiscoverSliderType.RECENT_REQUESTS,\n    enabled: true,\n    isBuiltIn: true,\n    order: 1,\n  },\n  {\n    type: DiscoverSliderType.PLEX_WATCHLIST,\n    enabled: true,\n    isBuiltIn: true,\n    order: 2,\n  },\n  {\n    type: DiscoverSliderType.TRENDING,\n    enabled: true,\n    isBuiltIn: true,\n    order: 3,\n  },\n  {\n    type: DiscoverSliderType.POPULAR_MOVIES,\n    enabled: true,\n    isBuiltIn: true,\n    order: 4,\n  },\n  {\n    type: DiscoverSliderType.MOVIE_GENRES,\n    enabled: true,\n    isBuiltIn: true,\n    order: 5,\n  },\n  {\n    type: DiscoverSliderType.UPCOMING_MOVIES,\n    enabled: true,\n    isBuiltIn: true,\n    order: 6,\n  },\n  {\n    type: DiscoverSliderType.STUDIOS,\n    enabled: true,\n    isBuiltIn: true,\n    order: 7,\n  },\n  {\n    type: DiscoverSliderType.POPULAR_TV,\n    enabled: true,\n    isBuiltIn: true,\n    order: 8,\n  },\n  {\n    type: DiscoverSliderType.TV_GENRES,\n    enabled: true,\n    isBuiltIn: true,\n    order: 9,\n  },\n  {\n    type: DiscoverSliderType.UPCOMING_TV,\n    enabled: true,\n    isBuiltIn: true,\n    order: 10,\n  },\n  {\n    type: DiscoverSliderType.NETWORKS,\n    enabled: true,\n    isBuiltIn: true,\n    order: 11,\n  },\n];\n"
  },
  {
    "path": "server/constants/error.ts",
    "content": "export enum ApiErrorCode {\n  InvalidUrl = 'INVALID_URL',\n  InvalidCredentials = 'INVALID_CREDENTIALS',\n  InvalidAuthToken = 'INVALID_AUTH_TOKEN',\n  InvalidEmail = 'INVALID_EMAIL',\n  NotAdmin = 'NOT_ADMIN',\n  NoAdminUser = 'NO_ADMIN_USER',\n  SyncErrorGroupedFolders = 'SYNC_ERROR_GROUPED_FOLDERS',\n  SyncErrorNoLibraries = 'SYNC_ERROR_NO_LIBRARIES',\n  Unauthorized = 'UNAUTHORIZED',\n  Unknown = 'UNKNOWN',\n}\n"
  },
  {
    "path": "server/constants/issue.ts",
    "content": "export enum IssueType {\n  VIDEO = 1,\n  AUDIO = 2,\n  SUBTITLES = 3,\n  OTHER = 4,\n}\n\nexport enum IssueStatus {\n  OPEN = 1,\n  RESOLVED = 2,\n}\n\nexport const IssueTypeName = {\n  [IssueType.AUDIO]: 'Audio',\n  [IssueType.VIDEO]: 'Video',\n  [IssueType.SUBTITLES]: 'Subtitle',\n  [IssueType.OTHER]: 'Other',\n};\n"
  },
  {
    "path": "server/constants/media.ts",
    "content": "export enum MediaRequestStatus {\n  PENDING = 1,\n  APPROVED,\n  DECLINED,\n  FAILED,\n  COMPLETED,\n}\n\nexport enum MediaType {\n  MOVIE = 'movie',\n  TV = 'tv',\n}\n\nexport enum MediaStatus {\n  UNKNOWN = 1,\n  PENDING,\n  PROCESSING,\n  PARTIALLY_AVAILABLE,\n  AVAILABLE,\n  BLOCKLISTED,\n  DELETED,\n}\n"
  },
  {
    "path": "server/constants/server.ts",
    "content": "export enum MediaServerType {\n  PLEX = 1,\n  JELLYFIN,\n  EMBY,\n  NOT_CONFIGURED,\n}\n\nexport enum ServerType {\n  JELLYFIN = 'Jellyfin',\n  EMBY = 'Emby',\n}\n"
  },
  {
    "path": "server/constants/user.ts",
    "content": "export enum UserType {\n  PLEX = 1,\n  LOCAL = 2,\n  JELLYFIN = 3,\n  EMBY = 4,\n}\n"
  },
  {
    "path": "server/datasource.ts",
    "content": "import fs from 'fs';\nimport type { TlsOptions } from 'tls';\nimport type { DataSourceOptions, EntityTarget, Repository } from 'typeorm';\nimport { DataSource } from 'typeorm';\n\nconst DB_SSL_PREFIX = 'DB_SSL_';\n\nfunction boolFromEnv(envVar: string, defaultVal = false) {\n  if (process.env[envVar]) {\n    return process.env[envVar]?.toLowerCase() === 'true';\n  }\n  return defaultVal;\n}\n\nfunction stringOrReadFileFromEnv(envVar: string): Buffer | string | undefined {\n  if (process.env[envVar]) {\n    return process.env[envVar];\n  }\n  const filePath = process.env[`${envVar}_FILE`];\n  if (filePath) {\n    return fs.readFileSync(filePath);\n  }\n  return undefined;\n}\n\nfunction buildSslConfig(): TlsOptions | undefined {\n  if (process.env.DB_USE_SSL?.toLowerCase() !== 'true') {\n    return undefined;\n  }\n  return {\n    rejectUnauthorized: boolFromEnv(\n      `${DB_SSL_PREFIX}REJECT_UNAUTHORIZED`,\n      true\n    ),\n    ca: stringOrReadFileFromEnv(`${DB_SSL_PREFIX}CA`),\n    key: stringOrReadFileFromEnv(`${DB_SSL_PREFIX}KEY`),\n    cert: stringOrReadFileFromEnv(`${DB_SSL_PREFIX}CERT`),\n  };\n}\n\nconst testConfig: DataSourceOptions = {\n  type: 'sqlite',\n  database: ':memory:',\n  synchronize: true,\n  dropSchema: true,\n  logging: boolFromEnv('DB_LOG_QUERIES'),\n  entities: ['server/entity/**/*.ts'],\n  migrations: ['server/migration/sqlite/**/*.ts'],\n  subscribers: ['server/subscriber/**/*.ts'],\n};\n\nconst devConfig: DataSourceOptions = {\n  type: 'sqlite',\n  database: process.env.CONFIG_DIRECTORY\n    ? `${process.env.CONFIG_DIRECTORY}/db/db.sqlite3`\n    : 'config/db/db.sqlite3',\n  synchronize: true,\n  migrationsRun: false,\n  logging: boolFromEnv('DB_LOG_QUERIES'),\n  enableWAL: true,\n  entities: ['server/entity/**/*.ts'],\n  migrations: ['server/migration/sqlite/**/*.ts'],\n  subscribers: ['server/subscriber/**/*.ts'],\n};\n\nconst prodConfig: DataSourceOptions = {\n  type: 'sqlite',\n  database: process.env.CONFIG_DIRECTORY\n    ? `${process.env.CONFIG_DIRECTORY}/db/db.sqlite3`\n    : 'config/db/db.sqlite3',\n  synchronize: false,\n  migrationsRun: false,\n  logging: boolFromEnv('DB_LOG_QUERIES'),\n  enableWAL: true,\n  entities: ['dist/entity/**/*.js'],\n  migrations: ['dist/migration/sqlite/**/*.js'],\n  subscribers: ['dist/subscriber/**/*.js'],\n};\n\nconst postgresDevConfig: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_SOCKET_PATH || process.env.DB_HOST,\n  port: process.env.DB_SOCKET_PATH\n    ? undefined\n    : parseInt(process.env.DB_PORT ?? '5432'),\n  username: process.env.DB_USER,\n  password: process.env.DB_PASS,\n  database: process.env.DB_NAME ?? 'seerr',\n  ssl: buildSslConfig(),\n  synchronize: false,\n  migrationsRun: true,\n  logging: boolFromEnv('DB_LOG_QUERIES'),\n  entities: ['server/entity/**/*.ts'],\n  migrations: ['server/migration/postgres/**/*.ts'],\n  subscribers: ['server/subscriber/**/*.ts'],\n};\n\nconst postgresProdConfig: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_SOCKET_PATH || process.env.DB_HOST,\n  port: process.env.DB_SOCKET_PATH\n    ? undefined\n    : parseInt(process.env.DB_PORT ?? '5432'),\n  username: process.env.DB_USER,\n  password: process.env.DB_PASS,\n  database: process.env.DB_NAME ?? 'seerr',\n  ssl: buildSslConfig(),\n  synchronize: false,\n  migrationsRun: false,\n  logging: boolFromEnv('DB_LOG_QUERIES'),\n  entities: ['dist/entity/**/*.js'],\n  migrations: ['dist/migration/postgres/**/*.js'],\n  subscribers: ['dist/subscriber/**/*.js'],\n};\n\nexport const isPgsql = process.env.DB_TYPE === 'postgres';\n\nfunction getDataSource(): DataSourceOptions {\n  if (process.env.NODE_ENV === 'test') {\n    return testConfig;\n  } else if (process.env.NODE_ENV === 'production') {\n    return isPgsql ? postgresProdConfig : prodConfig;\n  } else {\n    return isPgsql ? postgresDevConfig : devConfig;\n  }\n}\n\nconst dataSource = new DataSource(getDataSource());\n\nexport const getRepository = <Entity extends object>(\n  target: EntityTarget<Entity>\n): Repository<Entity> => {\n  return dataSource.getRepository(target);\n};\n\nexport default dataSource;\n"
  },
  {
    "path": "server/entity/Blocklist.ts",
    "content": "import { MediaStatus, type MediaType } from '@server/constants/media';\nimport dataSource from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport { User } from '@server/entity/User';\nimport type { BlocklistItem } from '@server/interfaces/api/blocklistInterfaces';\nimport { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport type { EntityManager } from 'typeorm';\nimport {\n  Column,\n  Entity,\n  Index,\n  JoinColumn,\n  ManyToOne,\n  OneToOne,\n  PrimaryGeneratedColumn,\n  Unique,\n} from 'typeorm';\nimport type { ZodNumber, ZodOptional, ZodString } from 'zod';\n\n@Entity()\n@Unique(['tmdbId', 'mediaType'])\nexport class Blocklist implements BlocklistItem {\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @Column({ type: 'varchar' })\n  public mediaType: MediaType;\n\n  @Column({ nullable: true, type: 'varchar' })\n  title?: string;\n\n  @Column()\n  @Index()\n  public tmdbId: number;\n\n  @ManyToOne(() => User, (user) => user.id, {\n    eager: true,\n  })\n  @Index()\n  user?: User;\n\n  @OneToOne(() => Media, (media) => media.blocklist, {\n    onDelete: 'CASCADE',\n  })\n  @JoinColumn()\n  public media: Media;\n\n  @Column({ nullable: true, type: 'varchar' })\n  public blocklistedTags?: string;\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  constructor(init?: Partial<Blocklist>) {\n    Object.assign(this, init);\n  }\n\n  public static async addToBlocklist(\n    {\n      blocklistRequest,\n    }: {\n      blocklistRequest: {\n        mediaType: MediaType;\n        title?: ZodOptional<ZodString>['_output'];\n        tmdbId: ZodNumber['_output'];\n        blocklistedTags?: string;\n      };\n    },\n    entityManager?: EntityManager\n  ): Promise<void> {\n    const em = entityManager ?? dataSource;\n    const blocklist = new this({\n      ...blocklistRequest,\n    });\n\n    const mediaRepository = em.getRepository(Media);\n    let media = await mediaRepository.findOne({\n      where: {\n        tmdbId: blocklistRequest.tmdbId,\n        mediaType: blocklistRequest.mediaType,\n      },\n    });\n\n    const blocklistRepository = em.getRepository(this);\n\n    await blocklistRepository.save(blocklist);\n\n    if (!media) {\n      media = new Media({\n        tmdbId: blocklistRequest.tmdbId,\n        status: MediaStatus.BLOCKLISTED,\n        status4k: MediaStatus.BLOCKLISTED,\n        mediaType: blocklistRequest.mediaType,\n        blocklist: Promise.resolve(blocklist),\n      });\n\n      await mediaRepository.save(media);\n    } else {\n      media.blocklist = Promise.resolve(blocklist);\n      media.status = MediaStatus.BLOCKLISTED;\n      media.status4k = MediaStatus.BLOCKLISTED;\n\n      await mediaRepository.save(media);\n    }\n  }\n}\n"
  },
  {
    "path": "server/entity/DiscoverSlider.ts",
    "content": "import type { DiscoverSliderType } from '@server/constants/discover';\nimport { defaultSliders } from '@server/constants/discover';\nimport { getRepository } from '@server/datasource';\nimport logger from '@server/logger';\nimport { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity()\nclass DiscoverSlider {\n  public static async bootstrapSliders(): Promise<void> {\n    const sliderRepository = getRepository(DiscoverSlider);\n\n    for (const slider of defaultSliders) {\n      const existingSlider = await sliderRepository.findOne({\n        where: {\n          type: slider.type,\n        },\n      });\n\n      if (!existingSlider) {\n        logger.info('Creating built-in discovery slider', {\n          label: 'Discover Slider',\n          slider,\n        });\n        await sliderRepository.save(new DiscoverSlider(slider));\n      }\n    }\n  }\n\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @Column({ type: 'int' })\n  public type: DiscoverSliderType;\n\n  @Column({ type: 'int' })\n  public order: number;\n\n  @Column({ default: false })\n  public isBuiltIn: boolean;\n\n  @Column({ default: true })\n  public enabled: boolean;\n\n  @Column({ nullable: true })\n  // Title is not required for built in sliders because we will\n  // use translations for them.\n  public title?: string;\n\n  @Column({ nullable: true })\n  public data?: string;\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  constructor(init?: Partial<DiscoverSlider>) {\n    Object.assign(this, init);\n  }\n}\n\nexport default DiscoverSlider;\n"
  },
  {
    "path": "server/entity/Issue.ts",
    "content": "import type { IssueType } from '@server/constants/issue';\nimport { IssueStatus } from '@server/constants/issue';\nimport { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport {\n  AfterLoad,\n  Column,\n  Entity,\n  Index,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\nimport IssueComment from './IssueComment';\nimport Media from './Media';\nimport { User } from './User';\n\n@Entity()\nclass Issue {\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @Column({ type: 'int' })\n  @Index()\n  public issueType: IssueType;\n\n  @Column({ type: 'int', default: IssueStatus.OPEN })\n  public status: IssueStatus;\n\n  @Column({ type: 'int', default: 0 })\n  public problemSeason: number;\n\n  @Column({ type: 'int', default: 0 })\n  public problemEpisode: number;\n\n  @ManyToOne(() => Media, (media) => media.issues, {\n    eager: true,\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public media: Media;\n\n  @ManyToOne(() => User, (user) => user.createdIssues, {\n    eager: true,\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public createdBy: User;\n\n  @ManyToOne(() => User, {\n    eager: true,\n    onDelete: 'CASCADE',\n    nullable: true,\n  })\n  @Index()\n  public modifiedBy?: User;\n\n  @OneToMany(() => IssueComment, (comment) => comment.issue, {\n    cascade: true,\n    eager: true,\n  })\n  public comments: IssueComment[];\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  @AfterLoad()\n  sortComments() {\n    this.comments?.sort((a, b) => a.id - b.id);\n  }\n\n  constructor(init?: Partial<Issue>) {\n    Object.assign(this, init);\n  }\n}\n\nexport default Issue;\n"
  },
  {
    "path": "server/entity/IssueComment.ts",
    "content": "import { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport {\n  Column,\n  Entity,\n  Index,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\nimport Issue from './Issue';\nimport { User } from './User';\n\n@Entity()\nclass IssueComment {\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @ManyToOne(() => User, {\n    eager: true,\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public user: User;\n\n  @ManyToOne(() => Issue, (issue) => issue.comments, {\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public issue: Issue;\n\n  @Column({ type: 'text' })\n  public message: string;\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  constructor(init?: Partial<IssueComment>) {\n    Object.assign(this, init);\n  }\n}\n\nexport default IssueComment;\n"
  },
  {
    "path": "server/entity/Media.ts",
    "content": "import RadarrAPI from '@server/api/servarr/radarr';\nimport SonarrAPI from '@server/api/servarr/sonarr';\nimport { MediaStatus, MediaType } from '@server/constants/media';\nimport { MediaServerType } from '@server/constants/server';\nimport { getRepository } from '@server/datasource';\nimport { Blocklist } from '@server/entity/Blocklist';\nimport type { User } from '@server/entity/User';\nimport { Watchlist } from '@server/entity/Watchlist';\nimport type { DownloadingItem } from '@server/lib/downloadtracker';\nimport downloadTracker from '@server/lib/downloadtracker';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport { getHostname } from '@server/utils/getHostname';\nimport {\n  AfterLoad,\n  Column,\n  Entity,\n  Index,\n  OneToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\nimport Issue from './Issue';\nimport { MediaRequest } from './MediaRequest';\nimport Season from './Season';\n\n@Entity()\n@Index(['tmdbId', 'mediaType'])\nclass Media {\n  public static async getRelatedMedia(\n    user: User | undefined,\n    items: { tmdbId: number; mediaType: string }[]\n  ): Promise<Media[]> {\n    const mediaRepository = getRepository(Media);\n\n    try {\n      if (items.length === 0) {\n        return [];\n      }\n\n      const finalIds = [...new Set(items.map((i) => i.tmdbId))];\n\n      const media = await mediaRepository\n        .createQueryBuilder('media')\n        .leftJoinAndSelect(\n          'media.watchlists',\n          'watchlist',\n          'media.id= watchlist.media and watchlist.requestedBy = :userId',\n          { userId: user?.id }\n        ) //,\n        .where(' media.tmdbId in (:...finalIds)', { finalIds })\n        .getMany();\n\n      return media.filter((m) =>\n        items.some((i) => i.tmdbId === m.tmdbId && i.mediaType === m.mediaType)\n      );\n    } catch (e) {\n      logger.error(e.message);\n      return [];\n    }\n  }\n\n  public static async getMedia(\n    id: number,\n    mediaType: MediaType\n  ): Promise<Media | undefined> {\n    const mediaRepository = getRepository(Media);\n\n    try {\n      const media = await mediaRepository.findOne({\n        where: { tmdbId: id, mediaType: mediaType },\n        relations: { requests: true, issues: true },\n      });\n\n      return media ?? undefined;\n    } catch (e) {\n      logger.error(e.message);\n      return undefined;\n    }\n  }\n\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @Column({ type: 'varchar' })\n  public mediaType: MediaType;\n\n  @Column()\n  @Index()\n  public tmdbId: number;\n\n  @Column({ unique: true, nullable: true })\n  @Index()\n  public tvdbId?: number;\n\n  @Column({ nullable: true })\n  @Index()\n  public imdbId?: string;\n\n  @Column({ type: 'int', default: MediaStatus.UNKNOWN })\n  @Index()\n  public status: MediaStatus;\n\n  @Column({ type: 'int', default: MediaStatus.UNKNOWN })\n  @Index()\n  public status4k: MediaStatus;\n\n  @OneToMany(() => MediaRequest, (request) => request.media, {\n    cascade: ['insert', 'remove'],\n  })\n  public requests: MediaRequest[];\n\n  @OneToMany(() => Watchlist, (watchlist) => watchlist.media)\n  public watchlists: null | Watchlist[];\n\n  @OneToMany(() => Season, (season) => season.media, {\n    cascade: true,\n    eager: true,\n  })\n  public seasons: Season[];\n\n  @OneToMany(() => Issue, (issue) => issue.media, { cascade: true })\n  public issues: Issue[];\n\n  @OneToOne(() => Blocklist, (blocklist) => blocklist.media)\n  public blocklist: Promise<Blocklist>;\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  /**\n   * The `lastSeasonChange` column stores the date and time when the media was added to the library.\n   * It needs to be database-aware because SQLite supports `datetime` while PostgreSQL supports `timestamp with timezone (timestampz)`.\n   */\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public lastSeasonChange: Date;\n\n  /**\n   * The `mediaAddedAt` column stores the date and time when the media was added to the library.\n   * It needs to be database-aware because SQLite supports `datetime` while PostgreSQL supports `timestamp with timezone (timestampz)`.\n   * This column is nullable because it can be null when the media is not yet synced to the library.\n   */\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    nullable: true,\n  })\n  public mediaAddedAt: Date;\n\n  @Column({ nullable: true, type: 'int' })\n  public serviceId?: number | null;\n\n  @Column({ nullable: true, type: 'int' })\n  public serviceId4k?: number | null;\n\n  @Column({ nullable: true, type: 'int' })\n  public externalServiceId?: number | null;\n\n  @Column({ nullable: true, type: 'int' })\n  public externalServiceId4k?: number | null;\n\n  @Column({ nullable: true, type: 'varchar' })\n  public externalServiceSlug?: string | null;\n\n  @Column({ nullable: true, type: 'varchar' })\n  public externalServiceSlug4k?: string | null;\n\n  @Column({ nullable: true, type: 'varchar' })\n  public ratingKey?: string | null;\n\n  @Column({ nullable: true, type: 'varchar' })\n  public ratingKey4k?: string | null;\n\n  @Column({ nullable: true, type: 'varchar' })\n  public jellyfinMediaId?: string | null;\n\n  @Column({ nullable: true, type: 'varchar' })\n  public jellyfinMediaId4k?: string | null;\n\n  public serviceUrl?: string;\n  public serviceUrl4k?: string;\n  public downloadStatus?: DownloadingItem[] = [];\n  public downloadStatus4k?: DownloadingItem[] = [];\n\n  public mediaUrl?: string;\n  public mediaUrl4k?: string;\n\n  public iOSPlexUrl?: string;\n  public iOSPlexUrl4k?: string;\n\n  public tautulliUrl?: string;\n  public tautulliUrl4k?: string;\n\n  constructor(init?: Partial<Media>) {\n    Object.assign(this, init);\n  }\n\n  public resetServiceData(): void {\n    this.serviceId = null;\n    this.serviceId4k = null;\n    this.externalServiceId = null;\n    this.externalServiceId4k = null;\n    this.externalServiceSlug = null;\n    this.externalServiceSlug4k = null;\n    this.ratingKey = null;\n    this.ratingKey4k = null;\n    this.jellyfinMediaId = null;\n    this.jellyfinMediaId4k = null;\n  }\n\n  @AfterLoad()\n  public setPlexUrls(): void {\n    const { machineId, webAppUrl } = getSettings().plex;\n    const { externalUrl: tautulliUrl } = getSettings().tautulli;\n\n    if (getSettings().main.mediaServerType == MediaServerType.PLEX) {\n      if (this.ratingKey) {\n        this.mediaUrl = `${\n          webAppUrl ? webAppUrl : 'https://app.plex.tv/desktop'\n        }#!/server/${machineId}/details?key=%2Flibrary%2Fmetadata%2F${\n          this.ratingKey\n        }`;\n\n        this.iOSPlexUrl = `plex://preplay/?metadataKey=%2Flibrary%2Fmetadata%2F${this.ratingKey}&server=${machineId}`;\n\n        if (tautulliUrl) {\n          this.tautulliUrl = `${tautulliUrl}/info?rating_key=${this.ratingKey}`;\n        }\n      }\n\n      if (this.ratingKey4k) {\n        this.mediaUrl4k = `${\n          webAppUrl ? webAppUrl : 'https://app.plex.tv/desktop'\n        }#!/server/${machineId}/details?key=%2Flibrary%2Fmetadata%2F${\n          this.ratingKey4k\n        }`;\n\n        this.iOSPlexUrl4k = `plex://preplay/?metadataKey=%2Flibrary%2Fmetadata%2F${this.ratingKey4k}&server=${machineId}`;\n\n        if (tautulliUrl) {\n          this.tautulliUrl4k = `${tautulliUrl}/info?rating_key=${this.ratingKey4k}`;\n        }\n      }\n    } else {\n      const pageName =\n        getSettings().main.mediaServerType == MediaServerType.EMBY\n          ? 'item'\n          : 'details';\n      const { serverId, externalHostname } = getSettings().jellyfin;\n      const jellyfinHost =\n        externalHostname && externalHostname.length > 0\n          ? externalHostname\n          : getHostname();\n\n      if (this.jellyfinMediaId) {\n        this.mediaUrl = `${jellyfinHost}/web/index.html#!/${pageName}?id=${this.jellyfinMediaId}&context=home&serverId=${serverId}`;\n      }\n      if (this.jellyfinMediaId4k) {\n        this.mediaUrl4k = `${jellyfinHost}/web/index.html#!/${pageName}?id=${this.jellyfinMediaId4k}&context=home&serverId=${serverId}`;\n      }\n    }\n  }\n\n  @AfterLoad()\n  public setServiceUrl(): void {\n    if (this.mediaType === MediaType.MOVIE) {\n      if (this.serviceId !== null && this.externalServiceSlug !== null) {\n        const settings = getSettings();\n        const server = settings.radarr.find(\n          (radarr) => radarr.id === this.serviceId\n        );\n\n        if (server) {\n          this.serviceUrl = server.externalUrl\n            ? `${server.externalUrl}/movie/${this.externalServiceSlug}`\n            : RadarrAPI.buildUrl(server, `/movie/${this.externalServiceSlug}`);\n        }\n      }\n\n      if (this.serviceId4k !== null && this.externalServiceSlug4k !== null) {\n        const settings = getSettings();\n        const server = settings.radarr.find(\n          (radarr) => radarr.id === this.serviceId4k\n        );\n\n        if (server) {\n          this.serviceUrl4k = server.externalUrl\n            ? `${server.externalUrl}/movie/${this.externalServiceSlug4k}`\n            : RadarrAPI.buildUrl(\n                server,\n                `/movie/${this.externalServiceSlug4k}`\n              );\n        }\n      }\n    }\n\n    if (this.mediaType === MediaType.TV) {\n      if (this.serviceId !== null && this.externalServiceSlug !== null) {\n        const settings = getSettings();\n        const server = settings.sonarr.find(\n          (sonarr) => sonarr.id === this.serviceId\n        );\n\n        if (server) {\n          this.serviceUrl = server.externalUrl\n            ? `${server.externalUrl}/series/${this.externalServiceSlug}`\n            : SonarrAPI.buildUrl(server, `/series/${this.externalServiceSlug}`);\n        }\n      }\n\n      if (this.serviceId4k !== null && this.externalServiceSlug4k !== null) {\n        const settings = getSettings();\n        const server = settings.sonarr.find(\n          (sonarr) => sonarr.id === this.serviceId4k\n        );\n\n        if (server) {\n          this.serviceUrl4k = server.externalUrl\n            ? `${server.externalUrl}/series/${this.externalServiceSlug4k}`\n            : SonarrAPI.buildUrl(\n                server,\n                `/series/${this.externalServiceSlug4k}`\n              );\n        }\n      }\n    }\n  }\n\n  @AfterLoad()\n  public getDownloadingItem(): void {\n    if (this.mediaType === MediaType.MOVIE) {\n      if (\n        this.externalServiceId !== undefined &&\n        this.externalServiceId !== null &&\n        this.serviceId !== undefined &&\n        this.serviceId !== null\n      ) {\n        this.downloadStatus = downloadTracker.getMovieProgress(\n          this.serviceId,\n          this.externalServiceId\n        );\n      }\n\n      if (\n        this.externalServiceId4k !== undefined &&\n        this.externalServiceId4k !== null &&\n        this.serviceId4k !== undefined &&\n        this.serviceId4k !== null\n      ) {\n        this.downloadStatus4k = downloadTracker.getMovieProgress(\n          this.serviceId4k,\n          this.externalServiceId4k\n        );\n      }\n    }\n\n    if (this.mediaType === MediaType.TV) {\n      if (\n        this.externalServiceId !== undefined &&\n        this.externalServiceId !== null &&\n        this.serviceId !== undefined &&\n        this.serviceId !== null\n      ) {\n        this.downloadStatus = downloadTracker.getSeriesProgress(\n          this.serviceId,\n          this.externalServiceId\n        );\n      }\n\n      if (\n        this.externalServiceId4k !== undefined &&\n        this.externalServiceId4k !== null &&\n        this.serviceId4k !== undefined &&\n        this.serviceId4k !== null\n      ) {\n        this.downloadStatus4k = downloadTracker.getSeriesProgress(\n          this.serviceId4k,\n          this.externalServiceId4k\n        );\n      }\n    }\n  }\n}\n\nexport default Media;\n"
  },
  {
    "path": "server/entity/MediaRequest.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants';\nimport type { TmdbKeyword } from '@server/api/themoviedb/interfaces';\nimport {\n  MediaRequestStatus,\n  MediaStatus,\n  MediaType,\n} from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport OverrideRule from '@server/entity/OverrideRule';\nimport type { MediaRequestBody } from '@server/interfaces/api/requestInterfaces';\nimport notificationManager, { Notification } from '@server/lib/notifications';\nimport { Permission } from '@server/lib/permissions';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport { truncate } from 'lodash';\nimport {\n  AfterInsert,\n  AfterLoad,\n  AfterUpdate,\n  Column,\n  Entity,\n  Index,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n  RelationCount,\n} from 'typeorm';\nimport Media from './Media';\nimport SeasonRequest from './SeasonRequest';\nimport { User } from './User';\n\nexport class RequestPermissionError extends Error {}\nexport class QuotaRestrictedError extends Error {}\nexport class DuplicateMediaRequestError extends Error {}\nexport class NoSeasonsAvailableError extends Error {}\nexport class BlocklistedMediaError extends Error {}\n\ntype MediaRequestOptions = {\n  isAutoRequest?: boolean;\n};\n\n@Entity()\nexport class MediaRequest {\n  public static async request(\n    requestBody: MediaRequestBody,\n    user: User,\n    options: MediaRequestOptions = {}\n  ): Promise<MediaRequest> {\n    const tmdb = new TheMovieDb();\n    const mediaRepository = getRepository(Media);\n    const requestRepository = getRepository(MediaRequest);\n    const userRepository = getRepository(User);\n    const settings = getSettings();\n\n    let requestUser = user;\n\n    if (\n      requestBody.userId &&\n      !requestUser.hasPermission([\n        Permission.MANAGE_USERS,\n        Permission.MANAGE_REQUESTS,\n      ])\n    ) {\n      throw new RequestPermissionError(\n        'You do not have permission to modify the request user.'\n      );\n    } else if (requestBody.userId) {\n      requestUser = await userRepository.findOneOrFail({\n        where: { id: requestBody.userId },\n      });\n    }\n\n    if (!requestUser) {\n      throw new Error('User missing from request context.');\n    }\n\n    if (\n      requestBody.mediaType === MediaType.MOVIE &&\n      !requestUser.hasPermission(\n        requestBody.is4k\n          ? [Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE]\n          : [Permission.REQUEST, Permission.REQUEST_MOVIE],\n        {\n          type: 'or',\n        }\n      )\n    ) {\n      throw new RequestPermissionError(\n        `You do not have permission to make ${\n          requestBody.is4k ? '4K ' : ''\n        }movie requests.`\n      );\n    } else if (\n      requestBody.mediaType === MediaType.TV &&\n      !requestUser.hasPermission(\n        requestBody.is4k\n          ? [Permission.REQUEST_4K, Permission.REQUEST_4K_TV]\n          : [Permission.REQUEST, Permission.REQUEST_TV],\n        {\n          type: 'or',\n        }\n      )\n    ) {\n      throw new RequestPermissionError(\n        `You do not have permission to make ${\n          requestBody.is4k ? '4K ' : ''\n        }series requests.`\n      );\n    }\n\n    const quotas = await requestUser.getQuota();\n\n    if (requestBody.mediaType === MediaType.MOVIE && quotas.movie.restricted) {\n      throw new QuotaRestrictedError('Movie Quota exceeded.');\n    } else if (requestBody.mediaType === MediaType.TV && quotas.tv.restricted) {\n      throw new QuotaRestrictedError('Series Quota exceeded.');\n    }\n\n    const tmdbMedia =\n      requestBody.mediaType === MediaType.MOVIE\n        ? await tmdb.getMovie({ movieId: requestBody.mediaId })\n        : await tmdb.getTvShow({ tvId: requestBody.mediaId });\n\n    let media = await mediaRepository.findOne({\n      where: {\n        tmdbId: requestBody.mediaId,\n        mediaType: requestBody.mediaType,\n      },\n      relations: ['requests'],\n    });\n\n    if (!media) {\n      media = new Media({\n        tmdbId: tmdbMedia.id,\n        tvdbId: requestBody.tvdbId ?? tmdbMedia.external_ids.tvdb_id,\n        status: !requestBody.is4k ? MediaStatus.PENDING : MediaStatus.UNKNOWN,\n        status4k: requestBody.is4k ? MediaStatus.PENDING : MediaStatus.UNKNOWN,\n        mediaType: requestBody.mediaType,\n      });\n    } else {\n      if (media.status === MediaStatus.BLOCKLISTED) {\n        logger.warn('Request for media blocked due to being blocklisted', {\n          tmdbId: tmdbMedia.id,\n          mediaType: requestBody.mediaType,\n          label: 'Media Request',\n        });\n\n        throw new BlocklistedMediaError('This media is blocklisted.');\n      }\n\n      if (media.status === MediaStatus.UNKNOWN && !requestBody.is4k) {\n        media.status = MediaStatus.PENDING;\n      }\n\n      if (media.status4k === MediaStatus.UNKNOWN && requestBody.is4k) {\n        media.status4k = MediaStatus.PENDING;\n      }\n    }\n\n    const existing = await requestRepository\n      .createQueryBuilder('request')\n      .leftJoin('request.media', 'media')\n      .leftJoinAndSelect('request.requestedBy', 'user')\n      .where('request.is4k = :is4k', { is4k: requestBody.is4k })\n      .andWhere('media.tmdbId = :tmdbId', { tmdbId: tmdbMedia.id })\n      .andWhere('media.mediaType = :mediaType', {\n        mediaType: requestBody.mediaType,\n      })\n      .getMany();\n\n    if (existing && existing.length > 0) {\n      // If there is an existing movie request that isn't declined, don't allow a new one.\n      if (\n        requestBody.mediaType === MediaType.MOVIE &&\n        existing[0].status !== MediaRequestStatus.DECLINED &&\n        existing[0].status !== MediaRequestStatus.COMPLETED\n      ) {\n        logger.warn('Duplicate request for media blocked', {\n          tmdbId: tmdbMedia.id,\n          mediaType: requestBody.mediaType,\n          is4k: requestBody.is4k,\n          label: 'Media Request',\n        });\n\n        throw new DuplicateMediaRequestError(\n          'Request for this media already exists.'\n        );\n      }\n\n      // If an existing auto-request for this media exists from the same user,\n      // don't allow a new one.\n      if (\n        existing.find(\n          (r) => r.requestedBy.id === requestUser.id && r.isAutoRequest\n        )\n      ) {\n        throw new DuplicateMediaRequestError(\n          'Auto-request for this media and user already exists.'\n        );\n      }\n    }\n\n    // Apply overrides if the user is not an admin or has the \"advanced request\" permission\n    const useOverrides = !user.hasPermission([Permission.MANAGE_REQUESTS], {\n      type: 'or',\n    });\n\n    let rootFolder = requestBody.rootFolder;\n    let profileId = requestBody.profileId;\n    let tags = requestBody.tags;\n\n    if (useOverrides) {\n      const defaultRadarrId = requestBody.is4k\n        ? settings.radarr.findIndex((r) => r.is4k && r.isDefault)\n        : settings.radarr.findIndex((r) => !r.is4k && r.isDefault);\n      const defaultSonarrId = requestBody.is4k\n        ? settings.sonarr.findIndex((s) => s.is4k && s.isDefault)\n        : settings.sonarr.findIndex((s) => !s.is4k && s.isDefault);\n\n      const overrideRuleRepository = getRepository(OverrideRule);\n      const overrideRules = await overrideRuleRepository.find({\n        where:\n          requestBody.mediaType === MediaType.MOVIE\n            ? { radarrServiceId: defaultRadarrId }\n            : { sonarrServiceId: defaultSonarrId },\n      });\n\n      const appliedOverrideRules = overrideRules.filter((rule) => {\n        const hasAnimeKeyword =\n          'results' in tmdbMedia.keywords &&\n          tmdbMedia.keywords.results.some(\n            (keyword: TmdbKeyword) => keyword.id === ANIME_KEYWORD_ID\n          );\n\n        // Skip override rules if the media is an anime TV show as anime TV\n        // is handled by default and override rules do not explicitly include\n        // the anime keyword\n        if (\n          requestBody.mediaType === MediaType.TV &&\n          hasAnimeKeyword &&\n          (!rule.keywords ||\n            !rule.keywords.split(',').map(Number).includes(ANIME_KEYWORD_ID))\n        ) {\n          return false;\n        }\n\n        if (\n          rule.users &&\n          !rule.users\n            .split(',')\n            .some((userId) => Number(userId) === requestUser.id)\n        ) {\n          return false;\n        }\n        if (\n          rule.genre &&\n          !rule.genre\n            .split(',')\n            .some((genreId) =>\n              tmdbMedia.genres\n                .map((genre) => genre.id)\n                .includes(Number(genreId))\n            )\n        ) {\n          return false;\n        }\n        if (\n          rule.language &&\n          !rule.language\n            .split('|')\n            .some((languageId) => languageId === tmdbMedia.original_language)\n        ) {\n          return false;\n        }\n        if (\n          rule.keywords &&\n          !rule.keywords.split(',').some((keywordId) => {\n            let keywordList: TmdbKeyword[] = [];\n\n            if ('keywords' in tmdbMedia.keywords) {\n              keywordList = tmdbMedia.keywords.keywords;\n            } else if ('results' in tmdbMedia.keywords) {\n              keywordList = tmdbMedia.keywords.results;\n            }\n\n            return keywordList\n              .map((keyword: TmdbKeyword) => keyword.id)\n              .includes(Number(keywordId));\n          })\n        ) {\n          return false;\n        }\n        return true;\n      });\n\n      // hacky way to prioritize rules\n      // TODO: make this better\n      const prioritizedRule = appliedOverrideRules.sort((a, b) => {\n        const keys: (keyof OverrideRule)[] = ['genre', 'language', 'keywords'];\n\n        const aSpecificity = keys.filter((key) => a[key] !== null).length;\n        const bSpecificity = keys.filter((key) => b[key] !== null).length;\n\n        // Take the rule with the most specific condition first\n        return bSpecificity - aSpecificity;\n      })[0];\n\n      if (prioritizedRule) {\n        if (prioritizedRule.rootFolder) {\n          rootFolder = prioritizedRule.rootFolder;\n        }\n        if (prioritizedRule.profileId) {\n          profileId = prioritizedRule.profileId;\n        }\n        if (prioritizedRule.tags) {\n          tags = [\n            ...new Set([\n              ...(tags || []),\n              ...prioritizedRule.tags.split(',').map((tag) => Number(tag)),\n            ]),\n          ];\n        }\n\n        logger.debug('Override rule applied.', {\n          label: 'Media Request',\n          overrides: prioritizedRule,\n        });\n      }\n    }\n\n    if (requestBody.mediaType === MediaType.MOVIE) {\n      await mediaRepository.save(media);\n\n      const request = new MediaRequest({\n        type: MediaType.MOVIE,\n        media,\n        requestedBy: requestUser,\n        // If the user is an admin or has the \"auto approve\" permission, automatically approve the request\n        status: user.hasPermission(\n          [\n            requestBody.is4k\n              ? Permission.AUTO_APPROVE_4K\n              : Permission.AUTO_APPROVE,\n            requestBody.is4k\n              ? Permission.AUTO_APPROVE_4K_MOVIE\n              : Permission.AUTO_APPROVE_MOVIE,\n            Permission.MANAGE_REQUESTS,\n          ],\n          { type: 'or' }\n        )\n          ? MediaRequestStatus.APPROVED\n          : MediaRequestStatus.PENDING,\n        modifiedBy: user.hasPermission(\n          [\n            requestBody.is4k\n              ? Permission.AUTO_APPROVE_4K\n              : Permission.AUTO_APPROVE,\n            requestBody.is4k\n              ? Permission.AUTO_APPROVE_4K_MOVIE\n              : Permission.AUTO_APPROVE_MOVIE,\n            Permission.MANAGE_REQUESTS,\n          ],\n          { type: 'or' }\n        )\n          ? user\n          : undefined,\n        is4k: requestBody.is4k,\n        serverId: requestBody.serverId,\n        profileId: profileId,\n        rootFolder: rootFolder,\n        tags: tags,\n        isAutoRequest: options.isAutoRequest ?? false,\n      });\n\n      await requestRepository.save(request);\n      return request;\n    } else {\n      const tmdbMediaShow = tmdbMedia as Awaited<\n        ReturnType<typeof tmdb.getTvShow>\n      >;\n      let requestedSeasons =\n        requestBody.seasons === 'all'\n          ? tmdbMediaShow.seasons\n              .filter((season) => season.season_number !== 0)\n              .map((season) => season.season_number)\n          : (requestBody.seasons as number[]);\n      if (!settings.main.enableSpecialEpisodes) {\n        requestedSeasons = requestedSeasons.filter((sn) => sn > 0);\n      }\n\n      let existingSeasons: number[] = [];\n\n      // We need to check existing requests on this title to make sure we don't double up on seasons that were\n      // already requested. In the case they were, we just throw out any duplicates but still approve the request.\n      // (Unless there are no seasons, in which case we abort)\n      if (media.requests) {\n        existingSeasons = media.requests\n          .filter(\n            (request) =>\n              request.is4k === requestBody.is4k &&\n              request.status !== MediaRequestStatus.DECLINED &&\n              request.status !== MediaRequestStatus.COMPLETED\n          )\n          .reduce((seasons, request) => {\n            const combinedSeasons = request.seasons.map(\n              (season) => season.seasonNumber\n            );\n\n            return [...seasons, ...combinedSeasons];\n          }, [] as number[]);\n      }\n\n      // We should also check seasons that are available/partially available but don't have existing requests\n      if (media.seasons) {\n        existingSeasons = [\n          ...existingSeasons,\n          ...media.seasons\n            .filter(\n              (season) =>\n                season[requestBody.is4k ? 'status4k' : 'status'] !==\n                  MediaStatus.UNKNOWN &&\n                season[requestBody.is4k ? 'status4k' : 'status'] !==\n                  MediaStatus.DELETED\n            )\n            .map((season) => season.seasonNumber),\n        ];\n      }\n\n      const finalSeasons = requestedSeasons.filter(\n        (rs) => !existingSeasons.includes(rs)\n      );\n\n      if (finalSeasons.length === 0) {\n        throw new NoSeasonsAvailableError('No seasons available to request');\n      } else if (\n        quotas.tv.limit &&\n        finalSeasons.length > (quotas.tv.remaining ?? 0)\n      ) {\n        throw new QuotaRestrictedError('Series Quota exceeded.');\n      }\n\n      await mediaRepository.save(media);\n\n      const request = new MediaRequest({\n        type: MediaType.TV,\n        media,\n        requestedBy: requestUser,\n        // If the user is an admin or has the \"auto approve\" permission, automatically approve the request\n        status: user.hasPermission(\n          [\n            requestBody.is4k\n              ? Permission.AUTO_APPROVE_4K\n              : Permission.AUTO_APPROVE,\n            requestBody.is4k\n              ? Permission.AUTO_APPROVE_4K_TV\n              : Permission.AUTO_APPROVE_TV,\n            Permission.MANAGE_REQUESTS,\n          ],\n          { type: 'or' }\n        )\n          ? MediaRequestStatus.APPROVED\n          : MediaRequestStatus.PENDING,\n        modifiedBy: user.hasPermission(\n          [\n            requestBody.is4k\n              ? Permission.AUTO_APPROVE_4K\n              : Permission.AUTO_APPROVE,\n            requestBody.is4k\n              ? Permission.AUTO_APPROVE_4K_TV\n              : Permission.AUTO_APPROVE_TV,\n            Permission.MANAGE_REQUESTS,\n          ],\n          { type: 'or' }\n        )\n          ? user\n          : undefined,\n        is4k: requestBody.is4k,\n        serverId: requestBody.serverId,\n        profileId: profileId,\n        rootFolder: rootFolder,\n        languageProfileId: requestBody.languageProfileId,\n        tags: tags,\n        seasons: finalSeasons.map(\n          (sn) =>\n            new SeasonRequest({\n              seasonNumber: sn,\n              status: user.hasPermission(\n                [\n                  requestBody.is4k\n                    ? Permission.AUTO_APPROVE_4K\n                    : Permission.AUTO_APPROVE,\n                  requestBody.is4k\n                    ? Permission.AUTO_APPROVE_4K_TV\n                    : Permission.AUTO_APPROVE_TV,\n                  Permission.MANAGE_REQUESTS,\n                ],\n                { type: 'or' }\n              )\n                ? MediaRequestStatus.APPROVED\n                : MediaRequestStatus.PENDING,\n            })\n        ),\n        isAutoRequest: options.isAutoRequest ?? false,\n      });\n\n      await requestRepository.save(request);\n      return request;\n    }\n  }\n\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @Column({ type: 'integer' })\n  @Index()\n  public status: MediaRequestStatus;\n\n  @ManyToOne(() => Media, (media) => media.requests, {\n    eager: true,\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public media: Media;\n\n  @ManyToOne(() => User, (user) => user.requests, {\n    eager: true,\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public requestedBy: User;\n\n  @ManyToOne(() => User, {\n    nullable: true,\n    cascade: true,\n    eager: true,\n    onDelete: 'SET NULL',\n  })\n  @Index()\n  public modifiedBy?: User;\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  @Column({ type: 'varchar' })\n  public type: MediaType;\n\n  @RelationCount((request: MediaRequest) => request.seasons)\n  public seasonCount: number;\n\n  @OneToMany(() => SeasonRequest, (season) => season.request, {\n    eager: true,\n    cascade: true,\n  })\n  public seasons: SeasonRequest[];\n\n  @Column({ default: false })\n  public is4k: boolean;\n\n  @Column({ nullable: true })\n  public serverId: number;\n\n  @Column({ nullable: true })\n  public profileId: number;\n\n  @Column({ nullable: true })\n  public rootFolder: string;\n\n  @Column({ nullable: true })\n  public languageProfileId: number;\n\n  @Column({\n    type: 'text',\n    nullable: true,\n    transformer: {\n      from: (value: string | null): number[] | null => {\n        if (value) {\n          if (value === 'none') {\n            return [];\n          }\n          return value.split(',').map((v) => Number(v));\n        }\n        return null;\n      },\n      to: (value: number[] | null): string | null => {\n        if (value) {\n          const finalValue = value.join(',');\n\n          // We want to keep the actual state of an \"empty array\" so we use\n          // the keyword \"none\" to track this.\n          if (!finalValue) {\n            return 'none';\n          }\n\n          return finalValue;\n        }\n        return null;\n      },\n    },\n  })\n  public tags?: number[];\n\n  @Column({ default: false })\n  public isAutoRequest: boolean;\n\n  constructor(init?: Partial<MediaRequest>) {\n    Object.assign(this, init);\n  }\n\n  @AfterInsert()\n  public async notifyNewRequest(): Promise<void> {\n    if (this.status === MediaRequestStatus.PENDING) {\n      const mediaRepository = getRepository(Media);\n      const media = await mediaRepository.findOne({\n        where: { id: this.media.id },\n      });\n      if (!media) {\n        logger.error('Media data not found', {\n          label: 'Media Request',\n          requestId: this.id,\n          mediaId: this.media.id,\n        });\n        return;\n      }\n\n      MediaRequest.sendNotification(this, media, Notification.MEDIA_PENDING);\n\n      if (this.isAutoRequest) {\n        MediaRequest.sendNotification(\n          this,\n          media,\n          Notification.MEDIA_AUTO_REQUESTED\n        );\n      }\n    }\n  }\n\n  /**\n   * Notification for approval\n   *\n   * We only check on AfterUpdate as to not trigger this for\n   * auto approved content\n   */\n  @AfterUpdate()\n  public async notifyApprovedOrDeclined(autoApproved = false): Promise<void> {\n    if (\n      this.status === MediaRequestStatus.APPROVED ||\n      this.status === MediaRequestStatus.DECLINED\n    ) {\n      const mediaRepository = getRepository(Media);\n      const media = await mediaRepository.findOne({\n        where: { id: this.media.id },\n      });\n      if (!media) {\n        logger.error('Media data not found', {\n          label: 'Media Request',\n          requestId: this.id,\n          mediaId: this.media.id,\n        });\n        return;\n      }\n\n      if (media[this.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE) {\n        logger.warn(\n          'Media became available before request was approved. Skipping approval notification',\n          { label: 'Media Request', requestId: this.id, mediaId: this.media.id }\n        );\n        return;\n      }\n\n      MediaRequest.sendNotification(\n        this,\n        media,\n        this.status === MediaRequestStatus.APPROVED\n          ? autoApproved\n            ? Notification.MEDIA_AUTO_APPROVED\n            : Notification.MEDIA_APPROVED\n          : Notification.MEDIA_DECLINED\n      );\n\n      if (\n        this.status === MediaRequestStatus.APPROVED &&\n        autoApproved &&\n        this.isAutoRequest\n      ) {\n        MediaRequest.sendNotification(\n          this,\n          media,\n          Notification.MEDIA_AUTO_REQUESTED\n        );\n      }\n    }\n  }\n\n  @AfterInsert()\n  public async autoapprovalNotification(): Promise<void> {\n    if (this.status === MediaRequestStatus.APPROVED) {\n      this.notifyApprovedOrDeclined(true);\n    }\n  }\n\n  @AfterLoad()\n  private sortSeasons() {\n    if (Array.isArray(this.seasons)) {\n      this.seasons.sort((a, b) => a.id - b.id);\n    }\n  }\n\n  static async sendNotification(\n    entity: MediaRequest,\n    media: Media,\n    type: Notification\n  ) {\n    const tmdb = new TheMovieDb();\n\n    try {\n      const mediaType = entity.type === MediaType.MOVIE ? 'Movie' : 'Series';\n      let event: string | undefined;\n      let notifyAdmin = true;\n      let notifySystem = true;\n\n      switch (type) {\n        case Notification.MEDIA_APPROVED:\n          event = `${entity.is4k ? '4K ' : ''}${mediaType} Request Approved`;\n          notifyAdmin = false;\n          break;\n        case Notification.MEDIA_DECLINED:\n          event = `${entity.is4k ? '4K ' : ''}${mediaType} Request Declined`;\n          notifyAdmin = false;\n          break;\n        case Notification.MEDIA_PENDING:\n          event = `New ${entity.is4k ? '4K ' : ''}${mediaType} Request`;\n          break;\n        case Notification.MEDIA_AUTO_REQUESTED:\n          event = `${\n            entity.is4k ? '4K ' : ''\n          }${mediaType} Request Automatically Submitted`;\n          notifyAdmin = false;\n          notifySystem = false;\n          break;\n        case Notification.MEDIA_AUTO_APPROVED:\n          event = `${\n            entity.is4k ? '4K ' : ''\n          }${mediaType} Request Automatically Approved`;\n          break;\n        case Notification.MEDIA_FAILED:\n          event = `${entity.is4k ? '4K ' : ''}${mediaType} Request Failed`;\n          break;\n      }\n\n      if (entity.type === MediaType.MOVIE) {\n        const movie = await tmdb.getMovie({ movieId: media.tmdbId });\n        notificationManager.sendNotification(type, {\n          media,\n          request: entity,\n          notifyAdmin,\n          notifySystem,\n          notifyUser: notifyAdmin ? undefined : entity.requestedBy,\n          event,\n          subject: `${movie.title}${\n            movie.release_date ? ` (${movie.release_date.slice(0, 4)})` : ''\n          }`,\n          message: truncate(movie.overview, {\n            length: 500,\n            separator: /\\s/,\n            omission: '…',\n          }),\n          image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${movie.poster_path}`,\n        });\n      } else if (entity.type === MediaType.TV) {\n        const tv = await tmdb.getTvShow({ tvId: media.tmdbId });\n        notificationManager.sendNotification(type, {\n          media,\n          request: entity,\n          notifyAdmin,\n          notifySystem,\n          notifyUser: notifyAdmin ? undefined : entity.requestedBy,\n          event,\n          subject: `${tv.name}${\n            tv.first_air_date ? ` (${tv.first_air_date.slice(0, 4)})` : ''\n          }`,\n          message: truncate(tv.overview, {\n            length: 500,\n            separator: /\\s/,\n            omission: '…',\n          }),\n          image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tv.poster_path}`,\n          extra: [\n            {\n              name: 'Requested Seasons',\n              value: entity.seasons\n                .map((season) => season.seasonNumber)\n                .join(', '),\n            },\n          ],\n        });\n      }\n    } catch (e) {\n      logger.error('Something went wrong sending media notification(s)', {\n        label: 'Notifications',\n        errorMessage: e.message,\n        requestId: entity.id,\n        mediaId: entity.media.id,\n      });\n    }\n  }\n}\n\nexport default MediaRequest;\n"
  },
  {
    "path": "server/entity/OverrideRule.ts",
    "content": "import { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity()\nclass OverrideRule {\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @Column({ type: 'int', nullable: true })\n  public radarrServiceId?: number;\n\n  @Column({ type: 'int', nullable: true })\n  public sonarrServiceId?: number;\n\n  @Column({ nullable: true })\n  public users?: string;\n\n  @Column({ nullable: true })\n  public genre?: string;\n\n  @Column({ nullable: true })\n  public language?: string;\n\n  @Column({ nullable: true })\n  public keywords?: string;\n\n  @Column({ type: 'int', nullable: true })\n  public profileId?: number;\n\n  @Column({ nullable: true })\n  public rootFolder?: string;\n\n  @Column({ nullable: true })\n  public tags?: string;\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  constructor(init?: Partial<OverrideRule>) {\n    Object.assign(this, init);\n  }\n}\n\nexport default OverrideRule;\n"
  },
  {
    "path": "server/entity/Season.ts",
    "content": "import { MediaStatus } from '@server/constants/media';\nimport { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport {\n  Column,\n  Entity,\n  Index,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\nimport Media from './Media';\n\n@Entity()\nclass Season {\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @Column()\n  public seasonNumber: number;\n\n  @Column({ type: 'int', default: MediaStatus.UNKNOWN })\n  public status: MediaStatus;\n\n  @Column({ type: 'int', default: MediaStatus.UNKNOWN })\n  public status4k: MediaStatus;\n\n  @ManyToOne(() => Media, (media) => media.seasons, {\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public media: Promise<Media>;\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  constructor(init?: Partial<Season>) {\n    Object.assign(this, init);\n  }\n}\n\nexport default Season;\n"
  },
  {
    "path": "server/entity/SeasonRequest.ts",
    "content": "import { MediaRequestStatus } from '@server/constants/media';\nimport { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport {\n  Column,\n  Entity,\n  Index,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\nimport { MediaRequest } from './MediaRequest';\n\n@Entity()\nclass SeasonRequest {\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @Column()\n  public seasonNumber: number;\n\n  @Column({ type: 'int', default: MediaRequestStatus.PENDING })\n  public status: MediaRequestStatus;\n\n  @ManyToOne(() => MediaRequest, (request) => request.seasons, {\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public request: MediaRequest;\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  constructor(init?: Partial<SeasonRequest>) {\n    Object.assign(this, init);\n  }\n}\n\nexport default SeasonRequest;\n"
  },
  {
    "path": "server/entity/Session.ts",
    "content": "import type { ISession } from 'connect-typeorm';\nimport { Column, Entity, Index, PrimaryColumn } from 'typeorm';\n\n@Entity()\nexport class Session implements ISession {\n  @Index()\n  @Column('bigint')\n  public expiredAt = Date.now();\n\n  @PrimaryColumn('varchar', { length: 255 })\n  public id = '';\n\n  @Column('text')\n  public json = '';\n}\n"
  },
  {
    "path": "server/entity/User.ts",
    "content": "import { MediaRequestStatus, MediaType } from '@server/constants/media';\nimport { UserType } from '@server/constants/user';\nimport { getRepository } from '@server/datasource';\nimport { Watchlist } from '@server/entity/Watchlist';\nimport type { QuotaResponse } from '@server/interfaces/api/userInterfaces';\nimport PreparedEmail from '@server/lib/email';\nimport type { PermissionCheckOptions } from '@server/lib/permissions';\nimport { Permission, hasPermission } from '@server/lib/permissions';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport { AfterDate } from '@server/utils/dateHelpers';\nimport bcrypt from 'bcrypt';\nimport { randomUUID } from 'crypto';\nimport path from 'path';\nimport { default as generatePassword } from 'secure-random-password';\nimport {\n  AfterLoad,\n  Column,\n  Entity,\n  Not,\n  OneToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n  RelationCount,\n} from 'typeorm';\nimport Issue from './Issue';\nimport { MediaRequest } from './MediaRequest';\nimport SeasonRequest from './SeasonRequest';\nimport { UserPushSubscription } from './UserPushSubscription';\nimport { UserSettings } from './UserSettings';\n\n@Entity()\nexport class User {\n  public static filterMany(\n    users: User[],\n    showFiltered?: boolean\n  ): Partial<User>[] {\n    return users.map((u) => u.filter(showFiltered));\n  }\n\n  static readonly filteredFields: string[] = [\n    'email',\n    'plexId',\n    'password',\n    'resetPasswordGuid',\n    'jellyfinDeviceId',\n    'jellyfinAuthToken',\n    'plexToken',\n    'settings',\n  ];\n\n  public displayName: string;\n\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @Column({\n    unique: true,\n    transformer: {\n      from: (value: string): string => (value ?? '').toLowerCase(),\n      to: (value: string): string => (value ?? '').toLowerCase(),\n    },\n  })\n  public email: string;\n\n  @Column({ type: 'varchar', nullable: true })\n  public plexUsername?: string | null;\n\n  @Column({ type: 'varchar', nullable: true })\n  public jellyfinUsername?: string | null;\n\n  @Column({ nullable: true })\n  public username?: string;\n\n  @Column({ nullable: true, select: false })\n  public password?: string;\n\n  @Column({ nullable: true, select: false })\n  public resetPasswordGuid?: string;\n\n  @DbAwareColumn({ type: 'datetime', nullable: true })\n  public recoveryLinkExpirationDate?: Date | null;\n\n  @Column({ type: 'integer', default: UserType.PLEX })\n  public userType: UserType;\n\n  @Column({ type: 'integer', nullable: true, select: true })\n  public plexId?: number | null;\n\n  @Column({ type: 'varchar', nullable: true })\n  public jellyfinUserId?: string | null;\n\n  @Column({ type: 'varchar', nullable: true, select: false })\n  public jellyfinDeviceId?: string | null;\n\n  @Column({ type: 'varchar', nullable: true, select: false })\n  public jellyfinAuthToken?: string | null;\n\n  @Column({ type: 'varchar', nullable: true, select: false })\n  public plexToken?: string | null;\n\n  @Column({ type: 'integer', default: 0 })\n  public permissions = 0;\n\n  @Column()\n  public avatar: string;\n\n  @Column({ type: 'varchar', nullable: true })\n  public avatarETag?: string | null;\n\n  @Column({ type: 'varchar', nullable: true })\n  public avatarVersion?: string | null;\n\n  @RelationCount((user: User) => user.requests)\n  public requestCount: number;\n\n  @OneToMany(() => MediaRequest, (request) => request.requestedBy)\n  public requests: MediaRequest[];\n\n  @OneToMany(() => Watchlist, (watchlist) => watchlist.requestedBy)\n  public watchlists: Watchlist[];\n\n  @Column({ nullable: true })\n  public movieQuotaLimit?: number;\n\n  @Column({ nullable: true })\n  public movieQuotaDays?: number;\n\n  @Column({ nullable: true })\n  public tvQuotaLimit?: number;\n\n  @Column({ nullable: true })\n  public tvQuotaDays?: number;\n\n  @OneToOne(() => UserSettings, (settings) => settings.user, {\n    cascade: true,\n    eager: true,\n    onDelete: 'CASCADE',\n  })\n  public settings?: UserSettings;\n\n  @OneToMany(() => UserPushSubscription, (pushSub) => pushSub.user)\n  public pushSubscriptions: UserPushSubscription[];\n\n  @OneToMany(() => Issue, (issue) => issue.createdBy, { cascade: true })\n  public createdIssues: Issue[];\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  public warnings: string[] = [];\n\n  constructor(init?: Partial<User>) {\n    Object.assign(this, init);\n  }\n\n  public filter(showFiltered?: boolean): Partial<User> {\n    const filtered: Partial<User> = Object.assign(\n      {},\n      ...(Object.keys(this) as (keyof User)[])\n        .filter((k) => showFiltered || !User.filteredFields.includes(k))\n        .map((k) => ({ [k]: this[k] }))\n    );\n\n    return filtered;\n  }\n\n  public hasPermission(\n    permissions: Permission | Permission[],\n    options?: PermissionCheckOptions\n  ): boolean {\n    return !!hasPermission(permissions, this.permissions, options);\n  }\n\n  public passwordMatch(password: string): Promise<boolean> {\n    return new Promise((resolve) => {\n      if (this.password) {\n        resolve(bcrypt.compare(password, this.password));\n      } else {\n        return resolve(false);\n      }\n    });\n  }\n\n  public async setPassword(password: string): Promise<void> {\n    const hashedPassword = await bcrypt.hash(password, 12);\n    this.password = hashedPassword;\n  }\n\n  public async generatePassword(): Promise<void> {\n    const password = generatePassword.randomPassword({ length: 16 });\n    this.setPassword(password);\n\n    const { applicationTitle, applicationUrl } = getSettings().main;\n    try {\n      logger.info(`Sending generated password email for ${this.email}`, {\n        label: 'User Management',\n      });\n\n      const email = new PreparedEmail(getSettings().notifications.agents.email);\n      await email.send({\n        template: path.join(__dirname, '../templates/email/generatedpassword'),\n        message: {\n          to: this.email,\n        },\n        locals: {\n          password: password,\n          applicationUrl,\n          applicationTitle,\n          recipientName: this.username,\n        },\n      });\n    } catch (e) {\n      logger.error('Failed to send out generated password email', {\n        label: 'User Management',\n        message: e.message,\n      });\n    }\n  }\n\n  public async resetPassword(): Promise<void> {\n    const guid = randomUUID();\n    this.resetPasswordGuid = guid;\n\n    // 24 hours into the future\n    const targetDate = new Date();\n    targetDate.setDate(targetDate.getDate() + 1);\n    this.recoveryLinkExpirationDate = targetDate;\n\n    const { applicationTitle, applicationUrl } = getSettings().main;\n    const resetPasswordLink = `${applicationUrl}/resetpassword/${guid}`;\n\n    try {\n      logger.info(`Sending reset password email for ${this.email}`, {\n        label: 'User Management',\n      });\n      const email = new PreparedEmail(getSettings().notifications.agents.email);\n      await email.send({\n        template: path.join(__dirname, '../templates/email/resetpassword'),\n        message: {\n          to: this.email,\n        },\n        locals: {\n          resetPasswordLink,\n          applicationUrl,\n          applicationTitle,\n          recipientName: this.displayName,\n          recipientEmail: this.email,\n        },\n      });\n    } catch (e) {\n      logger.error('Failed to send out reset password email', {\n        label: 'User Management',\n        message: e.message,\n      });\n    }\n  }\n\n  @AfterLoad()\n  public setDisplayName(): void {\n    this.displayName =\n      this.username || this.plexUsername || this.jellyfinUsername || this.email;\n  }\n\n  public async getQuota(): Promise<QuotaResponse> {\n    const {\n      main: { defaultQuotas },\n    } = getSettings();\n    const requestRepository = getRepository(MediaRequest);\n    const canBypass = this.hasPermission([Permission.MANAGE_USERS], {\n      type: 'or',\n    });\n\n    const movieQuotaLimit = !canBypass\n      ? (this.movieQuotaLimit ?? defaultQuotas.movie.quotaLimit)\n      : 0;\n    const movieQuotaDays = this.movieQuotaDays ?? defaultQuotas.movie.quotaDays;\n\n    // Count movie requests made during quota period\n    const movieDate = new Date();\n    if (movieQuotaDays) {\n      movieDate.setDate(movieDate.getDate() - movieQuotaDays);\n    }\n\n    const movieQuotaUsed = movieQuotaLimit\n      ? await requestRepository.count({\n          where: {\n            requestedBy: {\n              id: this.id,\n            },\n            createdAt: AfterDate(movieDate),\n            type: MediaType.MOVIE,\n            status: Not(MediaRequestStatus.DECLINED),\n          },\n        })\n      : 0;\n\n    const tvQuotaLimit = !canBypass\n      ? (this.tvQuotaLimit ?? defaultQuotas.tv.quotaLimit)\n      : 0;\n    const tvQuotaDays = this.tvQuotaDays ?? defaultQuotas.tv.quotaDays;\n\n    // Count tv season requests made during quota period\n    const tvDate = new Date();\n    if (tvQuotaDays) {\n      tvDate.setDate(tvDate.getDate() - tvQuotaDays);\n    }\n    const tvQuotaStartDate = tvDate.toJSON();\n    const tvQuotaUsed = tvQuotaLimit\n      ? (\n          await requestRepository\n            .createQueryBuilder('request')\n            .leftJoin('request.seasons', 'seasons')\n            .leftJoin('request.requestedBy', 'requestedBy')\n            .where('request.type = :requestType', {\n              requestType: MediaType.TV,\n            })\n            .andWhere('requestedBy.id = :userId', {\n              userId: this.id,\n            })\n            .andWhere('request.createdAt > :date', {\n              date: tvQuotaStartDate,\n            })\n            .andWhere('request.status != :declinedStatus', {\n              declinedStatus: MediaRequestStatus.DECLINED,\n            })\n            .addSelect((subQuery) => {\n              return subQuery\n                .select('COUNT(season.id)', 'seasonCount')\n                .from(SeasonRequest, 'season')\n                .leftJoin('season.request', 'parentRequest')\n                .where('parentRequest.id = request.id');\n            }, 'seasonCount')\n            .getMany()\n        ).reduce((sum: number, req: MediaRequest) => sum + req.seasonCount, 0)\n      : 0;\n\n    return {\n      movie: {\n        days: movieQuotaDays,\n        limit: movieQuotaLimit,\n        used: movieQuotaUsed,\n        remaining: movieQuotaLimit\n          ? Math.max(0, movieQuotaLimit - movieQuotaUsed)\n          : undefined,\n        restricted:\n          movieQuotaLimit && movieQuotaLimit - movieQuotaUsed <= 0\n            ? true\n            : false,\n      },\n      tv: {\n        days: tvQuotaDays,\n        limit: tvQuotaLimit,\n        used: tvQuotaUsed,\n        remaining: tvQuotaLimit\n          ? Math.max(0, tvQuotaLimit - tvQuotaUsed)\n          : undefined,\n        restricted:\n          tvQuotaLimit && tvQuotaLimit - tvQuotaUsed <= 0 ? true : false,\n      },\n    };\n  }\n}\n"
  },
  {
    "path": "server/entity/UserPushSubscription.ts",
    "content": "import { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport {\n  Column,\n  Entity,\n  Index,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n  Unique,\n} from 'typeorm';\nimport { User } from './User';\n\n@Entity()\n@Unique(['endpoint', 'user'])\nexport class UserPushSubscription {\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @ManyToOne(() => User, (user) => user.pushSubscriptions, {\n    eager: true,\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public user: User;\n\n  @Column()\n  public endpoint: string;\n\n  @Column()\n  public p256dh: string;\n\n  @Column()\n  public auth: string;\n\n  @Column({ nullable: true })\n  public userAgent: string;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    nullable: true,\n  })\n  public createdAt: Date;\n\n  constructor(init?: Partial<UserPushSubscription>) {\n    Object.assign(this, init);\n  }\n}\n"
  },
  {
    "path": "server/entity/UserSettings.ts",
    "content": "import type { NotificationAgentTypes } from '@server/interfaces/api/userSettingsInterfaces';\nimport { hasNotificationType, Notification } from '@server/lib/notifications';\nimport { NotificationAgentKey } from '@server/lib/settings';\nimport {\n  Column,\n  Entity,\n  JoinColumn,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\nimport { User } from './User';\n\nexport const ALL_NOTIFICATIONS = Object.values(Notification)\n  .filter((v) => !isNaN(Number(v)))\n  .reduce((a, v) => a + Number(v), 0);\n\n@Entity()\nexport class UserSettings {\n  constructor(init?: Partial<UserSettings>) {\n    Object.assign(this, init);\n  }\n\n  @PrimaryGeneratedColumn()\n  public id: number;\n\n  @OneToOne(() => User, (user) => user.settings, { onDelete: 'CASCADE' })\n  @JoinColumn()\n  public user: User;\n\n  @Column({ default: '' })\n  public locale?: string;\n\n  @Column({ nullable: true })\n  public discoverRegion?: string;\n\n  @Column({ nullable: true })\n  public streamingRegion?: string;\n\n  @Column({ nullable: true })\n  public originalLanguage?: string;\n\n  @Column({ nullable: true })\n  public pgpKey?: string;\n\n  @Column({ nullable: true })\n  public discordId?: string;\n\n  @Column({ nullable: true })\n  public pushbulletAccessToken?: string;\n\n  @Column({ nullable: true })\n  public pushoverApplicationToken?: string;\n\n  @Column({ nullable: true })\n  public pushoverUserKey?: string;\n\n  @Column({ nullable: true })\n  public pushoverSound?: string;\n\n  @Column({ nullable: true })\n  public telegramChatId?: string;\n\n  @Column({ nullable: true })\n  public telegramMessageThreadId?: string;\n\n  @Column({ nullable: true })\n  public telegramSendSilently?: boolean;\n\n  @Column({ nullable: true })\n  public watchlistSyncMovies?: boolean;\n\n  @Column({ nullable: true })\n  public watchlistSyncTv?: boolean;\n\n  @Column({\n    type: 'text',\n    nullable: true,\n    transformer: {\n      from: (value: string | null): Partial<NotificationAgentTypes> => {\n        const defaultTypes = {\n          email: ALL_NOTIFICATIONS,\n          discord: 0,\n          pushbullet: 0,\n          pushover: 0,\n          slack: 0,\n          telegram: 0,\n          webhook: 0,\n          webpush: ALL_NOTIFICATIONS,\n        };\n        if (!value) {\n          return defaultTypes;\n        }\n\n        const values = JSON.parse(value) as Partial<NotificationAgentTypes>;\n\n        // Something with the migration to this field has caused some issue where\n        // the value pre-populates with just a raw \"2\"? Here we check if that's the case\n        // and return the default notification types if so\n        if (typeof values !== 'object') {\n          return defaultTypes;\n        }\n\n        if (values.email == null) {\n          values.email = ALL_NOTIFICATIONS;\n        }\n\n        if (values.webpush == null) {\n          values.webpush = ALL_NOTIFICATIONS;\n        }\n\n        return values;\n      },\n      to: (value: Partial<NotificationAgentTypes>): string | null => {\n        if (!value || typeof value !== 'object') {\n          return null;\n        }\n\n        const allowedKeys = Object.values(NotificationAgentKey);\n\n        // Remove any unknown notification agent keys before saving to db\n        (Object.keys(value) as (keyof NotificationAgentTypes)[]).forEach(\n          (key) => {\n            if (!allowedKeys.includes(key)) {\n              delete value[key];\n            }\n          }\n        );\n\n        return JSON.stringify(value);\n      },\n    },\n  })\n  public notificationTypes: Partial<NotificationAgentTypes>;\n\n  public hasNotificationType(\n    key: NotificationAgentKey,\n    type: Notification\n  ): boolean {\n    return hasNotificationType(type, this.notificationTypes[key] ?? 0);\n  }\n}\n"
  },
  {
    "path": "server/entity/Watchlist.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport { MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport { User } from '@server/entity/User';\nimport type { WatchlistItem } from '@server/interfaces/api/discoverInterfaces';\nimport logger from '@server/logger';\nimport { DbAwareColumn } from '@server/utils/DbColumnHelper';\nimport {\n  Column,\n  Entity,\n  Index,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n  Unique,\n} from 'typeorm';\nimport type { ZodNumber, ZodOptional, ZodString } from 'zod';\n\nexport class DuplicateWatchlistRequestError extends Error {}\nexport class NotFoundError extends Error {\n  constructor(message = 'Not found') {\n    super(message);\n    this.name = 'NotFoundError';\n  }\n}\n\n@Entity()\n@Unique('UNIQUE_USER_DB', ['tmdbId', 'mediaType', 'requestedBy'])\nexport class Watchlist implements WatchlistItem {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column({ type: 'varchar' })\n  public ratingKey = '';\n\n  @Column({ type: 'varchar' })\n  public mediaType: MediaType;\n\n  @Column({ type: 'varchar' })\n  title = '';\n\n  @Column()\n  @Index()\n  public tmdbId: number;\n\n  @ManyToOne(() => User, (user) => user.watchlists, {\n    eager: true,\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public requestedBy: User;\n\n  @ManyToOne(() => Media, (media) => media.watchlists, {\n    eager: true,\n    onDelete: 'CASCADE',\n  })\n  @Index()\n  public media: Media;\n\n  @DbAwareColumn({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n  public createdAt: Date;\n\n  @DbAwareColumn({\n    type: 'datetime',\n    default: () => 'CURRENT_TIMESTAMP',\n    onUpdate: 'CURRENT_TIMESTAMP',\n  })\n  public updatedAt: Date;\n\n  constructor(init?: Partial<Watchlist>) {\n    Object.assign(this, init);\n  }\n\n  public static async createWatchlist({\n    watchlistRequest,\n    user,\n  }: {\n    watchlistRequest: {\n      mediaType: MediaType;\n      ratingKey?: ZodOptional<ZodString>['_output'];\n      title?: ZodOptional<ZodString>['_output'];\n      tmdbId: ZodNumber['_output'];\n    };\n    user: User;\n  }): Promise<Watchlist> {\n    const watchlistRepository = getRepository(this);\n    const mediaRepository = getRepository(Media);\n    const tmdb = new TheMovieDb();\n\n    const tmdbMedia =\n      watchlistRequest.mediaType === MediaType.MOVIE\n        ? await tmdb.getMovie({ movieId: watchlistRequest.tmdbId })\n        : await tmdb.getTvShow({ tvId: watchlistRequest.tmdbId });\n\n    const existing = await watchlistRepository\n      .createQueryBuilder('watchlist')\n      .leftJoinAndSelect('watchlist.requestedBy', 'user')\n      .where('user.id = :userId', { userId: user.id })\n      .andWhere('watchlist.tmdbId = :tmdbId', {\n        tmdbId: watchlistRequest.tmdbId,\n      })\n      .andWhere('watchlist.mediaType = :mediaType', {\n        mediaType: watchlistRequest.mediaType,\n      })\n      .getMany();\n\n    if (existing && existing.length > 0) {\n      logger.warn('Duplicate request for watchlist blocked', {\n        tmdbId: watchlistRequest.tmdbId,\n        mediaType: watchlistRequest.mediaType,\n        label: 'Watchlist',\n      });\n\n      throw new DuplicateWatchlistRequestError();\n    }\n\n    let media = await mediaRepository.findOne({\n      where: {\n        tmdbId: watchlistRequest.tmdbId,\n        mediaType: watchlistRequest.mediaType,\n      },\n    });\n\n    if (!media) {\n      media = new Media({\n        tmdbId: tmdbMedia.id,\n        tvdbId: tmdbMedia.external_ids.tvdb_id,\n        mediaType: watchlistRequest.mediaType,\n      });\n    }\n\n    const watchlist = new this({\n      ...watchlistRequest,\n      requestedBy: user,\n      media,\n    });\n\n    await mediaRepository.save(media);\n    await watchlistRepository.save(watchlist);\n    return watchlist;\n  }\n\n  public static async deleteWatchlist(\n    tmdbId: Watchlist['tmdbId'],\n    mediaType: MediaType,\n    user: User\n  ): Promise<Watchlist | null> {\n    const watchlistRepository = getRepository(this);\n    const watchlist = await watchlistRepository.findOneBy({\n      tmdbId,\n      mediaType,\n      requestedBy: { id: user.id },\n    });\n    if (!watchlist) {\n      throw new NotFoundError('not Found');\n    }\n\n    if (watchlist) {\n      await watchlistRepository.delete(watchlist.id);\n    }\n\n    return watchlist;\n  }\n}\n"
  },
  {
    "path": "server/index.ts",
    "content": "import csurf from '@dr.pogodin/csurf';\nimport PlexAPI from '@server/api/plexapi';\nimport dataSource, { getRepository, isPgsql } from '@server/datasource';\nimport DiscoverSlider from '@server/entity/DiscoverSlider';\nimport { Session } from '@server/entity/Session';\nimport { User } from '@server/entity/User';\nimport { startJobs } from '@server/job/schedule';\nimport notificationManager from '@server/lib/notifications';\nimport DiscordAgent from '@server/lib/notifications/agents/discord';\nimport EmailAgent from '@server/lib/notifications/agents/email';\nimport GotifyAgent from '@server/lib/notifications/agents/gotify';\nimport NtfyAgent from '@server/lib/notifications/agents/ntfy';\nimport PushbulletAgent from '@server/lib/notifications/agents/pushbullet';\nimport PushoverAgent from '@server/lib/notifications/agents/pushover';\nimport SlackAgent from '@server/lib/notifications/agents/slack';\nimport TelegramAgent from '@server/lib/notifications/agents/telegram';\nimport WebhookAgent from '@server/lib/notifications/agents/webhook';\nimport WebPushAgent from '@server/lib/notifications/agents/webpush';\nimport checkOverseerrMerge from '@server/lib/overseerrMerge';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport clearCookies from '@server/middleware/clearcookies';\nimport routes from '@server/routes';\nimport avatarproxy from '@server/routes/avatarproxy';\nimport imageproxy from '@server/routes/imageproxy';\nimport { appDataPermissions } from '@server/utils/appDataVolume';\nimport { getAppVersion } from '@server/utils/appVersion';\nimport createCustomProxyAgent from '@server/utils/customProxyAgent';\nimport { initializeDnsCache } from '@server/utils/dnsCache';\nimport restartFlag from '@server/utils/restartFlag';\nimport { getClientIp } from '@supercharge/request-ip';\nimport axios from 'axios';\nimport { TypeormStore } from 'connect-typeorm/out';\nimport cookieParser from 'cookie-parser';\nimport type { NextFunction, Request, Response } from 'express';\nimport express from 'express';\nimport * as OpenApiValidator from 'express-openapi-validator';\nimport type { Store } from 'express-session';\nimport session from 'express-session';\nimport http from 'http';\nimport https from 'https';\nimport next from 'next';\nimport path from 'path';\nimport swaggerUi from 'swagger-ui-express';\nimport YAML from 'yamljs';\n\nconst API_SPEC_PATH = path.join(__dirname, '../seerr-api.yml');\n\nlogger.info(`Starting Seerr version ${getAppVersion()}`);\nconst dev = process.env.NODE_ENV !== 'production';\nconst app = next({ dev });\nconst handle = app.getRequestHandler();\n\nif (!appDataPermissions()) {\n  logger.error(\n    'Something went wrong while checking config folder! Please ensure the config folder is set up properly.\\nhttps://docs.seerr.dev/getting-started'\n  );\n}\n\napp\n  .prepare()\n  .then(async () => {\n    // Run Overseerr to Seerr migration\n    await checkOverseerrMerge();\n\n    const dbConnection = dataSource.isInitialized\n      ? dataSource\n      : await dataSource.initialize();\n\n    // Run migrations in production\n    if (process.env.NODE_ENV === 'production') {\n      if (isPgsql) {\n        await dbConnection.runMigrations();\n      } else {\n        await dbConnection.query('PRAGMA foreign_keys=OFF');\n        await dbConnection.runMigrations();\n        await dbConnection.query('PRAGMA foreign_keys=ON');\n      }\n    }\n\n    // Load Settings\n    const settings = await getSettings().load();\n    restartFlag.initializeSettings(settings);\n\n    if (settings.network.forceIpv4First) {\n      axios.defaults.httpAgent = new http.Agent({ family: 4 });\n      axios.defaults.httpsAgent = new https.Agent({ family: 4 });\n    }\n\n    // Add DNS caching\n    if (settings.network.dnsCache?.enabled) {\n      initializeDnsCache({\n        forceMinTtl: settings.network.dnsCache.forceMinTtl,\n        forceMaxTtl: settings.network.dnsCache.forceMaxTtl,\n      });\n    }\n\n    // Register HTTP proxy\n    if (settings.network.proxy.enabled) {\n      await createCustomProxyAgent(\n        settings.network.proxy,\n        settings.network.forceIpv4First\n      );\n    }\n\n    // Migrate library types\n    if (\n      settings.plex.libraries.length > 1 &&\n      !settings.plex.libraries[0].type\n    ) {\n      const userRepository = getRepository(User);\n      const admin = await userRepository.findOne({\n        select: { id: true, plexToken: true },\n        where: { id: 1 },\n      });\n\n      if (admin) {\n        logger.info('Migrating Plex libraries to include media type', {\n          label: 'Settings',\n        });\n\n        const plexapi = new PlexAPI({ plexToken: admin.plexToken });\n        await plexapi.syncLibraries();\n      }\n    }\n\n    // Register Notification Agents\n    notificationManager.registerAgents([\n      new DiscordAgent(),\n      new EmailAgent(),\n      new GotifyAgent(),\n      new NtfyAgent(),\n      new PushbulletAgent(),\n      new PushoverAgent(),\n      new SlackAgent(),\n      new TelegramAgent(),\n      new WebhookAgent(),\n      new WebPushAgent(),\n    ]);\n\n    const userRepository = getRepository(User);\n    const totalUsers = await userRepository.count();\n    if (totalUsers > 0) {\n      startJobs();\n    } else {\n      logger.info(\n        `Skipping starting the scheduled jobs as we have no Plex/Jellyfin/Emby servers setup yet`,\n        {\n          label: 'Server',\n        }\n      );\n    }\n\n    // Bootstrap Discovery Sliders\n    await DiscoverSlider.bootstrapSliders();\n\n    const server = express();\n    if (settings.network.trustProxy) {\n      server.enable('trust proxy');\n    }\n    server.use(cookieParser());\n    server.use(express.json());\n    server.use(express.urlencoded({ extended: true }));\n    server.use((req, _res, next) => {\n      try {\n        const descriptor = Object.getOwnPropertyDescriptor(req, 'ip');\n        if (descriptor?.writable === true) {\n          Object.defineProperty(req, 'ip', {\n            ...descriptor,\n            value: getClientIp(req) ?? '',\n          });\n        }\n      } catch (e) {\n        logger.error('Failed to attach the ip to the request', {\n          label: 'Middleware',\n          message: (e as Error).message,\n        });\n      } finally {\n        next();\n      }\n    });\n    if (settings.network.csrfProtection) {\n      server.use(\n        csurf({\n          cookie: {\n            httpOnly: true,\n            sameSite: true,\n            secure: !dev,\n          },\n        })\n      );\n      server.use((req, res, next) => {\n        res.cookie('XSRF-TOKEN', req.csrfToken(), {\n          sameSite: true,\n          secure: !dev,\n        });\n        next();\n      });\n    }\n\n    // Set up sessions\n    const sessionRespository = getRepository(Session);\n    server.use(\n      '/api',\n      session({\n        secret: settings.clientId,\n        resave: false,\n        saveUninitialized: false,\n        cookie: {\n          maxAge: 1000 * 60 * 60 * 24 * 30,\n          httpOnly: true,\n          sameSite: settings.network.csrfProtection ? 'strict' : 'lax',\n          secure: 'auto',\n        },\n        store: new TypeormStore({\n          cleanupLimit: 2,\n          ttl: 60 * 60 * 24 * 30,\n        }).connect(sessionRespository) as Store,\n      })\n    );\n    const apiDocs = YAML.load(API_SPEC_PATH);\n    server.use('/api-docs', swaggerUi.serve, swaggerUi.setup(apiDocs));\n    server.use(\n      OpenApiValidator.middleware({\n        apiSpec: API_SPEC_PATH,\n        validateRequests: true,\n      })\n    );\n    /**\n     * This is a workaround to convert dates to strings before they are validated by\n     * OpenAPI validator. Otherwise, they are treated as objects instead of strings\n     * and response validation will fail\n     */\n    server.use((_req, res, next) => {\n      const original = res.json;\n      res.json = function jsonp(json) {\n        return original.call(this, JSON.parse(JSON.stringify(json)));\n      };\n      next();\n    });\n    server.use('/api/v1', routes);\n\n    // Do not set cookies so CDNs can cache them\n    server.use('/imageproxy', clearCookies, imageproxy);\n    server.use('/avatarproxy', clearCookies, avatarproxy);\n\n    server.get('*', (req, res) => handle(req, res));\n    server.use(\n      (\n        err: { status: number; message: string; errors: string[] },\n        _req: Request,\n        res: Response,\n        // We must provide a next function for the function signature here even though its not used\n        // eslint-disable-next-line @typescript-eslint/no-unused-vars\n        _next: NextFunction\n      ) => {\n        // format error\n        res.status(err.status || 500).json({\n          message: err.message,\n          errors: err.errors,\n        });\n      }\n    );\n\n    const port = Number(process.env.PORT) || 5055;\n    const host = process.env.HOST;\n    if (host) {\n      server.listen(port, host, () => {\n        logger.info(`Server ready on ${host} port ${port}`, {\n          label: 'Server',\n        });\n      });\n    } else {\n      server.listen(port, () => {\n        logger.info(`Server ready on port ${port}`, {\n          label: 'Server',\n        });\n      });\n    }\n  })\n  .catch((err) => {\n    logger.error(err.stack);\n    process.exit(1);\n  });\n"
  },
  {
    "path": "server/interfaces/api/blocklistInterfaces.ts",
    "content": "import type { User } from '@server/entity/User';\nimport type { PaginatedResponse } from '@server/interfaces/api/common';\n\nexport interface BlocklistItem {\n  tmdbId: number;\n  mediaType: 'movie' | 'tv';\n  title?: string;\n  createdAt?: Date;\n  user?: User;\n  blocklistedTags?: string;\n}\n\nexport interface BlocklistResultsResponse extends PaginatedResponse {\n  results: BlocklistItem[];\n}\n"
  },
  {
    "path": "server/interfaces/api/common.ts",
    "content": "interface PageInfo {\n  pages: number;\n  page: number;\n  results: number;\n  pageSize: number;\n}\n\nexport interface PaginatedResponse {\n  pageInfo: PageInfo;\n}\n\n/**\n * Get the keys of an object that are not functions\n */\ntype NonFunctionPropertyNames<T> = {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n  [K in keyof T]: T[K] extends Function ? never : K;\n}[keyof T];\n\n/**\n * Get the properties of an object that are not functions\n */\nexport type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;\n"
  },
  {
    "path": "server/interfaces/api/discoverInterfaces.ts",
    "content": "export interface GenreSliderItem {\n  id: number;\n  name: string;\n  backdrops: string[];\n}\n\nexport interface WatchlistItem {\n  id: number;\n  ratingKey: string;\n  tmdbId: number;\n  mediaType: 'movie' | 'tv';\n  title: string;\n}\n\nexport interface WatchlistResponse {\n  page: number;\n  totalPages: number;\n  totalResults: number;\n  results: WatchlistItem[];\n}\n"
  },
  {
    "path": "server/interfaces/api/issueInterfaces.ts",
    "content": "import type Issue from '@server/entity/Issue';\nimport type { PaginatedResponse } from './common';\n\nexport interface IssueResultsResponse extends PaginatedResponse {\n  results: Issue[];\n}\n"
  },
  {
    "path": "server/interfaces/api/mediaInterfaces.ts",
    "content": "import type Media from '@server/entity/Media';\nimport type { User } from '@server/entity/User';\nimport type { PaginatedResponse } from './common';\n\nexport interface MediaResultsResponse extends PaginatedResponse {\n  results: Media[];\n}\n\nexport interface MediaWatchDataResponse {\n  data?: {\n    users: User[];\n    playCount: number;\n    playCount7Days: number;\n    playCount30Days: number;\n  };\n  data4k?: {\n    users: User[];\n    playCount: number;\n    playCount7Days: number;\n    playCount30Days: number;\n  };\n}\n"
  },
  {
    "path": "server/interfaces/api/overrideRuleInterfaces.ts",
    "content": "import type OverrideRule from '@server/entity/OverrideRule';\n\nexport type OverrideRuleResultsResponse = OverrideRule[];\n"
  },
  {
    "path": "server/interfaces/api/personInterfaces.ts",
    "content": "import type { PersonCreditCast, PersonCreditCrew } from '@server/models/Person';\n\nexport interface PersonCombinedCreditsResponse {\n  id: number;\n  cast: PersonCreditCast[];\n  crew: PersonCreditCrew[];\n}\n"
  },
  {
    "path": "server/interfaces/api/plexInterfaces.ts",
    "content": "import type { PlexSettings } from '@server/lib/settings';\n\nexport interface PlexStatus {\n  settings: PlexSettings;\n  status: number;\n  message: string;\n}\n\nexport interface PlexConnection {\n  protocol: string;\n  address: string;\n  port: number;\n  uri: string;\n  local: boolean;\n  status?: number;\n  message?: string;\n}\n\nexport interface PlexDevice {\n  name: string;\n  product: string;\n  productVersion: string;\n  platform: string;\n  platformVersion: string;\n  device: string;\n  clientIdentifier: string;\n  createdAt: Date;\n  lastSeenAt: Date;\n  provides: string[];\n  owned: boolean;\n  accessToken?: string;\n  publicAddress?: string;\n  httpsRequired?: boolean;\n  synced?: boolean;\n  relay?: boolean;\n  dnsRebindingProtection?: boolean;\n  natLoopbackSupported?: boolean;\n  publicAddressMatches?: boolean;\n  presence?: boolean;\n  ownerID?: string;\n  home?: boolean;\n  sourceTitle?: string;\n  connection: PlexConnection[];\n}\n"
  },
  {
    "path": "server/interfaces/api/requestInterfaces.ts",
    "content": "import type { MediaType } from '@server/constants/media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport type { NonFunctionProperties, PaginatedResponse } from './common';\n\nexport interface RequestResultsResponse extends PaginatedResponse {\n  results: (NonFunctionProperties<MediaRequest> & {\n    profileName?: string;\n    canRemove?: boolean;\n  })[];\n  serviceErrors: {\n    radarr: { id: number; name: string }[];\n    sonarr: { id: number; name: string }[];\n  };\n}\n\nexport type MediaRequestBody = {\n  mediaType: MediaType;\n  mediaId: number;\n  tvdbId?: number;\n  seasons?: number[] | 'all';\n  is4k?: boolean;\n  serverId?: number;\n  profileId?: number;\n  profileName?: string;\n  rootFolder?: string;\n  languageProfileId?: number;\n  userId?: number;\n  tags?: number[];\n};\n"
  },
  {
    "path": "server/interfaces/api/serviceInterfaces.ts",
    "content": "import type { QualityProfile, RootFolder, Tag } from '@server/api/servarr/base';\nimport type { LanguageProfile } from '@server/api/servarr/sonarr';\n\nexport interface ServiceCommonServer {\n  id: number;\n  name: string;\n  is4k: boolean;\n  isDefault: boolean;\n  activeProfileId: number;\n  activeDirectory: string;\n  activeLanguageProfileId?: number;\n  activeAnimeProfileId?: number;\n  activeAnimeDirectory?: string;\n  activeAnimeLanguageProfileId?: number;\n  activeTags: number[];\n  activeAnimeTags?: number[];\n}\n\nexport interface ServiceCommonServerWithDetails {\n  server: ServiceCommonServer;\n  profiles: QualityProfile[];\n  rootFolders: Partial<RootFolder>[];\n  languageProfiles?: LanguageProfile[];\n  tags: Tag[];\n}\n"
  },
  {
    "path": "server/interfaces/api/settingsInterfaces.ts",
    "content": "import type { DnsEntries, DnsStats } from 'dns-caching';\nimport type { PaginatedResponse } from './common';\n\nexport type LogMessage = {\n  timestamp: string;\n  level: string;\n  label?: string;\n  message: string;\n  data?: Record<string, unknown>;\n};\n\nexport interface LogsResultsResponse extends PaginatedResponse {\n  results: LogMessage[];\n}\n\nexport interface SettingsAboutResponse {\n  version: string;\n  totalRequests: number;\n  totalMediaItems: number;\n  tz?: string;\n  appDataPath: string;\n}\n\nexport interface PublicSettingsResponse {\n  jellyfinHost?: string;\n  jellyfinExternalHost?: string;\n  jellyfinServerName?: string;\n  jellyfinForgotPasswordUrl?: string;\n  initialized: boolean;\n  applicationTitle: string;\n  applicationUrl: string;\n  hideAvailable: boolean;\n  hideBlocklisted: boolean;\n  localLogin: boolean;\n  mediaServerLogin: boolean;\n  movie4kEnabled: boolean;\n  series4kEnabled: boolean;\n  discoverRegion: string;\n  streamingRegion: string;\n  originalLanguage: string;\n  mediaServerType: number;\n  partialRequestsEnabled: boolean;\n  enableSpecialEpisodes: boolean;\n  cacheImages: boolean;\n  vapidPublic: string;\n  enablePushRegistration: boolean;\n  locale: string;\n  emailEnabled: boolean;\n  newPlexLogin: boolean;\n  youtubeUrl: string;\n}\n\nexport interface CacheItem {\n  id: string;\n  name: string;\n  stats: {\n    hits: number;\n    misses: number;\n    keys: number;\n    ksize: number;\n    vsize: number;\n  };\n}\n\nexport interface CacheResponse {\n  apiCaches: CacheItem[];\n  imageCache: Record<'tmdb' | 'avatar', { size: number; imageCount: number }>;\n  dnsCache: {\n    stats: DnsStats | undefined;\n    entries: DnsEntries | undefined;\n  };\n}\n\nexport interface StatusResponse {\n  version: string;\n  commitTag: string;\n  updateAvailable: boolean;\n  commitsBehind: number;\n  restartRequired: boolean;\n}\n"
  },
  {
    "path": "server/interfaces/api/userInterfaces.ts",
    "content": "import type Media from '@server/entity/Media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport type { User } from '@server/entity/User';\nimport type { PaginatedResponse } from './common';\n\nexport interface UserResultsResponse extends PaginatedResponse {\n  results: User[];\n}\n\nexport interface UserRequestsResponse extends PaginatedResponse {\n  results: MediaRequest[];\n}\n\nexport interface QuotaStatus {\n  days?: number;\n  limit?: number;\n  used: number;\n  remaining?: number;\n  restricted: boolean;\n}\n\nexport interface QuotaResponse {\n  movie: QuotaStatus;\n  tv: QuotaStatus;\n}\n\nexport interface UserWatchDataResponse {\n  recentlyWatched: Media[];\n  playCount: number;\n}\n"
  },
  {
    "path": "server/interfaces/api/userSettingsInterfaces.ts",
    "content": "import type { NotificationAgentKey } from '@server/lib/settings';\n\nexport interface UserSettingsGeneralResponse {\n  username?: string;\n  email?: string;\n  discordId?: string;\n  locale?: string;\n  discoverRegion?: string;\n  streamingRegion?: string;\n  originalLanguage?: string;\n  movieQuotaLimit?: number;\n  movieQuotaDays?: number;\n  tvQuotaLimit?: number;\n  tvQuotaDays?: number;\n  globalMovieQuotaDays?: number;\n  globalMovieQuotaLimit?: number;\n  globalTvQuotaLimit?: number;\n  globalTvQuotaDays?: number;\n  watchlistSyncMovies?: boolean;\n  watchlistSyncTv?: boolean;\n}\n\nexport type NotificationAgentTypes = Record<NotificationAgentKey, number>;\nexport interface UserSettingsNotificationsResponse {\n  emailEnabled?: boolean;\n  pgpKey?: string;\n  discordEnabled?: boolean;\n  discordEnabledTypes?: number;\n  discordId?: string;\n  pushbulletAccessToken?: string;\n  pushoverApplicationToken?: string;\n  pushoverUserKey?: string;\n  pushoverSound?: string;\n  telegramEnabled?: boolean;\n  telegramBotUsername?: string;\n  telegramChatId?: string;\n  telegramMessageThreadId?: string;\n  telegramSendSilently?: boolean;\n  webPushEnabled?: boolean;\n  notificationTypes: Partial<NotificationAgentTypes>;\n}\n"
  },
  {
    "path": "server/interfaces/api/watchlistCreate.ts",
    "content": "import { MediaType } from '@server/constants/media';\nimport { z } from 'zod';\n\nexport const watchlistCreate = z.object({\n  ratingKey: z.coerce.string().optional(),\n  tmdbId: z.coerce.number(),\n  mediaType: z.nativeEnum(MediaType),\n  title: z.coerce.string().optional(),\n});\n"
  },
  {
    "path": "server/job/blocklistedTagsProcessor.ts",
    "content": "import type { SortOptions } from '@server/api/themoviedb';\nimport { SortOptionsIterable } from '@server/api/themoviedb';\nimport type {\n  TmdbSearchMovieResponse,\n  TmdbSearchTvResponse,\n} from '@server/api/themoviedb/interfaces';\nimport { MediaType } from '@server/constants/media';\nimport dataSource from '@server/datasource';\nimport { Blocklist } from '@server/entity/Blocklist';\nimport Media from '@server/entity/Media';\nimport type {\n  RunnableScanner,\n  StatusBase,\n} from '@server/lib/scanners/baseScanner';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { createTmdbWithRegionLanguage } from '@server/routes/discover';\nimport type { EntityManager } from 'typeorm';\n\nconst TMDB_API_DELAY_MS = 250;\nclass AbortTransaction extends Error {}\n\nclass BlocklistedTagProcessor implements RunnableScanner<StatusBase> {\n  private running = false;\n  private progress = 0;\n  private total = 0;\n\n  public async run() {\n    this.running = true;\n\n    try {\n      await dataSource.transaction(async (em) => {\n        await this.cleanBlocklist(em);\n        await this.createBlocklistEntries(em);\n      });\n    } catch (err) {\n      if (err instanceof AbortTransaction) {\n        logger.info('Aborting job: Process Blocklisted Tags', {\n          label: 'Jobs',\n        });\n      } else {\n        throw err;\n      }\n    } finally {\n      this.reset();\n    }\n  }\n\n  public status(): StatusBase {\n    return {\n      running: this.running,\n      progress: this.progress,\n      total: this.total,\n    };\n  }\n\n  public cancel() {\n    this.running = false;\n    this.progress = 0;\n    this.total = 0;\n  }\n\n  private reset() {\n    this.cancel();\n  }\n\n  private async createBlocklistEntries(em: EntityManager) {\n    const tmdb = createTmdbWithRegionLanguage();\n\n    const settings = getSettings();\n    const blocklistedTags = settings.main.blocklistedTags;\n    const blocklistedTagsArr = blocklistedTags.split(',');\n\n    const pageLimit = settings.main.blocklistedTagsLimit;\n    const invalidKeywords = new Set<string>();\n\n    if (blocklistedTags.length === 0) {\n      return;\n    }\n\n    // The maximum number of queries we're expected to execute\n    this.total =\n      2 * blocklistedTagsArr.length * pageLimit * SortOptionsIterable.length;\n\n    for (const type of [MediaType.MOVIE, MediaType.TV]) {\n      const getDiscover =\n        type === MediaType.MOVIE ? tmdb.getDiscoverMovies : tmdb.getDiscoverTv;\n\n      // Iterate for each tag\n      for (const tag of blocklistedTagsArr) {\n        const keywordDetails = await tmdb.getKeywordDetails({\n          keywordId: Number(tag),\n        });\n\n        if (keywordDetails === null) {\n          logger.warn('Skipping invalid keyword in blocklisted tags', {\n            label: 'Blocklisted Tags Processor',\n            keywordId: tag,\n          });\n          invalidKeywords.add(tag);\n          continue;\n        }\n\n        let queryMax = pageLimit * SortOptionsIterable.length;\n        let fixedSortMode = false; // Set to true when the page limit allows for getting every page of tag\n\n        for (let query = 0; query < queryMax; query++) {\n          const page: number = fixedSortMode\n            ? query + 1\n            : (query % pageLimit) + 1;\n          const sortBy: SortOptions | undefined = fixedSortMode\n            ? undefined\n            : SortOptionsIterable[query % SortOptionsIterable.length];\n\n          if (!this.running) {\n            throw new AbortTransaction();\n          }\n\n          try {\n            const response = await getDiscover({\n              page,\n              sortBy,\n              keywords: tag,\n            });\n\n            await this.processResults(response, tag, type, em);\n            await new Promise((res) => setTimeout(res, TMDB_API_DELAY_MS));\n\n            this.progress++;\n            if (page === 1 && response.total_pages <= queryMax) {\n              // We will finish the tag with less queries than expected, move progress accordingly\n              this.progress += queryMax - response.total_pages;\n              fixedSortMode = true;\n              queryMax = response.total_pages;\n            }\n          } catch (error) {\n            logger.error('Error processing keyword in blocklisted tags', {\n              label: 'Blocklisted Tags Processor',\n              keywordId: tag,\n              errorMessage: error.message,\n            });\n          }\n        }\n      }\n    }\n\n    if (invalidKeywords.size > 0) {\n      const currentTags = blocklistedTagsArr.filter(\n        (tag) => !invalidKeywords.has(tag)\n      );\n      const cleanedTags = currentTags.join(',');\n\n      if (cleanedTags !== blocklistedTags) {\n        settings.main.blocklistedTags = cleanedTags;\n        await settings.save();\n\n        logger.info('Cleaned up invalid keywords from settings', {\n          label: 'Blocklisted Tags Processor',\n          removedKeywords: Array.from(invalidKeywords),\n          newBlocklistedTags: cleanedTags,\n        });\n      }\n    }\n  }\n\n  private async processResults(\n    response: TmdbSearchMovieResponse | TmdbSearchTvResponse,\n    keywordId: string,\n    mediaType: MediaType,\n    em: EntityManager\n  ) {\n    const blocklistRepository = em.getRepository(Blocklist);\n\n    for (const entry of response.results) {\n      const blocklistEntry = await blocklistRepository.findOne({\n        where: { tmdbId: entry.id, mediaType },\n      });\n\n      if (blocklistEntry) {\n        // Don't mark manual blocklists with tags\n        // If media wasn't previously blocklisted for this tag, add the tag to the media's blocklist\n        if (\n          blocklistEntry.blocklistedTags &&\n          !blocklistEntry.blocklistedTags.includes(`,${keywordId},`)\n        ) {\n          await blocklistRepository.update(blocklistEntry.id, {\n            blocklistedTags: `${blocklistEntry.blocklistedTags}${keywordId},`,\n          });\n        }\n      } else {\n        // Media wasn't previously blocklisted, add it to the blocklist\n        await Blocklist.addToBlocklist(\n          {\n            blocklistRequest: {\n              mediaType,\n              title: 'title' in entry ? entry.title : entry.name,\n              tmdbId: entry.id,\n              blocklistedTags: `,${keywordId},`,\n            },\n          },\n          em\n        );\n      }\n    }\n  }\n\n  private async cleanBlocklist(em: EntityManager) {\n    // Remove blocklist and media entries blocklisted by tags\n    const mediaRepository = em.getRepository(Media);\n    const mediaToRemove = await mediaRepository\n      .createQueryBuilder('media')\n      .innerJoinAndSelect(\n        Blocklist,\n        'blist',\n        'blist.tmdbId = media.tmdbId AND blist.mediaType = media.mediaType'\n      )\n      .where(`blist.blocklistedTags IS NOT NULL`)\n      .getMany();\n\n    // Batch removes so the query doesn't get too large\n    for (let i = 0; i < mediaToRemove.length; i += 500) {\n      await mediaRepository.remove(mediaToRemove.slice(i, i + 500)); // This also deletes the blocklist entries via cascading\n    }\n  }\n}\n\nconst blocklistedTagsProcessor = new BlocklistedTagProcessor();\n\nexport default blocklistedTagsProcessor;\n"
  },
  {
    "path": "server/job/schedule.ts",
    "content": "import { MediaServerType } from '@server/constants/server';\nimport blocklistedTagsProcessor from '@server/job/blocklistedTagsProcessor';\nimport availabilitySync from '@server/lib/availabilitySync';\nimport downloadTracker from '@server/lib/downloadtracker';\nimport ImageProxy from '@server/lib/imageproxy';\nimport refreshToken from '@server/lib/refreshToken';\nimport {\n  jellyfinFullScanner,\n  jellyfinRecentScanner,\n} from '@server/lib/scanners/jellyfin';\nimport { plexFullScanner, plexRecentScanner } from '@server/lib/scanners/plex';\nimport { radarrScanner } from '@server/lib/scanners/radarr';\nimport { sonarrScanner } from '@server/lib/scanners/sonarr';\nimport type { JobId } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport watchlistSync from '@server/lib/watchlistsync';\nimport logger from '@server/logger';\nimport schedule from 'node-schedule';\n\ninterface ScheduledJob {\n  id: JobId;\n  job: schedule.Job;\n  name: string;\n  type: 'process' | 'command';\n  interval: 'seconds' | 'minutes' | 'hours' | 'days' | 'fixed';\n  cronSchedule: string;\n  running?: () => boolean;\n  cancelFn?: () => void;\n}\n\nexport const scheduledJobs: ScheduledJob[] = [];\n\nexport const startJobs = (): void => {\n  const jobs = getSettings().jobs;\n  const mediaServerType = getSettings().main.mediaServerType;\n\n  if (mediaServerType === MediaServerType.PLEX) {\n    // Run recently added plex scan every 5 minutes\n    scheduledJobs.push({\n      id: 'plex-recently-added-scan',\n      name: 'Plex Recently Added Scan',\n      type: 'process',\n      interval: 'minutes',\n      cronSchedule: jobs['plex-recently-added-scan'].schedule,\n      job: schedule.scheduleJob(\n        jobs['plex-recently-added-scan'].schedule,\n        () => {\n          logger.info('Starting scheduled job: Plex Recently Added Scan', {\n            label: 'Jobs',\n          });\n          plexRecentScanner.run();\n        }\n      ),\n      running: () => plexRecentScanner.status().running,\n      cancelFn: () => plexRecentScanner.cancel(),\n    });\n\n    // Run full plex scan every 24 hours\n    scheduledJobs.push({\n      id: 'plex-full-scan',\n      name: 'Plex Full Library Scan',\n      type: 'process',\n      interval: 'hours',\n      cronSchedule: jobs['plex-full-scan'].schedule,\n      job: schedule.scheduleJob(jobs['plex-full-scan'].schedule, () => {\n        logger.info('Starting scheduled job: Plex Full Library Scan', {\n          label: 'Jobs',\n        });\n        plexFullScanner.run();\n      }),\n      running: () => plexFullScanner.status().running,\n      cancelFn: () => plexFullScanner.cancel(),\n    });\n\n    scheduledJobs.push({\n      id: 'plex-refresh-token',\n      name: 'Plex Refresh Token',\n      type: 'process',\n      interval: 'fixed',\n      cronSchedule: jobs['plex-refresh-token'].schedule,\n      job: schedule.scheduleJob(jobs['plex-refresh-token'].schedule, () => {\n        logger.info('Starting scheduled job: Plex Refresh Token', {\n          label: 'Jobs',\n        });\n        refreshToken.run();\n      }),\n    });\n\n    // Watchlist Sync\n    scheduledJobs.push({\n      id: 'plex-watchlist-sync',\n      name: 'Plex Watchlist Sync',\n      type: 'process',\n      interval: 'seconds',\n      cronSchedule: jobs['plex-watchlist-sync'].schedule,\n      job: schedule.scheduleJob(jobs['plex-watchlist-sync'].schedule, () => {\n        logger.info('Starting scheduled job: Plex Watchlist Sync', {\n          label: 'Jobs',\n        });\n        watchlistSync.syncWatchlist();\n      }),\n    });\n  } else if (\n    mediaServerType === MediaServerType.JELLYFIN ||\n    mediaServerType === MediaServerType.EMBY\n  ) {\n    // Run recently added jellyfin sync every 5 minutes\n    scheduledJobs.push({\n      id: 'jellyfin-recently-added-scan',\n      name: 'Jellyfin Recently Added Scan',\n      type: 'process',\n      interval: 'minutes',\n      cronSchedule: jobs['jellyfin-recently-added-scan'].schedule,\n      job: schedule.scheduleJob(\n        jobs['jellyfin-recently-added-scan'].schedule,\n        () => {\n          logger.info('Starting scheduled job: Jellyfin Recently Added Scan', {\n            label: 'Jobs',\n          });\n          jellyfinRecentScanner.run();\n        }\n      ),\n      running: () => jellyfinRecentScanner.status().running,\n      cancelFn: () => jellyfinRecentScanner.cancel(),\n    });\n\n    // Run full jellyfin sync every 24 hours\n    scheduledJobs.push({\n      id: 'jellyfin-full-scan',\n      name: 'Jellyfin Full Library Scan',\n      type: 'process',\n      interval: 'hours',\n      cronSchedule: jobs['jellyfin-full-scan'].schedule,\n      job: schedule.scheduleJob(jobs['jellyfin-full-scan'].schedule, () => {\n        logger.info('Starting scheduled job: Jellyfin Full Scan', {\n          label: 'Jobs',\n        });\n        jellyfinFullScanner.run();\n      }),\n      running: () => jellyfinFullScanner.status().running,\n      cancelFn: () => jellyfinFullScanner.cancel(),\n    });\n  }\n\n  // Run full radarr scan every 24 hours\n  scheduledJobs.push({\n    id: 'radarr-scan',\n    name: 'Radarr Scan',\n    type: 'process',\n    interval: 'hours',\n    cronSchedule: jobs['radarr-scan'].schedule,\n    job: schedule.scheduleJob(jobs['radarr-scan'].schedule, () => {\n      logger.info('Starting scheduled job: Radarr Scan', { label: 'Jobs' });\n      radarrScanner.run();\n    }),\n    running: () => radarrScanner.status().running,\n    cancelFn: () => radarrScanner.cancel(),\n  });\n\n  // Run full sonarr scan every 24 hours\n  scheduledJobs.push({\n    id: 'sonarr-scan',\n    name: 'Sonarr Scan',\n    type: 'process',\n    interval: 'hours',\n    cronSchedule: jobs['sonarr-scan'].schedule,\n    job: schedule.scheduleJob(jobs['sonarr-scan'].schedule, () => {\n      logger.info('Starting scheduled job: Sonarr Scan', { label: 'Jobs' });\n      sonarrScanner.run();\n    }),\n    running: () => sonarrScanner.status().running,\n    cancelFn: () => sonarrScanner.cancel(),\n  });\n\n  // Checks if media is still available in plex/sonarr/radarr libs\n  scheduledJobs.push({\n    id: 'availability-sync',\n    name: 'Media Availability Sync',\n    type: 'process',\n    interval: 'hours',\n    cronSchedule: jobs['availability-sync'].schedule,\n    job: schedule.scheduleJob(jobs['availability-sync'].schedule, () => {\n      logger.info('Starting scheduled job: Media Availability Sync', {\n        label: 'Jobs',\n      });\n      availabilitySync.run();\n    }),\n    running: () => availabilitySync.running,\n    cancelFn: () => availabilitySync.cancel(),\n  });\n\n  // Run download sync every minute\n  scheduledJobs.push({\n    id: 'download-sync',\n    name: 'Download Sync',\n    type: 'command',\n    interval: 'seconds',\n    cronSchedule: jobs['download-sync'].schedule,\n    job: schedule.scheduleJob(jobs['download-sync'].schedule, () => {\n      logger.debug('Starting scheduled job: Download Sync', {\n        label: 'Jobs',\n      });\n      downloadTracker.updateDownloads();\n    }),\n  });\n\n  // Reset download sync everyday at 01:00 am\n  scheduledJobs.push({\n    id: 'download-sync-reset',\n    name: 'Download Sync Reset',\n    type: 'command',\n    interval: 'hours',\n    cronSchedule: jobs['download-sync-reset'].schedule,\n    job: schedule.scheduleJob(jobs['download-sync-reset'].schedule, () => {\n      logger.info('Starting scheduled job: Download Sync Reset', {\n        label: 'Jobs',\n      });\n      downloadTracker.resetDownloadTracker();\n    }),\n  });\n\n  // Run image cache cleanup every 24 hours\n  scheduledJobs.push({\n    id: 'image-cache-cleanup',\n    name: 'Image Cache Cleanup',\n    type: 'process',\n    interval: 'hours',\n    cronSchedule: jobs['image-cache-cleanup'].schedule,\n    job: schedule.scheduleJob(jobs['image-cache-cleanup'].schedule, () => {\n      logger.info('Starting scheduled job: Image Cache Cleanup', {\n        label: 'Jobs',\n      });\n      // Clean TMDB image cache\n      ImageProxy.clearCache('tmdb');\n\n      // Clean users avatar image cache\n      ImageProxy.clearCache('avatar');\n    }),\n  });\n\n  scheduledJobs.push({\n    id: 'process-blocklisted-tags',\n    name: 'Process Blocklisted Tags',\n    type: 'process',\n    interval: 'days',\n    cronSchedule: jobs['process-blocklisted-tags'].schedule,\n    job: schedule.scheduleJob(jobs['process-blocklisted-tags'].schedule, () => {\n      logger.info('Starting scheduled job: Process Blocklisted Tags', {\n        label: 'Jobs',\n      });\n      blocklistedTagsProcessor.run();\n    }),\n    running: () => blocklistedTagsProcessor.status().running,\n    cancelFn: () => blocklistedTagsProcessor.cancel(),\n  });\n\n  logger.info('Scheduled jobs loaded', { label: 'Jobs' });\n};\n"
  },
  {
    "path": "server/lib/availabilitySync.ts",
    "content": "import type { JellyfinLibraryItem } from '@server/api/jellyfin';\nimport JellyfinAPI from '@server/api/jellyfin';\nimport type { PlexMetadata } from '@server/api/plexapi';\nimport PlexAPI from '@server/api/plexapi';\nimport RadarrAPI, { type RadarrMovie } from '@server/api/servarr/radarr';\nimport type { SonarrSeason, SonarrSeries } from '@server/api/servarr/sonarr';\nimport SonarrAPI from '@server/api/servarr/sonarr';\nimport { MediaRequestStatus, MediaStatus } from '@server/constants/media';\nimport { MediaServerType } from '@server/constants/server';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport MediaRequest from '@server/entity/MediaRequest';\nimport type Season from '@server/entity/Season';\nimport { User } from '@server/entity/User';\nimport type { RadarrSettings, SonarrSettings } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { getHostname } from '@server/utils/getHostname';\n\nclass AvailabilitySync {\n  public running = false;\n  private plexClient: PlexAPI;\n  private plexSeasonsCache: Record<string, PlexMetadata[]>;\n\n  private jellyfinClient: JellyfinAPI;\n  private jellyfinSeasonsCache: Record<string, JellyfinLibraryItem[]>;\n\n  private sonarrSeasonsCache: Record<string, SonarrSeason[]>;\n  private radarrServers: RadarrSettings[];\n  private sonarrServers: SonarrSettings[];\n\n  async run() {\n    const settings = getSettings();\n    const mediaServerType = getSettings().main.mediaServerType;\n    this.running = true;\n    this.plexSeasonsCache = {};\n    this.jellyfinSeasonsCache = {};\n    this.sonarrSeasonsCache = {};\n    this.radarrServers = settings.radarr.filter((server) => server.syncEnabled);\n    this.sonarrServers = settings.sonarr.filter((server) => server.syncEnabled);\n\n    try {\n      logger.info(`Starting availability sync...`, {\n        label: 'Availability Sync',\n      });\n      const pageSize = 50;\n\n      const userRepository = getRepository(User);\n\n      // If it is plex admin is selected using plexToken if jellyfin admin is selected using jellyfinUserID\n\n      let admin = null;\n\n      if (mediaServerType === MediaServerType.PLEX) {\n        admin = await userRepository.findOne({\n          select: { id: true, plexToken: true },\n          where: { id: 1 },\n        });\n      } else if (\n        mediaServerType === MediaServerType.JELLYFIN ||\n        mediaServerType === MediaServerType.EMBY\n      ) {\n        admin = await userRepository.findOne({\n          where: { id: 1 },\n          select: ['id', 'jellyfinUserId', 'jellyfinDeviceId'],\n          order: { id: 'ASC' },\n        });\n      }\n\n      switch (mediaServerType) {\n        case MediaServerType.PLEX:\n          if (admin && admin.plexToken) {\n            this.plexClient = new PlexAPI({ plexToken: admin.plexToken });\n          } else {\n            logger.error('Plex admin is not configured.');\n          }\n          break;\n        case MediaServerType.JELLYFIN:\n        case MediaServerType.EMBY:\n          if (admin) {\n            this.jellyfinClient = new JellyfinAPI(\n              getHostname(),\n              settings.jellyfin.apiKey,\n              admin.jellyfinDeviceId\n            );\n\n            this.jellyfinClient.setUserId(admin.jellyfinUserId ?? '');\n\n            try {\n              await this.jellyfinClient.getSystemInfo();\n            } catch (e) {\n              logger.error('Sync interrupted.', {\n                label: 'AvailabilitySync',\n                status: e.statusCode,\n                error: e.name,\n                errorMessage: e.errorCode,\n              });\n\n              this.running = false;\n              return;\n            }\n          } else {\n            logger.error('Jellyfin admin is not configured.');\n\n            this.running = false;\n            return;\n          }\n          break;\n        default:\n          logger.error('An admin is not configured.');\n\n          this.running = false;\n          return;\n      }\n\n      for await (const media of this.loadAvailableMediaPaginated(pageSize)) {\n        if (!this.running) {\n          throw new Error('Job aborted');\n        }\n\n        // Check plex, radarr, and sonarr for that specific media and\n        // if unavailable, then we change the status accordingly.\n        // If a non-4k or 4k version exists in at least one of the instances, we will only update that specific version\n        if (media.mediaType === 'movie') {\n          let movieExists = false;\n          let movieExists4k = false;\n\n          // if (mediaServerType === MediaServerType.PLEX) {\n          //   await this.mediaExistsInPlex(media, false);\n          // } else if (\n          //   mediaServerType === MediaServerType.JELLYFIN ||\n          //   mediaServerType === MediaServerType.EMBY\n          // ) {\n          //   await this.mediaExistsInJellyfin(media, false);\n          // }\n\n          const existsInRadarr = await this.mediaExistsInRadarr(media, false);\n          const existsInRadarr4k = await this.mediaExistsInRadarr(media, true);\n\n          // plex\n          if (mediaServerType === MediaServerType.PLEX) {\n            const { existsInPlex } = await this.mediaExistsInPlex(media, false);\n            const { existsInPlex: existsInPlex4k } =\n              await this.mediaExistsInPlex(media, true);\n\n            if (existsInPlex || existsInRadarr) {\n              movieExists = true;\n              logger.info(\n                `The non-4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,\n                {\n                  label: 'AvailabilitySync',\n                }\n              );\n            }\n\n            if (existsInPlex4k || existsInRadarr4k) {\n              movieExists4k = true;\n              logger.info(\n                `The 4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,\n                {\n                  label: 'AvailabilitySync',\n                }\n              );\n            }\n          }\n\n          //jellyfin\n          if (\n            mediaServerType === MediaServerType.JELLYFIN ||\n            mediaServerType === MediaServerType.EMBY\n          ) {\n            const { existsInJellyfin } = await this.mediaExistsInJellyfin(\n              media,\n              false\n            );\n            const { existsInJellyfin: existsInJellyfin4k } =\n              await this.mediaExistsInJellyfin(media, true);\n\n            if (existsInJellyfin || existsInRadarr) {\n              movieExists = true;\n              logger.info(\n                `The non-4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,\n                {\n                  label: 'AvailabilitySync',\n                }\n              );\n            }\n\n            if (existsInJellyfin4k || existsInRadarr4k) {\n              movieExists4k = true;\n              logger.info(\n                `The 4K movie [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,\n                {\n                  label: 'AvailabilitySync',\n                }\n              );\n            }\n          }\n\n          if (!movieExists && media.status === MediaStatus.AVAILABLE) {\n            await this.mediaUpdater(media, false, mediaServerType);\n          }\n\n          if (!movieExists4k && media.status4k === MediaStatus.AVAILABLE) {\n            await this.mediaUpdater(media, true, mediaServerType);\n          }\n        }\n\n        // If both versions still exist in plex, we still need\n        // to check through sonarr to verify season availability\n        if (media.mediaType === 'tv') {\n          let showExists = false;\n          let showExists4k = false;\n\n          //plex\n\n          const { existsInPlex, seasonsMap: plexSeasonsMap = new Map() } =\n            await this.mediaExistsInPlex(media, false);\n          const {\n            existsInPlex: existsInPlex4k,\n            seasonsMap: plexSeasonsMap4k = new Map(),\n          } = await this.mediaExistsInPlex(media, true);\n\n          //jellyfin\n          const {\n            existsInJellyfin,\n            seasonsMap: jellyfinSeasonsMap = new Map(),\n          } = await this.mediaExistsInJellyfin(media, false);\n          const {\n            existsInJellyfin: existsInJellyfin4k,\n            seasonsMap: jellyfinSeasonsMap4k = new Map(),\n          } = await this.mediaExistsInJellyfin(media, true);\n\n          const { existsInSonarr, seasonsMap: sonarrSeasonsMap } =\n            await this.mediaExistsInSonarr(media, false);\n          const {\n            existsInSonarr: existsInSonarr4k,\n            seasonsMap: sonarrSeasonsMap4k,\n          } = await this.mediaExistsInSonarr(media, true);\n\n          //plex\n          if (mediaServerType === MediaServerType.PLEX) {\n            if (existsInPlex || existsInSonarr) {\n              showExists = true;\n              logger.info(\n                `The non-4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,\n                {\n                  label: 'AvailabilitySync',\n                }\n              );\n            }\n          }\n\n          if (mediaServerType === MediaServerType.PLEX) {\n            if (existsInPlex4k || existsInSonarr4k) {\n              showExists4k = true;\n              logger.info(\n                `The 4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,\n                {\n                  label: 'AvailabilitySync',\n                }\n              );\n            }\n          }\n\n          //jellyfin\n          if (\n            mediaServerType === MediaServerType.JELLYFIN ||\n            mediaServerType === MediaServerType.EMBY\n          ) {\n            if (existsInJellyfin || existsInSonarr) {\n              showExists = true;\n              logger.info(\n                `The non-4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,\n                {\n                  label: 'AvailabilitySync',\n                }\n              );\n            }\n          }\n\n          if (\n            mediaServerType === MediaServerType.JELLYFIN ||\n            mediaServerType === MediaServerType.EMBY\n          ) {\n            if (existsInJellyfin4k || existsInSonarr4k) {\n              showExists4k = true;\n              logger.info(\n                `The 4K show [TMDB ID ${media.tmdbId}] still exists. Preventing removal.`,\n                {\n                  label: 'AvailabilitySync',\n                }\n              );\n            }\n          }\n\n          // Here we will create a final map that will cross compare\n          // with plex and sonarr. Filtered seasons will go through\n          // each season and assume the season does not exist. If Plex or\n          // Sonarr finds that season, we will change the final seasons value\n          // to true.\n          const filteredSeasonsMap: Map<number, boolean> = new Map();\n          media.seasons\n            .filter(\n              (season) =>\n                season.status === MediaStatus.AVAILABLE ||\n                season.status === MediaStatus.PARTIALLY_AVAILABLE\n            )\n            .forEach((season) =>\n              filteredSeasonsMap.set(season.seasonNumber, false)\n            );\n\n          const filteredSeasonsMap4k: Map<number, boolean> = new Map();\n          media.seasons\n            .filter(\n              (season) =>\n                season.status4k === MediaStatus.AVAILABLE ||\n                season.status4k === MediaStatus.PARTIALLY_AVAILABLE\n            )\n            .forEach((season) =>\n              filteredSeasonsMap4k.set(season.seasonNumber, false)\n            );\n\n          let finalSeasons: Map<number, boolean>;\n          let finalSeasons4k: Map<number, boolean>;\n\n          if (mediaServerType === MediaServerType.PLEX) {\n            finalSeasons = new Map([\n              ...filteredSeasonsMap,\n              ...plexSeasonsMap,\n              ...sonarrSeasonsMap,\n            ]);\n            finalSeasons4k = new Map([\n              ...filteredSeasonsMap4k,\n              ...plexSeasonsMap4k,\n              ...sonarrSeasonsMap4k,\n            ]);\n          } else {\n            // Jellyfin/Emby\n            finalSeasons = new Map([\n              ...filteredSeasonsMap,\n              ...jellyfinSeasonsMap,\n              ...sonarrSeasonsMap,\n            ]);\n            finalSeasons4k = new Map([\n              ...filteredSeasonsMap4k,\n              ...jellyfinSeasonsMap4k,\n              ...sonarrSeasonsMap4k,\n            ]);\n          }\n\n          if (\n            !showExists &&\n            (media.status === MediaStatus.AVAILABLE ||\n              media.status === MediaStatus.PARTIALLY_AVAILABLE ||\n              media.seasons.some(\n                (season) => season.status === MediaStatus.AVAILABLE\n              ) ||\n              media.seasons.some(\n                (season) => season.status === MediaStatus.PARTIALLY_AVAILABLE\n              ))\n          ) {\n            await this.mediaUpdater(media, false, mediaServerType);\n          }\n\n          if (\n            !showExists4k &&\n            (media.status4k === MediaStatus.AVAILABLE ||\n              media.status4k === MediaStatus.PARTIALLY_AVAILABLE ||\n              media.seasons.some(\n                (season) => season.status4k === MediaStatus.AVAILABLE\n              ) ||\n              media.seasons.some(\n                (season) => season.status4k === MediaStatus.PARTIALLY_AVAILABLE\n              ))\n          ) {\n            await this.mediaUpdater(media, true, mediaServerType);\n          }\n\n          // TODO: Figure out how to run seasonUpdater for each season\n\n          if ([...finalSeasons.values()].includes(false)) {\n            await this.seasonUpdater(\n              media,\n              finalSeasons,\n              false,\n              mediaServerType\n            );\n          }\n\n          if ([...finalSeasons4k.values()].includes(false)) {\n            await this.seasonUpdater(\n              media,\n              finalSeasons4k,\n              true,\n              mediaServerType\n            );\n          }\n        }\n      }\n    } catch (ex) {\n      logger.error('Failed to complete availability sync.', {\n        errorMessage: ex.message,\n        label: 'Availability Sync',\n      });\n    } finally {\n      logger.info(`Availability sync complete.`, {\n        label: 'Availability Sync',\n      });\n      this.running = false;\n    }\n  }\n\n  public cancel() {\n    this.running = false;\n  }\n\n  private async *loadAvailableMediaPaginated(pageSize: number) {\n    let offset = 0;\n    const mediaRepository = getRepository(Media);\n    const whereOptions = [\n      { status: MediaStatus.AVAILABLE },\n      { status: MediaStatus.PARTIALLY_AVAILABLE },\n      { status4k: MediaStatus.AVAILABLE },\n      { status4k: MediaStatus.PARTIALLY_AVAILABLE },\n      { seasons: { status: MediaStatus.AVAILABLE } },\n      { seasons: { status: MediaStatus.PARTIALLY_AVAILABLE } },\n      { seasons: { status4k: MediaStatus.AVAILABLE } },\n      { seasons: { status4k: MediaStatus.PARTIALLY_AVAILABLE } },\n    ];\n\n    let mediaPage: Media[];\n\n    do {\n      yield* (mediaPage = await mediaRepository.find({\n        where: whereOptions,\n        skip: offset,\n        take: pageSize,\n      }));\n      offset += pageSize;\n    } while (mediaPage.length > 0);\n  }\n\n  private async mediaUpdater(\n    media: Media,\n    is4k: boolean,\n    mediaServerType: MediaServerType\n  ): Promise<void> {\n    const mediaRepository = getRepository(Media);\n\n    try {\n      // If media type is tv, check if a season is processing\n      // to see if we need to keep the external metadata\n      let isMediaProcessing = false;\n\n      if (media.mediaType === 'tv') {\n        const requestRepository = getRepository(MediaRequest);\n\n        const request = await requestRepository\n          .createQueryBuilder('request')\n          .leftJoinAndSelect('request.media', 'media')\n          .where('(media.id = :id)', {\n            id: media.id,\n          })\n          .andWhere(\n            '(request.is4k = :is4k AND request.status = :requestStatus)',\n            {\n              requestStatus: MediaRequestStatus.APPROVED,\n              is4k: is4k,\n            }\n          )\n          .getOne();\n\n        if (request) {\n          isMediaProcessing = true;\n        }\n      }\n\n      // Set the non-4K or 4K media to deleted\n      // and change related columns to null if media\n      // is not processing\n      media[is4k ? 'status4k' : 'status'] = MediaStatus.DELETED;\n      media[is4k ? 'serviceId4k' : 'serviceId'] = isMediaProcessing\n        ? media[is4k ? 'serviceId4k' : 'serviceId']\n        : null;\n      media[is4k ? 'externalServiceId4k' : 'externalServiceId'] =\n        isMediaProcessing\n          ? media[is4k ? 'externalServiceId4k' : 'externalServiceId']\n          : null;\n      media[is4k ? 'externalServiceSlug4k' : 'externalServiceSlug'] =\n        isMediaProcessing\n          ? media[is4k ? 'externalServiceSlug4k' : 'externalServiceSlug']\n          : null;\n      if (mediaServerType === MediaServerType.PLEX) {\n        media[is4k ? 'ratingKey4k' : 'ratingKey'] = isMediaProcessing\n          ? media[is4k ? 'ratingKey4k' : 'ratingKey']\n          : null;\n      } else if (\n        mediaServerType === MediaServerType.JELLYFIN ||\n        mediaServerType === MediaServerType.EMBY\n      ) {\n        media[is4k ? 'jellyfinMediaId4k' : 'jellyfinMediaId'] =\n          isMediaProcessing\n            ? media[is4k ? 'jellyfinMediaId4k' : 'jellyfinMediaId']\n            : null;\n      }\n      logger.info(\n        `The ${is4k ? '4K' : 'non-4K'} ${\n          media.mediaType === 'movie' ? 'movie' : 'show'\n        } [TMDB ID ${media.tmdbId}] was not found in any ${\n          media.mediaType === 'movie' ? 'Radarr' : 'Sonarr'\n        } and ${\n          mediaServerType === MediaServerType.PLEX\n            ? 'plex'\n            : mediaServerType === MediaServerType.JELLYFIN\n              ? 'jellyfin'\n              : 'emby'\n        } instance. Status will be changed to deleted.`,\n        { label: 'AvailabilitySync' }\n      );\n\n      await mediaRepository.save(media);\n    } catch (ex) {\n      logger.debug(\n        `Failure updating the ${is4k ? '4K' : 'non-4K'} ${\n          media.mediaType === 'tv' ? 'show' : 'movie'\n        } [TMDB ID ${media.tmdbId}].`,\n        {\n          errorMessage: ex.message,\n          label: 'Availability Sync',\n        }\n      );\n    }\n  }\n\n  private async seasonUpdater(\n    media: Media,\n    seasons: Map<number, boolean>,\n    is4k: boolean,\n    mediaServerType: MediaServerType\n  ): Promise<void> {\n    const mediaRepository = getRepository(Media);\n\n    // Filter out only the values that are false\n    // (media that should be deleted)\n    const seasonsPendingRemoval = new Map(\n      // Disabled linter as only the value is needed from the filter\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      [...seasons].filter(([_, exists]) => !exists)\n    );\n    // Retrieve the season keys to pass into our log\n    const seasonKeys = [...seasonsPendingRemoval.keys()];\n\n    // let isSeasonRemoved = false;\n\n    try {\n      for (const mediaSeason of media.seasons) {\n        if (seasonsPendingRemoval.has(mediaSeason.seasonNumber)) {\n          mediaSeason[is4k ? 'status4k' : 'status'] = MediaStatus.DELETED;\n        }\n      }\n\n      if (media.status === MediaStatus.AVAILABLE && !is4k) {\n        media.status = MediaStatus.PARTIALLY_AVAILABLE;\n        logger.info(\n          `Marking the non-4K show [TMDB ID ${media.tmdbId}] as PARTIALLY_AVAILABLE because season removal has occurred.`,\n          { label: 'Availability Sync' }\n        );\n      }\n\n      if (media.status4k === MediaStatus.AVAILABLE && is4k) {\n        media.status4k = MediaStatus.PARTIALLY_AVAILABLE;\n        logger.info(\n          `Marking the 4K show [TMDB ID ${media.tmdbId}] as PARTIALLY_AVAILABLE because season removal has occurred.`,\n          { label: 'Availability Sync' }\n        );\n      }\n\n      media.lastSeasonChange = new Date();\n      await mediaRepository.save(media);\n\n      logger.info(\n        `The ${is4k ? '4K' : 'non-4K'} season(s) [${seasonKeys}] [TMDB ID ${\n          media.tmdbId\n        }] was not found in any ${\n          media.mediaType === 'tv' ? 'Sonarr' : 'Radarr'\n        } and ${\n          mediaServerType === MediaServerType.PLEX\n            ? 'plex'\n            : mediaServerType === MediaServerType.JELLYFIN\n              ? 'jellyfin'\n              : 'emby'\n        } instance. Status will be changed to deleted.`,\n        { label: 'AvailabilitySync' }\n      );\n    } catch (ex) {\n      logger.debug(\n        `Failure updating the ${\n          is4k ? '4K' : 'non-4K'\n        } season(s) [${seasonKeys}], TMDB ID ${media.tmdbId}.`,\n        {\n          errorMessage: ex.message,\n          label: 'Availability Sync',\n        }\n      );\n    }\n  }\n\n  private async mediaExistsInRadarr(\n    media: Media,\n    is4k: boolean\n  ): Promise<boolean> {\n    let existsInRadarr = false;\n\n    const hasSameServerInBothModes = this.radarrServers.some((a) =>\n      this.radarrServers.some(\n        (b) =>\n          a.is4k !== b.is4k && a.hostname === b.hostname && a.port === b.port\n      )\n    );\n\n    // Check for availability in all of the available radarr servers\n    // If any find the media, we will assume the media exists\n    for (const server of this.radarrServers.filter(\n      (server) => server.is4k === is4k\n    )) {\n      const radarrAPI = new RadarrAPI({\n        apiKey: server.apiKey,\n        url: RadarrAPI.buildUrl(server, '/api/v3'),\n      });\n\n      try {\n        let radarr: RadarrMovie | undefined;\n\n        if (media.externalServiceId && !is4k) {\n          radarr = await radarrAPI.getMovie({\n            id: media.externalServiceId,\n          });\n        }\n\n        if (media.externalServiceId4k && is4k) {\n          radarr = await radarrAPI.getMovie({\n            id: media.externalServiceId4k,\n          });\n        }\n\n        if (radarr && radarr.hasFile) {\n          const resolution =\n            radarr?.movieFile?.mediaInfo?.resolution?.split('x');\n          const is4kMovie =\n            resolution?.length === 2 && Number(resolution[0]) >= 2000;\n\n          if (hasSameServerInBothModes && resolution?.length === 2) {\n            // Same server in both modes then use resolution to distinguish\n            existsInRadarr = is4k ? is4kMovie : !is4kMovie;\n          } else {\n            // One server type and if file exists, count it\n            existsInRadarr = true;\n          }\n        }\n      } catch (ex) {\n        if (!ex.message.includes('404')) {\n          existsInRadarr = true;\n          logger.debug(\n            `Failure retrieving the ${is4k ? '4K' : 'non-4K'} movie [TMDB ID ${\n              media.tmdbId\n            }] from Radarr.`,\n            {\n              errorMessage: ex.message,\n              label: 'Availability Sync',\n            }\n          );\n        }\n      }\n\n      if (existsInRadarr) break;\n    }\n\n    return existsInRadarr;\n  }\n\n  private async mediaExistsInSonarr(\n    media: Media,\n    is4k: boolean\n  ): Promise<{ existsInSonarr: boolean; seasonsMap: Map<number, boolean> }> {\n    let existsInSonarr = false;\n    let preventSeasonSearch = false;\n\n    // Check for availability in all of the available sonarr servers\n    // If any find the media, we will assume the media exists\n    for (const server of this.sonarrServers.filter((server) => {\n      return server.is4k === is4k;\n    })) {\n      const sonarrAPI = new SonarrAPI({\n        apiKey: server.apiKey,\n        url: SonarrAPI.buildUrl(server, '/api/v3'),\n      });\n\n      try {\n        let sonarr: SonarrSeries | undefined;\n\n        if (media.externalServiceId && !is4k) {\n          sonarr = await sonarrAPI.getSeriesById(media.externalServiceId);\n          this.sonarrSeasonsCache[`${server.id}-${media.externalServiceId}`] =\n            sonarr.seasons;\n        }\n\n        if (media.externalServiceId4k && is4k) {\n          sonarr = await sonarrAPI.getSeriesById(media.externalServiceId4k);\n          this.sonarrSeasonsCache[`${server.id}-${media.externalServiceId4k}`] =\n            sonarr.seasons;\n        }\n\n        if (sonarr && sonarr.statistics.episodeFileCount > 0) {\n          existsInSonarr = true;\n        }\n      } catch (ex) {\n        if (!ex.message.includes('404')) {\n          existsInSonarr = true;\n          preventSeasonSearch = true;\n          logger.debug(\n            `Failure retrieving the ${is4k ? '4K' : 'non-4K'} show [TMDB ID ${\n              media.tmdbId\n            }] from Sonarr.`,\n            {\n              errorMessage: ex.message,\n              label: 'Availability Sync',\n            }\n          );\n        }\n      }\n    }\n\n    // Here we check each season for availability\n    // If the API returns an error other than a 404,\n    // we will have to prevent the season check from happening\n    const seasonsMap: Map<number, boolean> = new Map();\n\n    if (!preventSeasonSearch) {\n      const filteredSeasons = media.seasons.filter(\n        (season) =>\n          season[is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE ||\n          season[is4k ? 'status4k' : 'status'] ===\n            MediaStatus.PARTIALLY_AVAILABLE\n      );\n\n      for (const season of filteredSeasons) {\n        const seasonExists = await this.seasonExistsInSonarr(\n          media,\n          season,\n          is4k\n        );\n\n        if (seasonExists) {\n          seasonsMap.set(season.seasonNumber, true);\n        }\n      }\n    }\n\n    return { existsInSonarr, seasonsMap };\n  }\n\n  private async seasonExistsInSonarr(\n    media: Media,\n    season: Season,\n    is4k: boolean\n  ): Promise<boolean> {\n    let seasonExists = false;\n\n    // Check each sonarr instance to see if the media still exists\n    // If found, we will assume the media exists and prevent removal\n    // We can use the cache we built when we fetched the series with mediaExistsInSonarr\n    for (const server of this.sonarrServers.filter(\n      (server) => server.is4k === is4k\n    )) {\n      let sonarrSeasons: SonarrSeason[] | undefined;\n\n      if (media.externalServiceId && !is4k) {\n        sonarrSeasons =\n          this.sonarrSeasonsCache[`${server.id}-${media.externalServiceId}`];\n      }\n\n      if (media.externalServiceId4k && is4k) {\n        sonarrSeasons =\n          this.sonarrSeasonsCache[`${server.id}-${media.externalServiceId4k}`];\n      }\n\n      const seasonIsAvailable = sonarrSeasons?.find(\n        ({ seasonNumber, statistics }) =>\n          season.seasonNumber === seasonNumber &&\n          statistics?.episodeFileCount &&\n          statistics?.episodeFileCount > 0\n      );\n\n      if (seasonIsAvailable && sonarrSeasons) {\n        seasonExists = true;\n      }\n    }\n\n    return seasonExists;\n  }\n\n  // Plex\n  private async mediaExistsInPlex(\n    media: Media,\n    is4k: boolean\n  ): Promise<{ existsInPlex: boolean; seasonsMap?: Map<number, boolean> }> {\n    const ratingKey = media.ratingKey;\n    const ratingKey4k = media.ratingKey4k;\n    let existsInPlex = false;\n    let preventSeasonSearch = false;\n\n    // Check each plex instance to see if the media still exists\n    // If found, we will assume the media exists and prevent removal\n    // We can use the cache we built when we fetched the series with mediaExistsInPlex\n    try {\n      let plexMedia: PlexMetadata | undefined;\n\n      if (ratingKey && !is4k) {\n        plexMedia = await this.plexClient?.getMetadata(ratingKey);\n\n        if (media.mediaType === 'tv') {\n          this.plexSeasonsCache[ratingKey] =\n            await this.plexClient?.getChildrenMetadata(ratingKey);\n        }\n      }\n\n      if (ratingKey4k && is4k) {\n        plexMedia = await this.plexClient?.getMetadata(ratingKey4k);\n\n        if (media.mediaType === 'tv') {\n          this.plexSeasonsCache[ratingKey4k] =\n            await this.plexClient?.getChildrenMetadata(ratingKey4k);\n        }\n\n        if (plexMedia) {\n          if (ratingKey === ratingKey4k) {\n            plexMedia = undefined;\n          }\n\n          if (\n            plexMedia &&\n            media.mediaType === 'movie' &&\n            !plexMedia.Media?.some(\n              (mediaItem) => (mediaItem.width ?? 0) >= 2000\n            )\n          ) {\n            plexMedia = undefined;\n          }\n\n          if (plexMedia && media.mediaType === 'tv') {\n            const cachedSeasons = this.plexSeasonsCache[ratingKey4k];\n            if (cachedSeasons?.length) {\n              let has4kInAnySeason = false;\n              for (const season of cachedSeasons) {\n                try {\n                  const episodes = await this.plexClient?.getChildrenMetadata(\n                    season.ratingKey\n                  );\n                  const has4kEpisode = episodes?.some((episode) =>\n                    episode.Media?.some(\n                      (mediaItem) => (mediaItem.width ?? 0) >= 2000\n                    )\n                  );\n                  if (has4kEpisode) {\n                    has4kInAnySeason = true;\n                    break;\n                  }\n                } catch {\n                  // If we can't fetch episodes for a season, continue checking other seasons\n                }\n              }\n              if (!has4kInAnySeason) {\n                plexMedia = undefined;\n              }\n            }\n          }\n        }\n      }\n\n      if (plexMedia) {\n        existsInPlex = true;\n      }\n    } catch (ex) {\n      if (!ex.message.includes('404')) {\n        existsInPlex = true;\n        preventSeasonSearch = true;\n        logger.debug(\n          `Failure retrieving the ${is4k ? '4K' : 'non-4K'} ${\n            media.mediaType === 'tv' ? 'show' : 'movie'\n          } [TMDB ID ${media.tmdbId}] from Plex.`,\n          {\n            errorMessage: ex.message,\n            label: 'Availability Sync',\n          }\n        );\n      }\n    }\n\n    // Here we check each season in plex for availability\n    // If the API returns an error other than a 404,\n    // we will have to prevent the season check from happening\n    if (media.mediaType === 'tv') {\n      const seasonsMap: Map<number, boolean> = new Map();\n\n      if (!preventSeasonSearch) {\n        const filteredSeasons = media.seasons.filter(\n          (season) =>\n            season[is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE ||\n            season[is4k ? 'status4k' : 'status'] ===\n              MediaStatus.PARTIALLY_AVAILABLE\n        );\n\n        for (const season of filteredSeasons) {\n          const seasonExists = await this.seasonExistsInPlex(\n            media,\n            season,\n            is4k\n          );\n\n          if (seasonExists) {\n            seasonsMap.set(season.seasonNumber, true);\n          }\n        }\n      }\n\n      return { existsInPlex, seasonsMap };\n    }\n\n    return { existsInPlex };\n  }\n\n  private async seasonExistsInPlex(\n    media: Media,\n    season: Season,\n    is4k: boolean\n  ): Promise<boolean> {\n    const ratingKey = media.ratingKey;\n    const ratingKey4k = media.ratingKey4k;\n    let seasonExistsInPlex = false;\n\n    // Check each plex instance to see if the season exists\n    let plexSeasons: PlexMetadata[] | undefined;\n\n    if (ratingKey && !is4k) {\n      plexSeasons = this.plexSeasonsCache[ratingKey];\n    }\n\n    if (ratingKey4k && is4k) {\n      plexSeasons = this.plexSeasonsCache[ratingKey4k];\n    }\n\n    const seasonIsAvailable = plexSeasons?.find(\n      (plexSeason) => plexSeason.index === season.seasonNumber\n    );\n\n    if (seasonIsAvailable) {\n      seasonExistsInPlex = true;\n    }\n\n    return seasonExistsInPlex;\n  }\n\n  // Jellyfin\n  private async mediaExistsInJellyfin(\n    media: Media,\n    is4k: boolean\n  ): Promise<{ existsInJellyfin: boolean; seasonsMap?: Map<number, boolean> }> {\n    const ratingKey = media.jellyfinMediaId;\n    const ratingKey4k = media.jellyfinMediaId4k;\n    let existsInJellyfin = false;\n    let preventSeasonSearch = false;\n\n    // Check each jellyfin instance to see if the media still exists\n    // If found, we will assume the media exists and prevent removal\n    // We can use the cache we built when we fetched the series with mediaExistsInJellyfin\n    try {\n      let jellyfinMedia: JellyfinLibraryItem | undefined;\n\n      if (ratingKey && !is4k) {\n        jellyfinMedia = await this.jellyfinClient?.getItemData(ratingKey);\n\n        if (media.mediaType === 'tv' && jellyfinMedia !== undefined) {\n          this.jellyfinSeasonsCache[ratingKey] =\n            await this.jellyfinClient?.getSeasons(ratingKey);\n        }\n      }\n\n      if (ratingKey4k && is4k) {\n        jellyfinMedia = await this.jellyfinClient?.getItemData(ratingKey4k);\n\n        if (media.mediaType === 'tv' && jellyfinMedia !== undefined) {\n          this.jellyfinSeasonsCache[ratingKey4k] =\n            await this.jellyfinClient?.getSeasons(ratingKey4k);\n        }\n      }\n\n      if (jellyfinMedia) {\n        existsInJellyfin = true;\n      }\n    } catch (ex) {\n      if (!ex.message.includes('404') && !ex.message.includes('500')) {\n        existsInJellyfin = true;\n        preventSeasonSearch = true;\n        logger.debug(\n          `Failure retrieving the ${is4k ? '4K' : 'non-4K'} ${\n            media.mediaType === 'tv' ? 'show' : 'movie'\n          } [TMDB ID ${media.tmdbId}] from Jellyfin.`,\n          {\n            errorMessage: ex.message,\n            label: 'AvailabilitySync',\n          }\n        );\n      }\n    }\n\n    // Here we check each season in jellyfin for availability\n    // If the API returns an error other than a 404,\n    // we will have to prevent the season check from happening\n    if (media.mediaType === 'tv') {\n      const seasonsMap: Map<number, boolean> = new Map();\n\n      if (!preventSeasonSearch) {\n        const filteredSeasons = media.seasons.filter(\n          (season) =>\n            season[is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE ||\n            season[is4k ? 'status4k' : 'status'] ===\n              MediaStatus.PARTIALLY_AVAILABLE\n        );\n\n        for (const season of filteredSeasons) {\n          const seasonExists = await this.seasonExistsInJellyfin(\n            media,\n            season,\n            is4k\n          );\n\n          if (seasonExists) {\n            seasonsMap.set(season.seasonNumber, true);\n          }\n        }\n      }\n\n      return { existsInJellyfin, seasonsMap };\n    }\n\n    return { existsInJellyfin };\n  }\n\n  private async seasonExistsInJellyfin(\n    media: Media,\n    season: Season,\n    is4k: boolean\n  ): Promise<boolean> {\n    const ratingKey = media.jellyfinMediaId;\n    const ratingKey4k = media.jellyfinMediaId4k;\n    let seasonExistsInJellyfin = false;\n\n    // Check each jellyfin instance to see if the season exists\n    let jellyfinSeasons: JellyfinLibraryItem[] | undefined;\n\n    if (ratingKey && !is4k) {\n      jellyfinSeasons = this.jellyfinSeasonsCache[ratingKey];\n    }\n\n    if (ratingKey4k && is4k) {\n      jellyfinSeasons = this.jellyfinSeasonsCache[ratingKey4k];\n    }\n\n    const seasonIsAvailable = jellyfinSeasons?.find(\n      (jellyfinSeason) => jellyfinSeason.IndexNumber === season.seasonNumber\n    );\n\n    if (seasonIsAvailable) {\n      seasonExistsInJellyfin = true;\n    }\n\n    return seasonExistsInJellyfin;\n  }\n}\n\nconst availabilitySync = new AvailabilitySync();\n\nexport default availabilitySync;\n"
  },
  {
    "path": "server/lib/cache.ts",
    "content": "import NodeCache from 'node-cache';\n\nexport type AvailableCacheIds =\n  | 'tmdb'\n  | 'radarr'\n  | 'sonarr'\n  | 'rt'\n  | 'imdb'\n  | 'github'\n  | 'plexguid'\n  | 'plextv'\n  | 'plexwatchlist'\n  | 'tvdb';\n\nconst DEFAULT_TTL = 300;\nconst DEFAULT_CHECK_PERIOD = 120;\n\nclass Cache {\n  public id: AvailableCacheIds;\n  public data: NodeCache;\n  public name: string;\n\n  constructor(\n    id: AvailableCacheIds,\n    name: string,\n    options: { stdTtl?: number; checkPeriod?: number } = {}\n  ) {\n    this.id = id;\n    this.name = name;\n    this.data = new NodeCache({\n      stdTTL: options.stdTtl ?? DEFAULT_TTL,\n      checkperiod: options.checkPeriod ?? DEFAULT_CHECK_PERIOD,\n    });\n  }\n\n  public getStats() {\n    return this.data.getStats();\n  }\n\n  public flush(): void {\n    this.data.flushAll();\n  }\n}\n\nclass CacheManager {\n  private availableCaches: Record<AvailableCacheIds, Cache> = {\n    tmdb: new Cache('tmdb', 'The Movie Database API', {\n      stdTtl: 21600,\n      checkPeriod: 60 * 30,\n    }),\n    radarr: new Cache('radarr', 'Radarr API'),\n    sonarr: new Cache('sonarr', 'Sonarr API'),\n    rt: new Cache('rt', 'Rotten Tomatoes API', {\n      stdTtl: 43200,\n      checkPeriod: 60 * 30,\n    }),\n    imdb: new Cache('imdb', 'IMDB Radarr Proxy', {\n      stdTtl: 43200,\n      checkPeriod: 60 * 30,\n    }),\n    github: new Cache('github', 'GitHub API', {\n      stdTtl: 21600,\n      checkPeriod: 60 * 30,\n    }),\n    plexguid: new Cache('plexguid', 'Plex GUID', {\n      stdTtl: 86400 * 7, // 1 week cache\n      checkPeriod: 60 * 30,\n    }),\n    plextv: new Cache('plextv', 'Plex TV', {\n      stdTtl: 86400 * 7, // 1 week cache\n      checkPeriod: 60,\n    }),\n    plexwatchlist: new Cache('plexwatchlist', 'Plex Watchlist'),\n    tvdb: new Cache('tvdb', 'The TVDB API', {\n      stdTtl: 21600,\n      checkPeriod: 60 * 30,\n    }),\n  };\n\n  public getCache(id: AvailableCacheIds): Cache {\n    return this.availableCaches[id];\n  }\n\n  public getAllCaches(): Record<string, Cache> {\n    return this.availableCaches;\n  }\n}\n\nconst cacheManager = new CacheManager();\n\nexport default cacheManager;\n"
  },
  {
    "path": "server/lib/downloadtracker.ts",
    "content": "import RadarrAPI from '@server/api/servarr/radarr';\nimport SonarrAPI from '@server/api/servarr/sonarr';\nimport { MediaType } from '@server/constants/media';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { uniqWith } from 'lodash';\n\ninterface EpisodeNumberResult {\n  seasonNumber: number;\n  episodeNumber: number;\n  absoluteEpisodeNumber: number;\n  id: number;\n}\nexport interface DownloadingItem {\n  mediaType: MediaType;\n  externalId: number;\n  size: number;\n  sizeLeft: number;\n  status: string;\n  timeLeft: string;\n  estimatedCompletionTime: Date;\n  title: string;\n  downloadId: string;\n  episode?: EpisodeNumberResult;\n}\n\nclass DownloadTracker {\n  private radarrServers: Record<number, DownloadingItem[]> = {};\n  private sonarrServers: Record<number, DownloadingItem[]> = {};\n\n  public getMovieProgress(\n    serverId: number,\n    externalServiceId: number\n  ): DownloadingItem[] {\n    if (!this.radarrServers[serverId]) {\n      return [];\n    }\n\n    return this.radarrServers[serverId].filter(\n      (item) => item.externalId === externalServiceId\n    );\n  }\n\n  public getSeriesProgress(\n    serverId: number,\n    externalServiceId: number\n  ): DownloadingItem[] {\n    if (!this.sonarrServers[serverId]) {\n      return [];\n    }\n\n    return this.sonarrServers[serverId].filter(\n      (item) => item.externalId === externalServiceId\n    );\n  }\n\n  public async resetDownloadTracker() {\n    this.radarrServers = {};\n    this.sonarrServers = {};\n  }\n\n  public updateDownloads() {\n    this.updateRadarrDownloads();\n    this.updateSonarrDownloads();\n  }\n\n  private async updateRadarrDownloads() {\n    const settings = getSettings();\n\n    // Remove duplicate servers\n    const filteredServers = uniqWith(settings.radarr, (radarrA, radarrB) => {\n      return (\n        radarrA.hostname === radarrB.hostname &&\n        radarrA.port === radarrB.port &&\n        radarrA.baseUrl === radarrB.baseUrl\n      );\n    });\n\n    // Load downloads from Radarr servers\n    Promise.all(\n      filteredServers.map(async (server) => {\n        if (server.syncEnabled) {\n          const radarr = new RadarrAPI({\n            apiKey: server.apiKey,\n            url: RadarrAPI.buildUrl(server, '/api/v3'),\n          });\n\n          try {\n            await radarr.refreshMonitoredDownloads();\n            const queueItems = await radarr.getQueue();\n\n            this.radarrServers[server.id] = queueItems.map((item) => ({\n              externalId: item.movieId,\n              estimatedCompletionTime: new Date(item.estimatedCompletionTime),\n              mediaType: MediaType.MOVIE,\n              size: item.size,\n              sizeLeft: item.sizeleft,\n              status: item.status,\n              timeLeft: item.timeleft,\n              title: item.title,\n              downloadId: item.downloadId,\n            }));\n\n            if (queueItems.length > 0) {\n              logger.debug(\n                `Found ${queueItems.length} item(s) in progress on Radarr server: ${server.name}`,\n                { label: 'Download Tracker' }\n              );\n            }\n          } catch {\n            logger.error(\n              `Unable to get queue from Radarr server: ${server.name}`,\n              {\n                label: 'Download Tracker',\n              }\n            );\n          }\n\n          // Duplicate this data to matching servers\n          const matchingServers = settings.radarr.filter(\n            (rs) =>\n              rs.hostname === server.hostname &&\n              rs.port === server.port &&\n              rs.baseUrl === server.baseUrl &&\n              rs.id !== server.id\n          );\n\n          if (matchingServers.length > 0) {\n            logger.debug(\n              `Matching download data to ${matchingServers.length} other Radarr server(s)`,\n              { label: 'Download Tracker' }\n            );\n          }\n\n          matchingServers.forEach((ms) => {\n            if (ms.syncEnabled) {\n              this.radarrServers[ms.id] = this.radarrServers[server.id];\n            }\n          });\n        }\n      })\n    );\n  }\n\n  private async updateSonarrDownloads() {\n    const settings = getSettings();\n\n    // Remove duplicate servers\n    const filteredServers = uniqWith(settings.sonarr, (sonarrA, sonarrB) => {\n      return (\n        sonarrA.hostname === sonarrB.hostname &&\n        sonarrA.port === sonarrB.port &&\n        sonarrA.baseUrl === sonarrB.baseUrl\n      );\n    });\n\n    // Load downloads from Sonarr servers\n    Promise.all(\n      filteredServers.map(async (server) => {\n        if (server.syncEnabled) {\n          const sonarr = new SonarrAPI({\n            apiKey: server.apiKey,\n            url: SonarrAPI.buildUrl(server, '/api/v3'),\n          });\n\n          try {\n            await sonarr.refreshMonitoredDownloads();\n            const queueItems = await sonarr.getQueue();\n\n            this.sonarrServers[server.id] = queueItems.map((item) => ({\n              externalId: item.seriesId,\n              estimatedCompletionTime: new Date(item.estimatedCompletionTime),\n              mediaType: MediaType.TV,\n              size: item.size,\n              sizeLeft: item.sizeleft,\n              status: item.status,\n              timeLeft: item.timeleft,\n              title: item.title,\n              episode: item.episode,\n              downloadId: item.downloadId,\n            }));\n\n            if (queueItems.length > 0) {\n              logger.debug(\n                `Found ${queueItems.length} item(s) in progress on Sonarr server: ${server.name}`,\n                { label: 'Download Tracker' }\n              );\n            }\n          } catch {\n            logger.error(\n              `Unable to get queue from Sonarr server: ${server.name}`,\n              {\n                label: 'Download Tracker',\n              }\n            );\n          }\n\n          // Duplicate this data to matching servers\n          const matchingServers = settings.sonarr.filter(\n            (ss) =>\n              ss.hostname === server.hostname &&\n              ss.port === server.port &&\n              ss.baseUrl === server.baseUrl &&\n              ss.id !== server.id\n          );\n\n          if (matchingServers.length > 0) {\n            logger.debug(\n              `Matching download data to ${matchingServers.length} other Sonarr server(s)`,\n              { label: 'Download Tracker' }\n            );\n          }\n\n          matchingServers.forEach((ms) => {\n            if (ms.syncEnabled) {\n              this.sonarrServers[ms.id] = this.sonarrServers[server.id];\n            }\n          });\n        }\n      })\n    );\n  }\n}\n\nconst downloadTracker = new DownloadTracker();\n\nexport default downloadTracker;\n"
  },
  {
    "path": "server/lib/email/index.ts",
    "content": "import type { NotificationAgentEmail } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport Email from 'email-templates';\nimport nodemailer from 'nodemailer';\nimport { URL } from 'url';\nimport { openpgpEncrypt } from './openpgpEncrypt';\n\nclass PreparedEmail extends Email {\n  public constructor(settings: NotificationAgentEmail, pgpKey?: string) {\n    const { applicationUrl } = getSettings().main;\n\n    const transport = nodemailer.createTransport({\n      name: applicationUrl ? new URL(applicationUrl).hostname : undefined,\n      host: settings.options.smtpHost,\n      port: settings.options.smtpPort,\n      secure: settings.options.secure,\n      ignoreTLS: settings.options.ignoreTls,\n      requireTLS: settings.options.requireTls,\n      tls: settings.options.allowSelfSigned\n        ? {\n            rejectUnauthorized: false,\n          }\n        : undefined,\n      auth:\n        settings.options.authUser && settings.options.authPass\n          ? {\n              user: settings.options.authUser,\n              pass: settings.options.authPass,\n            }\n          : undefined,\n    });\n\n    if (pgpKey) {\n      transport.use(\n        'stream',\n        openpgpEncrypt({\n          signingKey: settings.options.pgpPrivateKey,\n          password: settings.options.pgpPassword,\n          encryptionKeys: [pgpKey],\n        })\n      );\n    }\n\n    super({\n      message: {\n        from: {\n          name: settings.options.senderName,\n          address: settings.options.emailFrom,\n        },\n      },\n      send: true,\n      transport: transport,\n      preview: false,\n    });\n  }\n}\n\nexport default PreparedEmail;\n"
  },
  {
    "path": "server/lib/email/openpgpEncrypt.ts",
    "content": "import logger from '@server/logger';\nimport { randomBytes } from 'crypto';\nimport * as openpgp from 'openpgp';\nimport type { TransformCallback } from 'stream';\nimport { Transform } from 'stream';\n\ninterface EncryptorOptions {\n  signingKey?: string;\n  password?: string;\n  encryptionKeys: string[];\n}\n\nclass PGPEncryptor extends Transform {\n  private _messageChunks: Uint8Array[] = [];\n  private _messageLength = 0;\n  private _signingKey?: string;\n  private _password?: string;\n\n  private _encryptionKeys: string[];\n\n  constructor(options: EncryptorOptions) {\n    super();\n    this._signingKey = options.signingKey;\n    this._password = options.password;\n    this._encryptionKeys = options.encryptionKeys;\n  }\n\n  // just save the whole message\n  _transform = (\n    chunk: Uint8Array,\n    _encoding: BufferEncoding,\n    callback: TransformCallback\n  ): void => {\n    this._messageChunks.push(chunk);\n    this._messageLength += chunk.length;\n    callback();\n  };\n\n  // Actually do stuff\n  _flush = async (callback: TransformCallback): Promise<void> => {\n    const message = Buffer.concat(this._messageChunks, this._messageLength);\n\n    try {\n      // Reconstruct message as buffer\n      const validPublicKeys = await Promise.all(\n        this._encryptionKeys.map((armoredKey) =>\n          openpgp.readKey({ armoredKey })\n        )\n      );\n      let privateKey: openpgp.PrivateKey | undefined;\n\n      // Just return the message if there is no one to encrypt for\n      if (!validPublicKeys.length) {\n        this.push(message);\n        return callback();\n      }\n\n      // Only sign the message if private key and password exist\n      if (this._signingKey && this._password) {\n        privateKey = await openpgp.decryptKey({\n          privateKey: await openpgp.readPrivateKey({\n            armoredKey: this._signingKey,\n          }),\n          passphrase: this._password,\n        });\n      }\n\n      const emailPartDelimiter = '\\r\\n\\r\\n';\n      const messageParts = message.toString().split(emailPartDelimiter);\n\n      /**\n       * In this loop original headers are split up into two parts,\n       * one for the email that is sent\n       * and one for the encrypted content\n       */\n      const header = messageParts.shift() as string;\n      const emailHeaders: string[][] = [];\n      const contentHeaders: string[][] = [];\n      const linesInHeader = header.split('\\r\\n');\n      let previousHeader: string[] = [];\n      for (let i = 0; i < linesInHeader.length; i++) {\n        const line = linesInHeader[i];\n\n        if (/^\\s/.test(line) || i === 0) {\n          previousHeader.push(line);\n        } else {\n          if (\n            /^(content-type|content-transfer-encoding):/i.test(\n              previousHeader[0]\n            )\n          ) {\n            contentHeaders.push(previousHeader);\n          } else {\n            emailHeaders.push(previousHeader);\n          }\n          previousHeader = [line];\n        }\n      }\n\n      if (previousHeader.length > 0) {\n        if (\n          /^(content-type|content-transfer-encoding):/i.test(previousHeader[0])\n        ) {\n          contentHeaders.push(previousHeader);\n        } else {\n          emailHeaders.push(previousHeader);\n        }\n      }\n\n      // Generate a new boundary for the email content\n      const boundary = 'nm_' + randomBytes(14).toString('hex');\n      /**\n       * Concatenate everything into single strings\n       * and add pgp headers to the email headers\n       */\n      const emailHeadersRaw =\n        emailHeaders.map((line) => line.join('\\r\\n')).join('\\r\\n') +\n        '\\r\\n' +\n        'Content-Type: multipart/encrypted; protocol=\"application/pgp-encrypted\";' +\n        '\\r\\n' +\n        ' boundary=\"' +\n        boundary +\n        '\"' +\n        '\\r\\n' +\n        'Content-Description: OpenPGP encrypted message' +\n        '\\r\\n' +\n        'Content-Transfer-Encoding: 7bit';\n      const contentHeadersRaw = contentHeaders\n        .map((line) => line.join('\\r\\n'))\n        .join('\\r\\n');\n\n      const encryptedMessage = await openpgp.encrypt({\n        message: await openpgp.createMessage({\n          text:\n            contentHeadersRaw +\n            emailPartDelimiter +\n            messageParts.join(emailPartDelimiter),\n        }),\n        encryptionKeys: validPublicKeys,\n        signingKeys: privateKey,\n      });\n\n      const body =\n        '--' +\n        boundary +\n        '\\r\\n' +\n        'Content-Type: application/pgp-encrypted\\r\\n' +\n        'Content-Transfer-Encoding: 7bit\\r\\n' +\n        '\\r\\n' +\n        'Version: 1\\r\\n' +\n        '\\r\\n' +\n        '--' +\n        boundary +\n        '\\r\\n' +\n        'Content-Type: application/octet-stream; name=encrypted.asc\\r\\n' +\n        'Content-Disposition: inline; filename=encrypted.asc\\r\\n' +\n        'Content-Transfer-Encoding: 7bit\\r\\n' +\n        '\\r\\n' +\n        encryptedMessage +\n        '\\r\\n--' +\n        boundary +\n        '--\\r\\n';\n\n      this.push(Buffer.from(emailHeadersRaw + emailPartDelimiter + body));\n      callback();\n    } catch (e) {\n      logger.error(\n        'Something went wrong while encrypting email message with OpenPGP. Sending email without encryption',\n        {\n          label: 'Notifications',\n          errorMessage: e.message,\n        }\n      );\n\n      this.push(message);\n      callback();\n    }\n  };\n}\n\nexport const openpgpEncrypt = (options: EncryptorOptions) => {\n  // Disabling this line because I don't want to fix it but I am tired\n  // of seeing the lint warning\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  return function (mail: any, callback: () => unknown): void {\n    if (!options.encryptionKeys.length) {\n      setImmediate(callback);\n    }\n    mail.message.transform(\n      () =>\n        new PGPEncryptor({\n          signingKey: options.signingKey,\n          password: options.password,\n          encryptionKeys: options.encryptionKeys,\n        })\n    );\n    setImmediate(callback);\n  };\n};\n"
  },
  {
    "path": "server/lib/imageproxy.ts",
    "content": "import logger from '@server/logger';\nimport { requestInterceptorFunction } from '@server/utils/customProxyAgent';\nimport axios from 'axios';\nimport rateLimit, { type rateLimitOptions } from 'axios-rate-limit';\nimport { createHash } from 'crypto';\nimport { promises } from 'fs';\nimport mime from 'mime/lite';\nimport path, { join } from 'path';\n\ntype ImageResponse = {\n  meta: {\n    revalidateAfter: number;\n    curRevalidate: number;\n    isStale: boolean;\n    etag: string;\n    extension: string | null;\n    cacheKey: string;\n    cacheMiss: boolean;\n  };\n  imageBuffer: Buffer;\n};\n\nconst baseCacheDirectory = process.env.CONFIG_DIRECTORY\n  ? `${process.env.CONFIG_DIRECTORY}/cache/images`\n  : path.join(__dirname, '../../config/cache/images');\n\nclass ImageProxy {\n  public static async clearCache(key: string) {\n    let deletedImages = 0;\n    const cacheDirectory = path.join(baseCacheDirectory, key);\n\n    try {\n      const files = await promises.readdir(cacheDirectory);\n\n      for (const file of files) {\n        const filePath = path.join(cacheDirectory, file);\n        const stat = await promises.lstat(filePath);\n\n        if (stat.isDirectory()) {\n          const imageFiles = await promises.readdir(filePath);\n\n          for (const imageFile of imageFiles) {\n            const [, expireAtSt] = imageFile.split('.');\n            const expireAt = Number(expireAtSt);\n            const now = Date.now();\n\n            if (now > expireAt) {\n              await promises.rm(path.join(filePath), {\n                recursive: true,\n              });\n              deletedImages += 1;\n            }\n          }\n        }\n      }\n    } catch (e) {\n      if (e.code === 'ENOENT') {\n        logger.error('Directory not found', {\n          label: 'Image Cache',\n          message: e.message,\n        });\n      } else {\n        logger.error('Failed to read directory', {\n          label: 'Image Cache',\n          message: e.message,\n        });\n      }\n    }\n\n    logger.info(`Cleared ${deletedImages} stale image(s) from cache '${key}'`, {\n      label: 'Image Cache',\n    });\n  }\n\n  public static async getImageStats(\n    key: string\n  ): Promise<{ size: number; imageCount: number }> {\n    const cacheDirectory = path.join(baseCacheDirectory, key);\n\n    const imageTotalSize = await ImageProxy.getDirectorySize(cacheDirectory);\n    const imageCount = await ImageProxy.getImageCount(cacheDirectory);\n\n    return {\n      size: imageTotalSize,\n      imageCount,\n    };\n  }\n\n  private static async getDirectorySize(dir: string): Promise<number> {\n    try {\n      const files = await promises.readdir(dir, {\n        withFileTypes: true,\n      });\n\n      const paths = files.map(async (file) => {\n        const path = join(dir, file.name);\n\n        if (file.isDirectory()) return await ImageProxy.getDirectorySize(path);\n\n        if (file.isFile()) {\n          const { size } = await promises.stat(path);\n\n          return size;\n        }\n\n        return 0;\n      });\n\n      return (await Promise.all(paths))\n        .flat(Infinity)\n        .reduce((i, size) => i + size, 0);\n    } catch (e) {\n      if (e.code === 'ENOENT') {\n        return 0;\n      }\n    }\n\n    return 0;\n  }\n\n  private static async getImageCount(dir: string) {\n    try {\n      const files = await promises.readdir(dir);\n\n      return files.length;\n    } catch (e) {\n      if (e.code === 'ENOENT') {\n        return 0;\n      }\n    }\n\n    return 0;\n  }\n\n  private axios;\n  private cacheVersion;\n  private key;\n\n  constructor(\n    key: string,\n    baseUrl: string,\n    options: {\n      cacheVersion?: number;\n      rateLimitOptions?: rateLimitOptions;\n      headers?: Record<string, string>;\n    } = {}\n  ) {\n    this.cacheVersion = options.cacheVersion ?? 1;\n    this.key = key;\n    this.axios = axios.create({\n      baseURL: baseUrl,\n      headers: options.headers,\n    });\n    this.axios.interceptors.request.use(requestInterceptorFunction);\n\n    if (options.rateLimitOptions) {\n      this.axios = rateLimit(this.axios, options.rateLimitOptions);\n    }\n  }\n\n  public async getImage(\n    path: string,\n    fallbackPath?: string\n  ): Promise<ImageResponse> {\n    const cacheKey = this.getCacheKey(path);\n\n    const imageResponse = await this.get(cacheKey);\n\n    if (!imageResponse) {\n      const newImage = await this.set(path, cacheKey);\n\n      if (!newImage) {\n        if (fallbackPath) {\n          return await this.getImage(fallbackPath);\n        } else {\n          throw new Error('Failed to load image');\n        }\n      }\n\n      return newImage;\n    }\n\n    // If the image is stale, we will revalidate it in the background.\n    if (imageResponse.meta.isStale) {\n      this.set(path, cacheKey);\n    }\n\n    return imageResponse;\n  }\n\n  public async clearCachedImage(path: string) {\n    // find cacheKey\n    const cacheKey = this.getCacheKey(path);\n    const directory = join(this.getCacheDirectory(), cacheKey);\n\n    try {\n      await promises.access(directory);\n    } catch (e) {\n      if (e.code === 'ENOENT') {\n        logger.debug(\n          `Cache directory '${cacheKey}' does not exist; nothing to clear.`,\n          {\n            label: 'Image Cache',\n          }\n        );\n        return;\n      } else {\n        logger.error('Error checking cache directory existence', {\n          label: 'Image Cache',\n          message: e.message,\n        });\n        return;\n      }\n    }\n\n    try {\n      const files = await promises.readdir(directory);\n\n      await promises.rm(directory, { recursive: true });\n\n      logger.debug(`Cleared ${files[0]} from cache 'avatar'`, {\n        label: 'Image Cache',\n      });\n    } catch (e) {\n      logger.error('Failed to clear cached image', {\n        label: 'Image Cache',\n        message: e.message,\n      });\n    }\n  }\n\n  private async get(cacheKey: string): Promise<ImageResponse | null> {\n    try {\n      const directory = join(this.getCacheDirectory(), cacheKey);\n      const files = await promises.readdir(directory);\n      const now = Date.now();\n\n      for (const file of files) {\n        const [maxAgeSt, expireAtSt, etag, extension] = file.split('.');\n        const buffer = await promises.readFile(join(directory, file));\n        const expireAt = Number(expireAtSt);\n        const maxAge = Number(maxAgeSt);\n\n        return {\n          meta: {\n            curRevalidate: maxAge,\n            revalidateAfter: maxAge * 1000 + now,\n            isStale: now > expireAt,\n            etag,\n            extension,\n            cacheKey,\n            cacheMiss: false,\n          },\n          imageBuffer: buffer,\n        };\n      }\n    } catch {\n      // No files. Treat as empty cache.\n    }\n\n    return null;\n  }\n\n  private async set(\n    path: string,\n    cacheKey: string\n  ): Promise<ImageResponse | null> {\n    try {\n      const directory = join(this.getCacheDirectory(), cacheKey);\n      const response = await this.axios.get(path, {\n        responseType: 'arraybuffer',\n      });\n\n      const buffer = Buffer.from(response.data, 'binary');\n\n      const contentType = response.headers['content-type'] || '';\n      const extension = mime.getExtension(contentType) || '';\n\n      let maxAge = Number(\n        (response.headers['cache-control'] ?? '0').split('=')[1]\n      );\n\n      if (!maxAge) maxAge = 86400;\n      const expireAt = Date.now() + maxAge * 1000;\n      const etag = (response.headers.etag ?? '').replace(/\"/g, '');\n\n      await this.writeToCacheDir(\n        directory,\n        extension,\n        maxAge,\n        expireAt,\n        buffer,\n        etag\n      );\n\n      return {\n        meta: {\n          curRevalidate: maxAge,\n          revalidateAfter: expireAt,\n          isStale: false,\n          etag,\n          extension,\n          cacheKey,\n          cacheMiss: true,\n        },\n        imageBuffer: buffer,\n      };\n    } catch (e) {\n      logger.debug('Something went wrong caching image.', {\n        label: 'Image Cache',\n        errorMessage: e.message,\n      });\n      return null;\n    }\n  }\n\n  private async writeToCacheDir(\n    dir: string,\n    extension: string | null,\n    maxAge: number,\n    expireAt: number,\n    buffer: Buffer,\n    etag: string\n  ) {\n    const filename = join(dir, `${maxAge}.${expireAt}.${etag}.${extension}`);\n\n    await promises.rm(dir, { force: true, recursive: true }).catch(() => {\n      // do nothing\n    });\n\n    await promises.mkdir(dir, { recursive: true });\n    await promises.writeFile(filename, buffer);\n  }\n\n  private getCacheKey(path: string) {\n    return this.getHash([this.key, this.cacheVersion, path]);\n  }\n\n  private getHash(items: (string | number | Buffer)[]) {\n    const hash = createHash('sha256');\n    for (const item of items) {\n      if (typeof item === 'number') hash.update(String(item));\n      else {\n        hash.update(item);\n      }\n    }\n    // See https://en.wikipedia.org/wiki/Base64#Filenames\n    return hash.digest('base64').replace(/\\//g, '-');\n  }\n\n  private getCacheDirectory() {\n    return path.join(baseCacheDirectory, this.key);\n  }\n}\n\nexport default ImageProxy;\n"
  },
  {
    "path": "server/lib/notifications/agents/agent.ts",
    "content": "import type Issue from '@server/entity/Issue';\nimport type IssueComment from '@server/entity/IssueComment';\nimport type Media from '@server/entity/Media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport type { User } from '@server/entity/User';\nimport type { NotificationAgentConfig } from '@server/lib/settings';\nimport type { Notification } from '..';\n\nexport interface NotificationPayload {\n  event?: string;\n  subject: string;\n  notifySystem: boolean;\n  notifyAdmin: boolean;\n  notifyUser?: User;\n  media?: Media;\n  image?: string;\n  message?: string;\n  extra?: { name: string; value: string }[];\n  request?: MediaRequest;\n  issue?: Issue;\n  comment?: IssueComment;\n  pendingRequestsCount?: number;\n  isAdmin?: boolean;\n}\n\nexport abstract class BaseAgent<T extends NotificationAgentConfig> {\n  protected settings?: T;\n  public constructor(settings?: T) {\n    this.settings = settings;\n  }\n\n  protected abstract getSettings(): T;\n}\n\nexport interface NotificationAgent {\n  shouldSend(): boolean;\n  send(type: Notification, payload: NotificationPayload): Promise<boolean>;\n}\n"
  },
  {
    "path": "server/lib/notifications/agents/discord.ts",
    "content": "import { IssueStatus, IssueTypeName } from '@server/constants/issue';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport type { NotificationAgentDiscord } from '@server/lib/settings';\nimport { NotificationAgentKey, getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport axios from 'axios';\nimport {\n  Notification,\n  hasNotificationType,\n  shouldSendAdminNotification,\n} from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\nenum EmbedColors {\n  DEFAULT = 0,\n  AQUA = 1752220,\n  GREEN = 3066993,\n  BLUE = 3447003,\n  PURPLE = 10181046,\n  GOLD = 15844367,\n  ORANGE = 15105570,\n  RED = 15158332,\n  GREY = 9807270,\n  DARKER_GREY = 8359053,\n  NAVY = 3426654,\n  DARK_AQUA = 1146986,\n  DARK_GREEN = 2067276,\n  DARK_BLUE = 2123412,\n  DARK_PURPLE = 7419530,\n  DARK_GOLD = 12745742,\n  DARK_ORANGE = 11027200,\n  DARK_RED = 10038562,\n  DARK_GREY = 9936031,\n  LIGHT_GREY = 12370112,\n  DARK_NAVY = 2899536,\n  LUMINOUS_VIVID_PINK = 16580705,\n  DARK_VIVID_PINK = 12320855,\n}\n\ninterface DiscordImageEmbed {\n  url?: string;\n  proxy_url?: string;\n  height?: number;\n  width?: number;\n}\n\ninterface Field {\n  name: string;\n  value: string;\n  inline?: boolean;\n}\ninterface DiscordRichEmbed {\n  title?: string;\n  type?: 'rich'; // Always rich for webhooks\n  description?: string;\n  url?: string;\n  timestamp?: string;\n  color?: number;\n  footer?: {\n    text: string;\n    icon_url?: string;\n    proxy_icon_url?: string;\n  };\n  image?: DiscordImageEmbed;\n  thumbnail?: DiscordImageEmbed;\n  provider?: {\n    name?: string;\n    url?: string;\n  };\n  author?: {\n    name?: string;\n    url?: string;\n    icon_url?: string;\n    proxy_icon_url?: string;\n  };\n  fields?: Field[];\n}\n\ninterface DiscordWebhookPayload {\n  embeds: DiscordRichEmbed[];\n  username?: string;\n  avatar_url?: string;\n  tts: boolean;\n  content?: string;\n  allowed_mentions?: {\n    parse?: ('users' | 'roles' | 'everyone')[];\n    roles?: string[];\n    users?: string[];\n  };\n}\n\nclass DiscordAgent\n  extends BaseAgent<NotificationAgentDiscord>\n  implements NotificationAgent\n{\n  protected getSettings(): NotificationAgentDiscord {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.discord;\n  }\n\n  public buildEmbed(\n    type: Notification,\n    payload: NotificationPayload\n  ): DiscordRichEmbed {\n    const settings = getSettings();\n    const { applicationUrl } = settings.main;\n    const { embedPoster } = settings.notifications.agents.discord;\n\n    const appUrl =\n      applicationUrl || `http://localhost:${process.env.port || 5055}`;\n    let color = EmbedColors.DARK_PURPLE;\n    const fields: Field[] = [];\n\n    if (payload.request) {\n      fields.push({\n        name: 'Requested By',\n        value: payload.request.requestedBy.displayName,\n        inline: true,\n      });\n\n      let status = '';\n      switch (type) {\n        case Notification.MEDIA_PENDING:\n          color = EmbedColors.ORANGE;\n          status = `[Pending Approval](${appUrl}/requests)`;\n          break;\n        case Notification.MEDIA_APPROVED:\n        case Notification.MEDIA_AUTO_APPROVED:\n          color = EmbedColors.PURPLE;\n          status = 'Processing';\n          break;\n        case Notification.MEDIA_AVAILABLE:\n          color = EmbedColors.GREEN;\n          status = 'Available';\n          break;\n        case Notification.MEDIA_DECLINED:\n          color = EmbedColors.RED;\n          status = 'Declined';\n          break;\n        case Notification.MEDIA_FAILED:\n          color = EmbedColors.RED;\n          status = 'Failed';\n          break;\n      }\n\n      if (status) {\n        fields.push({\n          name: 'Request Status',\n          value: status,\n          inline: true,\n        });\n      }\n    } else if (payload.comment) {\n      fields.push({\n        name: `Comment from ${payload.comment.user.displayName}`,\n        value: payload.comment.message,\n        inline: false,\n      });\n    } else if (payload.issue) {\n      fields.push(\n        {\n          name: 'Reported By',\n          value: payload.issue.createdBy.displayName,\n          inline: true,\n        },\n        {\n          name: 'Issue Type',\n          value: IssueTypeName[payload.issue.issueType],\n          inline: true,\n        },\n        {\n          name: 'Issue Status',\n          value:\n            payload.issue.status === IssueStatus.OPEN ? 'Open' : 'Resolved',\n          inline: true,\n        }\n      );\n\n      switch (type) {\n        case Notification.ISSUE_CREATED:\n        case Notification.ISSUE_REOPENED:\n          color = EmbedColors.RED;\n          break;\n        case Notification.ISSUE_COMMENT:\n          color = EmbedColors.ORANGE;\n          break;\n        case Notification.ISSUE_RESOLVED:\n          color = EmbedColors.GREEN;\n          break;\n      }\n    }\n\n    for (const extra of payload.extra ?? []) {\n      fields.push({\n        name: extra.name,\n        value: extra.value,\n        inline: true,\n      });\n    }\n\n    const url = applicationUrl\n      ? payload.issue\n        ? `${applicationUrl}/issues/${payload.issue.id}`\n        : payload.media\n          ? `${applicationUrl}/${payload.media.mediaType}/${payload.media.tmdbId}`\n          : undefined\n      : undefined;\n\n    return {\n      title: payload.event\n        ? `${payload.event}: ${payload.subject}`\n        : payload.subject,\n      url,\n      description: payload.message,\n      color,\n      timestamp: new Date().toISOString(),\n      fields,\n      thumbnail: embedPoster\n        ? {\n            url: payload.image,\n          }\n        : undefined,\n    };\n  }\n\n  public shouldSend(): boolean {\n    const settings = this.getSettings();\n\n    if (settings.enabled && settings.options.webhookUrl) {\n      return true;\n    }\n\n    return false;\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    const settings = this.getSettings();\n\n    if (\n      !payload.notifySystem ||\n      !hasNotificationType(type, settings.types ?? 0)\n    ) {\n      return true;\n    }\n\n    logger.debug('Sending Discord notification', {\n      label: 'Notifications',\n      type: Notification[type],\n      subject: payload.subject,\n    });\n\n    const userMentions: string[] = [];\n\n    try {\n      if (settings.options.enableMentions) {\n        if (payload.notifyUser) {\n          if (\n            payload.notifyUser.settings?.hasNotificationType(\n              NotificationAgentKey.DISCORD,\n              type\n            ) &&\n            payload.notifyUser.settings.discordId\n          ) {\n            userMentions.push(`<@${payload.notifyUser.settings.discordId}>`);\n          }\n        }\n\n        if (payload.notifyAdmin) {\n          const userRepository = getRepository(User);\n          const users = await userRepository.find();\n\n          userMentions.push(\n            ...users\n              .filter(\n                (user) =>\n                  user.settings?.hasNotificationType(\n                    NotificationAgentKey.DISCORD,\n                    type\n                  ) &&\n                  user.settings.discordId &&\n                  shouldSendAdminNotification(type, user, payload)\n              )\n              .map((user) => `<@${user.settings?.discordId}>`)\n          );\n        }\n      }\n\n      if (settings.options.webhookRoleId) {\n        userMentions.push(`<@&${settings.options.webhookRoleId}>`);\n      }\n\n      await axios.post(settings.options.webhookUrl, {\n        username: settings.options.botUsername\n          ? settings.options.botUsername\n          : getSettings().main.applicationTitle,\n        avatar_url: settings.options.botAvatarUrl,\n        embeds: [this.buildEmbed(type, payload)],\n        content: userMentions.join(' '),\n      } as DiscordWebhookPayload);\n\n      return true;\n    } catch (e) {\n      logger.error('Error sending Discord notification', {\n        label: 'Notifications',\n        type: Notification[type],\n        subject: payload.subject,\n        errorMessage: e.message,\n        response: e?.response?.data,\n      });\n\n      return false;\n    }\n  }\n}\n\nexport default DiscordAgent;\n"
  },
  {
    "path": "server/lib/notifications/agents/email.ts",
    "content": "import { IssueType, IssueTypeName } from '@server/constants/issue';\nimport { MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport PreparedEmail from '@server/lib/email';\nimport type { NotificationAgentEmail } from '@server/lib/settings';\nimport { NotificationAgentKey, getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport type { EmailOptions } from 'email-templates';\nimport path from 'path';\nimport validator from 'validator';\nimport { Notification, shouldSendAdminNotification } from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\nclass EmailAgent\n  extends BaseAgent<NotificationAgentEmail>\n  implements NotificationAgent\n{\n  protected getSettings(): NotificationAgentEmail {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.email;\n  }\n\n  public shouldSend(): boolean {\n    const settings = this.getSettings();\n\n    if (\n      settings.enabled &&\n      settings.options.emailFrom &&\n      settings.options.smtpHost &&\n      settings.options.smtpPort\n    ) {\n      return true;\n    }\n\n    return false;\n  }\n\n  private buildMessage(\n    type: Notification,\n    payload: NotificationPayload,\n    recipientEmail: string,\n    recipientName?: string\n  ): EmailOptions | undefined {\n    const settings = getSettings();\n    const { applicationUrl, applicationTitle } = settings.main;\n    const { embedPoster } = settings.notifications.agents.email;\n\n    if (type === Notification.TEST_NOTIFICATION) {\n      return {\n        template: path.join(__dirname, '../../../templates/email/test-email'),\n        message: {\n          to: recipientEmail,\n        },\n        locals: {\n          body: payload.message,\n          applicationUrl,\n          applicationTitle,\n          recipientName,\n          recipientEmail,\n        },\n      };\n    }\n\n    const mediaType = payload.media\n      ? payload.media.mediaType === MediaType.MOVIE\n        ? 'movie'\n        : 'series'\n      : undefined;\n    const is4k = payload.request?.is4k;\n\n    if (payload.request) {\n      let body = '';\n\n      switch (type) {\n        case Notification.MEDIA_PENDING:\n          body = `A new request for the following ${mediaType} ${\n            is4k ? 'in 4K ' : ''\n          }is pending approval:`;\n          break;\n        case Notification.MEDIA_AUTO_REQUESTED:\n          body = `A new request for the following ${mediaType} ${\n            is4k ? 'in 4K ' : ''\n          }was automatically submitted:`;\n          break;\n        case Notification.MEDIA_APPROVED:\n          body = `Your request for the following ${mediaType} ${\n            is4k ? 'in 4K ' : ''\n          }has been approved:`;\n          break;\n        case Notification.MEDIA_AUTO_APPROVED:\n          body = `A new request for the following ${mediaType} ${\n            is4k ? 'in 4K ' : ''\n          }has been automatically approved:`;\n          break;\n        case Notification.MEDIA_AVAILABLE:\n          body = `Your request for the following ${mediaType} ${\n            is4k ? 'in 4K ' : ''\n          }is now available:`;\n          break;\n        case Notification.MEDIA_DECLINED:\n          body = `Your request for the following ${mediaType} ${\n            is4k ? 'in 4K ' : ''\n          }was declined:`;\n          break;\n        case Notification.MEDIA_FAILED:\n          body = `A request for the following ${mediaType} ${\n            is4k ? 'in 4K ' : ''\n          }failed to be added to ${\n            payload.media?.mediaType === MediaType.MOVIE ? 'Radarr' : 'Sonarr'\n          }:`;\n          break;\n      }\n\n      return {\n        template: path.join(\n          __dirname,\n          '../../../templates/email/media-request'\n        ),\n        message: {\n          to: recipientEmail,\n        },\n        locals: {\n          event: payload.event,\n          body,\n          mediaName: payload.subject,\n          mediaExtra: payload.extra ?? [],\n          imageUrl: embedPoster ? payload.image : undefined,\n          timestamp: new Date().toTimeString(),\n          requestedBy: payload.request.requestedBy.displayName,\n          actionUrl: applicationUrl\n            ? `${applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}`\n            : undefined,\n          applicationUrl,\n          applicationTitle,\n          recipientName,\n          recipientEmail,\n        },\n      };\n    } else if (payload.issue) {\n      const issueType =\n        payload.issue && payload.issue.issueType !== IssueType.OTHER\n          ? `${IssueTypeName[payload.issue.issueType].toLowerCase()} issue`\n          : 'issue';\n\n      let body = '';\n\n      switch (type) {\n        case Notification.ISSUE_CREATED:\n          body = `A new ${issueType} has been reported by ${payload.issue.createdBy.displayName} for the ${mediaType} ${payload.subject}:`;\n          break;\n        case Notification.ISSUE_COMMENT:\n          body = `${payload.comment?.user.displayName} commented on the ${issueType} for the ${mediaType} ${payload.subject}:`;\n          break;\n        case Notification.ISSUE_RESOLVED:\n          body = `The ${issueType} for the ${mediaType} ${payload.subject} was marked as resolved by ${payload.issue.modifiedBy?.displayName}!`;\n          break;\n        case Notification.ISSUE_REOPENED:\n          body = `The ${issueType} for the ${mediaType} ${payload.subject} was reopened by ${payload.issue.modifiedBy?.displayName}.`;\n          break;\n      }\n\n      return {\n        template: path.join(__dirname, '../../../templates/email/media-issue'),\n        message: {\n          to: recipientEmail,\n        },\n        locals: {\n          event: payload.event,\n          body,\n          issueDescription: payload.message,\n          issueComment: payload.comment?.message,\n          mediaName: payload.subject,\n          extra: payload.extra ?? [],\n          imageUrl: embedPoster ? payload.image : undefined,\n          timestamp: new Date().toTimeString(),\n          actionUrl: applicationUrl\n            ? `${applicationUrl}/issues/${payload.issue.id}`\n            : undefined,\n          applicationUrl,\n          applicationTitle,\n          recipientName,\n          recipientEmail,\n        },\n      };\n    }\n\n    return undefined;\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    if (payload.notifyUser) {\n      if (\n        !payload.notifyUser.settings ||\n        // Check if user has email notifications enabled and fallback to true if undefined\n        // since email should default to true\n        (payload.notifyUser.settings.hasNotificationType(\n          NotificationAgentKey.EMAIL,\n          type\n        ) ??\n          true)\n      ) {\n        logger.debug('Sending email notification', {\n          label: 'Notifications',\n          recipient: payload.notifyUser.displayName,\n          type: Notification[type],\n          subject: payload.subject,\n        });\n\n        try {\n          const email = new PreparedEmail(\n            this.getSettings(),\n            payload.notifyUser.settings?.pgpKey\n          );\n          if (\n            validator.isEmail(payload.notifyUser.email, { require_tld: false })\n          ) {\n            await email.send(\n              this.buildMessage(\n                type,\n                payload,\n                payload.notifyUser.email,\n                payload.notifyUser.displayName\n              )\n            );\n          } else {\n            logger.warn('Invalid email address provided for user', {\n              label: 'Notifications',\n              recipient: payload.notifyUser.displayName,\n              type: Notification[type],\n              subject: payload.subject,\n            });\n          }\n        } catch (e) {\n          logger.error('Error sending email notification', {\n            label: 'Notifications',\n            recipient: payload.notifyUser.displayName,\n            type: Notification[type],\n            subject: payload.subject,\n            errorMessage: e.message,\n          });\n\n          return false;\n        }\n      }\n    }\n\n    if (payload.notifyAdmin) {\n      const userRepository = getRepository(User);\n      const users = await userRepository.find();\n\n      await Promise.all(\n        users\n          .filter(\n            (user) =>\n              (!user.settings ||\n                // Check if user has email notifications enabled and fallback to true if undefined\n                // since email should default to true\n                (user.settings.hasNotificationType(\n                  NotificationAgentKey.EMAIL,\n                  type\n                ) ??\n                  true)) &&\n              shouldSendAdminNotification(type, user, payload)\n          )\n          .map(async (user) => {\n            logger.debug('Sending email notification', {\n              label: 'Notifications',\n              recipient: user.displayName,\n              type: Notification[type],\n              subject: payload.subject,\n            });\n\n            try {\n              const email = new PreparedEmail(\n                this.getSettings(),\n                user.settings?.pgpKey\n              );\n              if (validator.isEmail(user.email, { require_tld: false })) {\n                await email.send(\n                  this.buildMessage(type, payload, user.email, user.displayName)\n                );\n              } else {\n                logger.warn('Invalid email address provided for user', {\n                  label: 'Notifications',\n                  recipient: user.displayName,\n                  type: Notification[type],\n                  subject: payload.subject,\n                });\n              }\n            } catch (e) {\n              logger.error('Error sending email notification', {\n                label: 'Notifications',\n                recipient: user.displayName,\n                type: Notification[type],\n                subject: payload.subject,\n                errorMessage: e.message,\n              });\n\n              return false;\n            }\n          })\n      );\n    }\n\n    return true;\n  }\n}\n\nexport default EmailAgent;\n"
  },
  {
    "path": "server/lib/notifications/agents/gotify.ts",
    "content": "import { IssueStatus, IssueTypeName } from '@server/constants/issue';\nimport type { NotificationAgentGotify } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport axios from 'axios';\nimport { Notification, hasNotificationType } from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\ninterface GotifyPayload {\n  title: string;\n  message: string;\n  priority: number;\n  extras: Record<string, unknown>;\n}\n\nclass GotifyAgent\n  extends BaseAgent<NotificationAgentGotify>\n  implements NotificationAgent\n{\n  protected getSettings(): NotificationAgentGotify {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.gotify;\n  }\n\n  public shouldSend(): boolean {\n    const settings = this.getSettings();\n\n    if (\n      settings.enabled &&\n      settings.options.url &&\n      settings.options.token &&\n      settings.options.priority !== undefined\n    ) {\n      return true;\n    }\n\n    return false;\n  }\n\n  private getNotificationPayload(\n    type: Notification,\n    payload: NotificationPayload\n  ): GotifyPayload {\n    const { applicationUrl, applicationTitle } = getSettings().main;\n    const settings = this.getSettings();\n    const priority = settings.options.priority ?? 1;\n\n    const title = payload.event\n      ? `${payload.event} - ${payload.subject}`\n      : payload.subject;\n\n    let message = payload.message ? `${payload.message}  \\n\\n` : '';\n\n    if (payload.request) {\n      message += `\\n**Requested By:** ${payload.request.requestedBy.displayName}  `;\n\n      let status = '';\n      switch (type) {\n        case Notification.MEDIA_PENDING:\n          status = 'Pending Approval';\n          break;\n        case Notification.MEDIA_APPROVED:\n        case Notification.MEDIA_AUTO_APPROVED:\n          status = 'Processing';\n          break;\n        case Notification.MEDIA_AVAILABLE:\n          status = 'Available';\n          break;\n        case Notification.MEDIA_DECLINED:\n          status = 'Declined';\n          break;\n        case Notification.MEDIA_FAILED:\n          status = 'Failed';\n          break;\n      }\n\n      if (status) {\n        message += `\\n**Request Status:** ${status}  `;\n      }\n    } else if (payload.comment) {\n      message += `\\nComment from ${payload.comment.user.displayName}:\\n${payload.comment.message}  `;\n    } else if (payload.issue) {\n      message += `\\n\\n**Reported By:** ${payload.issue.createdBy.displayName}  `;\n      message += `\\n**Issue Type:** ${\n        IssueTypeName[payload.issue.issueType]\n      }  `;\n      message += `\\n**Issue Status:** ${\n        payload.issue.status === IssueStatus.OPEN ? 'Open' : 'Resolved'\n      }  `;\n    }\n\n    for (const extra of payload.extra ?? []) {\n      message += `\\n\\n**${extra.name}**\\n${extra.value}  `;\n    }\n\n    if (applicationUrl && payload.media) {\n      const actionUrl = `${applicationUrl}/${payload.media.mediaType}/${payload.media.tmdbId}`;\n      const displayUrl =\n        actionUrl.length > 40 ? `${actionUrl.slice(0, 41)}...` : actionUrl;\n      message += `\\n\\n**Open in ${applicationTitle}:** [${displayUrl}](${actionUrl})  `;\n    }\n\n    return {\n      extras: {\n        'client::display': {\n          contentType: 'text/markdown',\n        },\n      },\n      title,\n      message,\n      priority,\n    };\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    const settings = this.getSettings();\n\n    if (\n      !payload.notifySystem ||\n      !hasNotificationType(type, settings.types ?? 0)\n    ) {\n      return true;\n    }\n\n    logger.debug('Sending Gotify notification', {\n      label: 'Notifications',\n      type: Notification[type],\n      subject: payload.subject,\n    });\n    try {\n      const endpoint = `${settings.options.url}/message?token=${settings.options.token}`;\n      const notificationPayload = this.getNotificationPayload(type, payload);\n\n      await axios.post(endpoint, notificationPayload);\n\n      return true;\n    } catch (e) {\n      logger.error('Error sending Gotify notification', {\n        label: 'Notifications',\n        type: Notification[type],\n        subject: payload.subject,\n        errorMessage: e.message,\n        response: e?.response?.data,\n      });\n\n      return false;\n    }\n  }\n}\n\nexport default GotifyAgent;\n"
  },
  {
    "path": "server/lib/notifications/agents/ntfy.ts",
    "content": "import { IssueStatus, IssueTypeName } from '@server/constants/issue';\nimport type { NotificationAgentNtfy } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport axios from 'axios';\nimport { Notification, hasNotificationType } from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\nclass NtfyAgent\n  extends BaseAgent<NotificationAgentNtfy>\n  implements NotificationAgent\n{\n  protected getSettings(): NotificationAgentNtfy {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.ntfy;\n  }\n\n  private buildPayload(type: Notification, payload: NotificationPayload) {\n    const settings = getSettings();\n    const { applicationUrl } = settings.main;\n    const { embedPoster } = settings.notifications.agents.ntfy;\n\n    const topic = this.getSettings().options.topic;\n    const priority = this.getSettings().options.priority ?? 3;\n\n    const title = payload.event\n      ? `${payload.event} - ${payload.subject}`\n      : payload.subject;\n    let message = payload.message ?? '';\n\n    if (payload.request) {\n      message += `\\n\\nRequested By: ${payload.request.requestedBy.displayName}`;\n\n      let status = '';\n      switch (type) {\n        case Notification.MEDIA_PENDING:\n          status = 'Pending Approval';\n          break;\n        case Notification.MEDIA_APPROVED:\n        case Notification.MEDIA_AUTO_APPROVED:\n          status = 'Processing';\n          break;\n        case Notification.MEDIA_AVAILABLE:\n          status = 'Available';\n          break;\n        case Notification.MEDIA_DECLINED:\n          status = 'Declined';\n          break;\n        case Notification.MEDIA_FAILED:\n          status = 'Failed';\n          break;\n      }\n\n      if (status) {\n        message += `\\nRequest Status: ${status}`;\n      }\n    } else if (payload.comment) {\n      message += `\\nComment from ${payload.comment.user.displayName}:\\n${payload.comment.message}`;\n    } else if (payload.issue) {\n      message += `\\n\\nReported By: ${payload.issue.createdBy.displayName}`;\n      message += `\\nIssue Type: ${IssueTypeName[payload.issue.issueType]}`;\n      message += `\\nIssue Status: ${\n        payload.issue.status === IssueStatus.OPEN ? 'Open' : 'Resolved'\n      }`;\n    }\n\n    for (const extra of payload.extra ?? []) {\n      message += `\\n\\n**${extra.name}**\\n${extra.value}`;\n    }\n\n    const attach = embedPoster ? payload.image : undefined;\n\n    let click;\n    if (applicationUrl && payload.media) {\n      click = `${applicationUrl}/${payload.media.mediaType}/${payload.media.tmdbId}`;\n    }\n\n    return {\n      topic,\n      priority,\n      title,\n      message,\n      attach,\n      click,\n    };\n  }\n\n  public shouldSend(): boolean {\n    const settings = this.getSettings();\n\n    if (settings.enabled && settings.options.url && settings.options.topic) {\n      return true;\n    }\n\n    return false;\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    const settings = this.getSettings();\n\n    if (\n      !payload.notifySystem ||\n      !hasNotificationType(type, settings.types ?? 0)\n    ) {\n      return true;\n    }\n\n    logger.debug('Sending ntfy notification', {\n      label: 'Notifications',\n      type: Notification[type],\n      subject: payload.subject,\n    });\n\n    try {\n      let authHeader;\n      if (\n        settings.options.authMethodUsernamePassword &&\n        settings.options.username &&\n        settings.options.password\n      ) {\n        const encodedAuth = Buffer.from(\n          `${settings.options.username}:${settings.options.password}`\n        ).toString('base64');\n\n        authHeader = `Basic ${encodedAuth}`;\n      } else if (settings.options.authMethodToken) {\n        authHeader = `Bearer ${settings.options.token}`;\n      }\n\n      await axios.post(\n        settings.options.url,\n        this.buildPayload(type, payload),\n        authHeader\n          ? {\n              headers: {\n                Authorization: authHeader,\n              },\n            }\n          : undefined\n      );\n\n      return true;\n    } catch (e) {\n      logger.error('Error sending ntfy notification', {\n        label: 'Notifications',\n        type: Notification[type],\n        subject: payload.subject,\n        errorMessage: e.message,\n        response: e?.response?.data,\n      });\n\n      return false;\n    }\n  }\n}\n\nexport default NtfyAgent;\n"
  },
  {
    "path": "server/lib/notifications/agents/pushbullet.ts",
    "content": "import { IssueStatus, IssueTypeName } from '@server/constants/issue';\nimport { MediaStatus } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport type { NotificationAgentPushbullet } from '@server/lib/settings';\nimport { NotificationAgentKey, getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport axios from 'axios';\nimport {\n  Notification,\n  hasNotificationType,\n  shouldSendAdminNotification,\n} from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\ninterface PushbulletPayload {\n  type: string;\n  title: string;\n  body: string;\n  channel_tag?: string;\n}\n\nclass PushbulletAgent\n  extends BaseAgent<NotificationAgentPushbullet>\n  implements NotificationAgent\n{\n  protected getSettings(): NotificationAgentPushbullet {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.pushbullet;\n  }\n\n  public shouldSend(): boolean {\n    return true;\n  }\n\n  private getNotificationPayload(\n    type: Notification,\n    payload: NotificationPayload\n  ): PushbulletPayload {\n    const title = payload.event\n      ? `${payload.event} - ${payload.subject}`\n      : payload.subject;\n    let body = payload.message ?? '';\n\n    if (payload.request) {\n      body += `\\n\\nRequested By: ${payload.request.requestedBy.displayName}`;\n\n      let status = '';\n      switch (type) {\n        case Notification.MEDIA_AUTO_REQUESTED:\n          status =\n            payload.media?.status === MediaStatus.PENDING\n              ? 'Pending Approval'\n              : 'Processing';\n          break;\n        case Notification.MEDIA_PENDING:\n          status = 'Pending Approval';\n          break;\n        case Notification.MEDIA_APPROVED:\n        case Notification.MEDIA_AUTO_APPROVED:\n          status = 'Processing';\n          break;\n        case Notification.MEDIA_AVAILABLE:\n          status = 'Available';\n          break;\n        case Notification.MEDIA_DECLINED:\n          status = 'Declined';\n          break;\n        case Notification.MEDIA_FAILED:\n          status = 'Failed';\n          break;\n      }\n\n      if (status) {\n        body += `\\nRequest Status: ${status}`;\n      }\n    } else if (payload.comment) {\n      body += `\\n\\nComment from ${payload.comment.user.displayName}:\\n${payload.comment.message}`;\n    } else if (payload.issue) {\n      body += `\\n\\nReported By: ${payload.issue.createdBy.displayName}`;\n      body += `\\nIssue Type: ${IssueTypeName[payload.issue.issueType]}`;\n      body += `\\nIssue Status: ${\n        payload.issue.status === IssueStatus.OPEN ? 'Open' : 'Resolved'\n      }`;\n    }\n\n    for (const extra of payload.extra ?? []) {\n      body += `\\n${extra.name}: ${extra.value}`;\n    }\n\n    return {\n      type: 'note',\n      title,\n      body,\n    };\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    const settings = this.getSettings();\n    const endpoint = 'https://api.pushbullet.com/v2/pushes';\n    const notificationPayload = this.getNotificationPayload(type, payload);\n\n    // Send system notification\n    if (\n      payload.notifySystem &&\n      hasNotificationType(type, settings.types ?? 0) &&\n      settings.enabled &&\n      settings.options.accessToken\n    ) {\n      logger.debug('Sending Pushbullet notification', {\n        label: 'Notifications',\n        type: Notification[type],\n        subject: payload.subject,\n      });\n\n      try {\n        await axios.post(\n          endpoint,\n          { ...notificationPayload, channel_tag: settings.options.channelTag },\n          {\n            headers: {\n              'Access-Token': settings.options.accessToken,\n            },\n          }\n        );\n      } catch (e) {\n        logger.error('Error sending Pushbullet notification', {\n          label: 'Notifications',\n          type: Notification[type],\n          subject: payload.subject,\n          errorMessage: e.message,\n          response: e.response?.data,\n        });\n\n        return false;\n      }\n    }\n\n    if (payload.notifyUser) {\n      if (\n        payload.notifyUser.settings?.hasNotificationType(\n          NotificationAgentKey.PUSHBULLET,\n          type\n        ) &&\n        payload.notifyUser.settings?.pushbulletAccessToken &&\n        payload.notifyUser.settings.pushbulletAccessToken !==\n          settings.options.accessToken\n      ) {\n        logger.debug('Sending Pushbullet notification', {\n          label: 'Notifications',\n          recipient: payload.notifyUser.displayName,\n          type: Notification[type],\n          subject: payload.subject,\n        });\n\n        try {\n          await axios.post(endpoint, notificationPayload, {\n            headers: {\n              'Access-Token': payload.notifyUser.settings.pushbulletAccessToken,\n            },\n          });\n        } catch (e) {\n          logger.error('Error sending Pushbullet notification', {\n            label: 'Notifications',\n            recipient: payload.notifyUser.displayName,\n            type: Notification[type],\n            subject: payload.subject,\n            errorMessage: e.message,\n            response: e.response?.data,\n          });\n\n          return false;\n        }\n      }\n    }\n\n    if (payload.notifyAdmin) {\n      const userRepository = getRepository(User);\n      const users = await userRepository.find();\n\n      await Promise.all(\n        users\n          .filter(\n            (user) =>\n              user.settings?.hasNotificationType(\n                NotificationAgentKey.PUSHBULLET,\n                type\n              ) && shouldSendAdminNotification(type, user, payload)\n          )\n          .map(async (user) => {\n            if (\n              user.settings?.pushbulletAccessToken &&\n              (settings.options.channelTag ||\n                user.settings.pushbulletAccessToken !==\n                  settings.options.accessToken)\n            ) {\n              logger.debug('Sending Pushbullet notification', {\n                label: 'Notifications',\n                recipient: user.displayName,\n                type: Notification[type],\n                subject: payload.subject,\n              });\n\n              try {\n                await axios.post(endpoint, notificationPayload, {\n                  headers: {\n                    'Access-Token': user.settings.pushbulletAccessToken,\n                  },\n                });\n              } catch (e) {\n                logger.error('Error sending Pushbullet notification', {\n                  label: 'Notifications',\n                  recipient: user.displayName,\n                  type: Notification[type],\n                  subject: payload.subject,\n                  errorMessage: e.message,\n                  response: e.response?.data,\n                });\n\n                return false;\n              }\n            }\n          })\n      );\n    }\n\n    return true;\n  }\n}\n\nexport default PushbulletAgent;\n"
  },
  {
    "path": "server/lib/notifications/agents/pushover.ts",
    "content": "import { IssueStatus, IssueTypeName } from '@server/constants/issue';\nimport { MediaStatus } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport type { NotificationAgentPushover } from '@server/lib/settings';\nimport { NotificationAgentKey, getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport axios from 'axios';\nimport {\n  Notification,\n  hasNotificationType,\n  shouldSendAdminNotification,\n} from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\ninterface PushoverImagePayload {\n  attachment_base64: string;\n  attachment_type: string;\n}\n\ninterface PushoverPayload extends PushoverImagePayload {\n  token: string;\n  user: string;\n  title: string;\n  message: string;\n  url: string;\n  url_title: string;\n  priority: number;\n  html: number;\n}\n\nclass PushoverAgent\n  extends BaseAgent<NotificationAgentPushover>\n  implements NotificationAgent\n{\n  protected getSettings(): NotificationAgentPushover {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.pushover;\n  }\n\n  public shouldSend(): boolean {\n    const settings = this.getSettings();\n\n    if (\n      settings.enabled &&\n      settings.options.accessToken &&\n      settings.options.userToken\n    ) {\n      return true;\n    }\n\n    return false;\n  }\n\n  private async getImagePayload(\n    imageUrl: string\n  ): Promise<Partial<PushoverImagePayload>> {\n    try {\n      const response = await axios.get(imageUrl, {\n        responseType: 'arraybuffer',\n      });\n      const base64 = Buffer.from(response.data, 'binary').toString('base64');\n      const contentType = (\n        response.headers['Content-Type'] || response.headers['content-type']\n      )?.toString();\n\n      return {\n        attachment_base64: base64,\n        attachment_type: contentType,\n      };\n    } catch (e) {\n      logger.error('Error getting image payload', {\n        label: 'Notifications',\n        errorMessage: e.message,\n        response: e.response?.data,\n      });\n      return {};\n    }\n  }\n\n  private async getNotificationPayload(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<Partial<PushoverPayload>> {\n    const settings = getSettings();\n    const { applicationUrl, applicationTitle } = settings.main;\n    const { embedPoster } = settings.notifications.agents.pushover;\n\n    const title = payload.event ?? payload.subject;\n    let message = payload.event ? `<b>${payload.subject}</b>` : '';\n    let priority = 0;\n\n    if (payload.message) {\n      message += `<small>${message ? '\\n' : ''}${payload.message}</small>`;\n    }\n\n    if (payload.request) {\n      message += `<small>\\n\\n<b>Requested By:</b> ${payload.request.requestedBy.displayName}</small>`;\n\n      let status = '';\n      switch (type) {\n        case Notification.MEDIA_AUTO_REQUESTED:\n          status =\n            payload.media?.status === MediaStatus.PENDING\n              ? 'Pending Approval'\n              : 'Processing';\n          break;\n        case Notification.MEDIA_PENDING:\n          status = 'Pending Approval';\n          break;\n        case Notification.MEDIA_APPROVED:\n        case Notification.MEDIA_AUTO_APPROVED:\n          status = 'Processing';\n          break;\n        case Notification.MEDIA_AVAILABLE:\n          status = 'Available';\n          break;\n        case Notification.MEDIA_DECLINED:\n          status = 'Declined';\n          priority = 1;\n          break;\n        case Notification.MEDIA_FAILED:\n          status = 'Failed';\n          priority = 1;\n          break;\n      }\n\n      if (status) {\n        message += `<small>\\n<b>Request Status:</b> ${status}</small>`;\n      }\n    } else if (payload.comment) {\n      message += `<small>\\n\\n<b>Comment from ${payload.comment.user.displayName}:</b> ${payload.comment.message}</small>`;\n    } else if (payload.issue) {\n      message += `<small>\\n\\n<b>Reported By:</b> ${payload.issue.createdBy.displayName}</small>`;\n      message += `<small>\\n<b>Issue Type:</b> ${\n        IssueTypeName[payload.issue.issueType]\n      }</small>`;\n      message += `<small>\\n<b>Issue Status:</b> ${\n        payload.issue.status === IssueStatus.OPEN ? 'Open' : 'Resolved'\n      }</small>`;\n\n      if (type === Notification.ISSUE_CREATED) {\n        priority = 1;\n      }\n    }\n\n    for (const extra of payload.extra ?? []) {\n      message += `<small>\\n<b>${extra.name}:</b> ${extra.value}</small>`;\n    }\n\n    const url = applicationUrl\n      ? payload.issue\n        ? `${applicationUrl}/issues/${payload.issue.id}`\n        : payload.media\n          ? `${applicationUrl}/${payload.media.mediaType}/${payload.media.tmdbId}`\n          : undefined\n      : undefined;\n    const url_title = url\n      ? `View ${payload.issue ? 'Issue' : 'Media'} in ${applicationTitle}`\n      : undefined;\n\n    let attachment_base64;\n    let attachment_type;\n    if (embedPoster && payload.image) {\n      const imagePayload = await this.getImagePayload(payload.image);\n      if (imagePayload.attachment_base64 && imagePayload.attachment_type) {\n        attachment_base64 = imagePayload.attachment_base64;\n        attachment_type = imagePayload.attachment_type;\n      }\n    }\n\n    return {\n      title,\n      message,\n      url,\n      url_title,\n      priority,\n      html: 1,\n      attachment_base64,\n      attachment_type,\n    };\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    const settings = this.getSettings();\n    const endpoint = 'https://api.pushover.net/1/messages.json';\n    const notificationPayload = await this.getNotificationPayload(\n      type,\n      payload\n    );\n\n    // Send system notification\n    if (\n      payload.notifySystem &&\n      hasNotificationType(type, settings.types ?? 0) &&\n      settings.enabled &&\n      settings.options.accessToken &&\n      settings.options.userToken\n    ) {\n      logger.debug('Sending Pushover notification', {\n        label: 'Notifications',\n        type: Notification[type],\n        subject: payload.subject,\n      });\n\n      try {\n        await axios.post(endpoint, {\n          ...notificationPayload,\n          token: settings.options.accessToken,\n          user: settings.options.userToken,\n          sound: settings.options.sound,\n        } as PushoverPayload);\n      } catch (e) {\n        logger.error('Error sending Pushover notification', {\n          label: 'Notifications',\n          type: Notification[type],\n          subject: payload.subject,\n          errorMessage: e.message,\n          response: e.response?.data,\n        });\n\n        return false;\n      }\n    }\n\n    if (payload.notifyUser) {\n      if (\n        payload.notifyUser.settings?.hasNotificationType(\n          NotificationAgentKey.PUSHOVER,\n          type\n        ) &&\n        payload.notifyUser.settings.pushoverApplicationToken &&\n        payload.notifyUser.settings.pushoverUserKey &&\n        (payload.notifyUser.settings.pushoverApplicationToken !==\n          settings.options.accessToken ||\n          payload.notifyUser.settings.pushoverUserKey !==\n            settings.options.userToken)\n      ) {\n        logger.debug('Sending Pushover notification', {\n          label: 'Notifications',\n          recipient: payload.notifyUser.displayName,\n          type: Notification[type],\n          subject: payload.subject,\n        });\n\n        try {\n          await axios.post(endpoint, {\n            ...notificationPayload,\n            token: payload.notifyUser.settings.pushoverApplicationToken,\n            user: payload.notifyUser.settings.pushoverUserKey,\n            sound: payload.notifyUser.settings.pushoverSound,\n          } as PushoverPayload);\n        } catch (e) {\n          logger.error('Error sending Pushover notification', {\n            label: 'Notifications',\n            recipient: payload.notifyUser.displayName,\n            type: Notification[type],\n            subject: payload.subject,\n            errorMessage: e.message,\n            response: e.response?.data,\n          });\n\n          return false;\n        }\n      }\n    }\n\n    if (payload.notifyAdmin) {\n      const userRepository = getRepository(User);\n      const users = await userRepository.find();\n\n      await Promise.all(\n        users\n          .filter(\n            (user) =>\n              user.settings?.hasNotificationType(\n                NotificationAgentKey.PUSHOVER,\n                type\n              ) && shouldSendAdminNotification(type, user, payload)\n          )\n          .map(async (user) => {\n            if (\n              user.settings?.pushoverApplicationToken &&\n              user.settings?.pushoverUserKey &&\n              user.settings.pushoverApplicationToken !==\n                settings.options.accessToken &&\n              user.settings.pushoverUserKey !== settings.options.userToken\n            ) {\n              logger.debug('Sending Pushover notification', {\n                label: 'Notifications',\n                recipient: user.displayName,\n                type: Notification[type],\n                subject: payload.subject,\n              });\n\n              try {\n                await axios.post(endpoint, {\n                  ...notificationPayload,\n                  token: user.settings.pushoverApplicationToken,\n                  user: user.settings.pushoverUserKey,\n                } as PushoverPayload);\n              } catch (e) {\n                logger.error('Error sending Pushover notification', {\n                  label: 'Notifications',\n                  recipient: user.displayName,\n                  type: Notification[type],\n                  subject: payload.subject,\n                  errorMessage: e.message,\n                  response: e.response?.data,\n                });\n\n                return false;\n              }\n            }\n          })\n      );\n    }\n\n    return true;\n  }\n}\n\nexport default PushoverAgent;\n"
  },
  {
    "path": "server/lib/notifications/agents/slack.ts",
    "content": "import { IssueStatus, IssueTypeName } from '@server/constants/issue';\nimport type { NotificationAgentSlack } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport axios from 'axios';\nimport { Notification, hasNotificationType } from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\ninterface EmbedField {\n  type: 'plain_text' | 'mrkdwn';\n  text: string;\n}\n\ninterface TextItem {\n  type: 'plain_text' | 'mrkdwn';\n  text: string;\n  emoji?: boolean;\n}\n\ninterface Element {\n  type: 'button';\n  text?: TextItem;\n  action_id: string;\n  url?: string;\n  value?: string;\n  style?: 'primary' | 'danger';\n}\n\ninterface EmbedBlock {\n  type: 'header' | 'actions' | 'section' | 'context';\n  block_id?: 'section789';\n  text?: TextItem;\n  fields?: EmbedField[];\n  accessory?: {\n    type: 'image';\n    image_url: string;\n    alt_text: string;\n  };\n  elements?: (Element | TextItem)[];\n}\n\ninterface SlackBlockEmbed {\n  text: string;\n  blocks: EmbedBlock[];\n}\n\nclass SlackAgent\n  extends BaseAgent<NotificationAgentSlack>\n  implements NotificationAgent\n{\n  protected getSettings(): NotificationAgentSlack {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.slack;\n  }\n\n  public buildEmbed(\n    type: Notification,\n    payload: NotificationPayload\n  ): SlackBlockEmbed {\n    const settings = getSettings();\n    const { applicationUrl, applicationTitle } = settings.main;\n    const { embedPoster } = settings.notifications.agents.slack;\n\n    const fields: EmbedField[] = [];\n\n    if (payload.request) {\n      fields.push({\n        type: 'mrkdwn',\n        text: `*Requested By*\\n${payload.request.requestedBy.displayName}`,\n      });\n\n      let status = '';\n      switch (type) {\n        case Notification.MEDIA_PENDING:\n          status = 'Pending Approval';\n          break;\n        case Notification.MEDIA_APPROVED:\n        case Notification.MEDIA_AUTO_APPROVED:\n          status = 'Processing';\n          break;\n        case Notification.MEDIA_AVAILABLE:\n          status = 'Available';\n          break;\n        case Notification.MEDIA_DECLINED:\n          status = 'Declined';\n          break;\n        case Notification.MEDIA_FAILED:\n          status = 'Failed';\n          break;\n      }\n\n      if (status) {\n        fields.push({\n          type: 'mrkdwn',\n          text: `*Request Status*\\n${status}`,\n        });\n      }\n    } else if (payload.comment) {\n      fields.push({\n        type: 'mrkdwn',\n        text: `*Comment from ${payload.comment.user.displayName}*\\n${payload.comment.message}`,\n      });\n    } else if (payload.issue) {\n      fields.push(\n        {\n          type: 'mrkdwn',\n          text: `*Reported By*\\n${payload.issue.createdBy.displayName}`,\n        },\n        {\n          type: 'mrkdwn',\n          text: `*Issue Type*\\n${IssueTypeName[payload.issue.issueType]}`,\n        },\n        {\n          type: 'mrkdwn',\n          text: `*Issue Status*\\n${\n            payload.issue.status === IssueStatus.OPEN ? 'Open' : 'Resolved'\n          }`,\n        }\n      );\n    }\n\n    for (const extra of payload.extra ?? []) {\n      fields.push({\n        type: 'mrkdwn',\n        text: `*${extra.name}*\\n${extra.value}`,\n      });\n    }\n\n    const blocks: EmbedBlock[] = [];\n\n    if (payload.event) {\n      blocks.push({\n        type: 'context',\n        elements: [\n          {\n            type: 'mrkdwn',\n            text: `*${payload.event}*`,\n          },\n        ],\n      });\n    }\n\n    blocks.push({\n      type: 'header',\n      text: {\n        type: 'plain_text',\n        text: payload.subject,\n      },\n    });\n\n    if (payload.message) {\n      blocks.push({\n        type: 'section',\n        text: {\n          type: 'mrkdwn',\n          text: payload.message,\n        },\n        accessory:\n          embedPoster && payload.image\n            ? {\n                type: 'image',\n                image_url: payload.image,\n                alt_text: payload.subject,\n              }\n            : undefined,\n      });\n    }\n\n    if (fields.length > 0) {\n      blocks.push({\n        type: 'section',\n        fields,\n      });\n    }\n\n    const url = applicationUrl\n      ? payload.issue\n        ? `${applicationUrl}/issues/${payload.issue.id}`\n        : payload.media\n          ? `${applicationUrl}/${payload.media.mediaType}/${payload.media.tmdbId}`\n          : undefined\n      : undefined;\n\n    if (url) {\n      blocks.push({\n        type: 'actions',\n        elements: [\n          {\n            action_id: 'open-in-seerr',\n            type: 'button',\n            url,\n            text: {\n              type: 'plain_text',\n              text: `View ${\n                payload.issue ? 'Issue' : 'Media'\n              } in ${applicationTitle}`,\n            },\n          },\n        ],\n      });\n    }\n\n    return {\n      text: payload.event ?? payload.subject,\n      blocks,\n    };\n  }\n\n  public shouldSend(): boolean {\n    const settings = this.getSettings();\n\n    if (settings.enabled && settings.options.webhookUrl) {\n      return true;\n    }\n\n    return false;\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    const settings = this.getSettings();\n\n    if (\n      !payload.notifySystem ||\n      !hasNotificationType(type, settings.types ?? 0)\n    ) {\n      return true;\n    }\n\n    logger.debug('Sending Slack notification', {\n      label: 'Notifications',\n      type: Notification[type],\n      subject: payload.subject,\n    });\n    try {\n      await axios.post(\n        settings.options.webhookUrl,\n        this.buildEmbed(type, payload)\n      );\n\n      return true;\n    } catch (e) {\n      logger.error('Error sending Slack notification', {\n        label: 'Notifications',\n        type: Notification[type],\n        subject: payload.subject,\n        errorMessage: e.message,\n        response: e?.response?.data,\n      });\n\n      return false;\n    }\n  }\n}\n\nexport default SlackAgent;\n"
  },
  {
    "path": "server/lib/notifications/agents/telegram.ts",
    "content": "import { IssueStatus, IssueTypeName } from '@server/constants/issue';\nimport { MediaStatus } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport type { NotificationAgentTelegram } from '@server/lib/settings';\nimport { NotificationAgentKey, getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport axios from 'axios';\nimport {\n  Notification,\n  hasNotificationType,\n  shouldSendAdminNotification,\n} from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\ninterface TelegramMessagePayload {\n  text: string;\n  parse_mode: string;\n  chat_id: string;\n  message_thread_id: string;\n  disable_notification: boolean;\n}\n\ninterface TelegramPhotoPayload {\n  photo: string;\n  caption: string;\n  parse_mode: string;\n  chat_id: string;\n  message_thread_id: string;\n  disable_notification: boolean;\n}\n\nclass TelegramAgent\n  extends BaseAgent<NotificationAgentTelegram>\n  implements NotificationAgent\n{\n  private baseUrl = 'https://api.telegram.org/';\n\n  protected getSettings(): NotificationAgentTelegram {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.telegram;\n  }\n\n  public shouldSend(): boolean {\n    const settings = this.getSettings();\n\n    if (settings.enabled && settings.options.botAPI) {\n      return true;\n    }\n\n    return false;\n  }\n\n  private escapeText(text: string | undefined): string {\n    return text ? text.replace(/[_*[\\]()~>#+=|{}.!-]/gi, (x) => '\\\\' + x) : '';\n  }\n\n  private getNotificationPayload(\n    type: Notification,\n    payload: NotificationPayload\n  ): Partial<TelegramMessagePayload | TelegramPhotoPayload> {\n    const settings = getSettings();\n    const { applicationUrl, applicationTitle } = settings.main;\n    const { embedPoster } = settings.notifications.agents.telegram;\n\n    /* eslint-disable no-useless-escape */\n    let message = `\\*${this.escapeText(\n      payload.event ? `${payload.event} - ${payload.subject}` : payload.subject\n    )}\\*`;\n    if (payload.message) {\n      message += `\\n${this.escapeText(payload.message)}`;\n    }\n\n    if (payload.request) {\n      message += `\\n\\n\\*Requested By:\\* ${this.escapeText(\n        payload.request?.requestedBy.displayName\n      )}`;\n\n      let status = '';\n      switch (type) {\n        case Notification.MEDIA_AUTO_REQUESTED:\n          status =\n            payload.media?.status === MediaStatus.PENDING\n              ? 'Pending Approval'\n              : 'Processing';\n          break;\n        case Notification.MEDIA_PENDING:\n          status = 'Pending Approval';\n          break;\n        case Notification.MEDIA_APPROVED:\n        case Notification.MEDIA_AUTO_APPROVED:\n          status = 'Processing';\n          break;\n        case Notification.MEDIA_AVAILABLE:\n          status = 'Available';\n          break;\n        case Notification.MEDIA_DECLINED:\n          status = 'Declined';\n          break;\n        case Notification.MEDIA_FAILED:\n          status = 'Failed';\n          break;\n      }\n\n      if (status) {\n        message += `\\n\\*Request Status:\\* ${status}`;\n      }\n    } else if (payload.comment) {\n      message += `\\n\\n\\*Comment from ${this.escapeText(\n        payload.comment.user.displayName\n      )}:\\* ${this.escapeText(payload.comment.message)}`;\n    } else if (payload.issue) {\n      message += `\\n\\n\\*Reported By:\\* ${this.escapeText(\n        payload.issue.createdBy.displayName\n      )}`;\n      message += `\\n\\*Issue Type:\\* ${IssueTypeName[payload.issue.issueType]}`;\n      message += `\\n\\*Issue Status:\\* ${\n        payload.issue.status === IssueStatus.OPEN ? 'Open' : 'Resolved'\n      }`;\n    }\n\n    for (const extra of payload.extra ?? []) {\n      message += `\\n\\*${extra.name}:\\* ${extra.value}`;\n    }\n\n    const url = applicationUrl\n      ? payload.issue\n        ? `${applicationUrl}/issues/${payload.issue.id}`\n        : payload.media\n          ? `${applicationUrl}/${payload.media.mediaType}/${payload.media.tmdbId}`\n          : undefined\n      : undefined;\n\n    if (url) {\n      message += `\\n\\n\\[View ${\n        payload.issue ? 'Issue' : 'Media'\n      } in ${this.escapeText(applicationTitle)}\\]\\(${url}\\)`;\n    }\n    /* eslint-enable */\n\n    return embedPoster && payload.image\n      ? {\n          photo: payload.image,\n          caption: message,\n          parse_mode: 'MarkdownV2',\n        }\n      : {\n          text: message,\n          parse_mode: 'MarkdownV2',\n        };\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    const settings = this.getSettings();\n    const endpoint = `${this.baseUrl}bot${settings.options.botAPI}/${\n      settings.embedPoster && payload.image ? 'sendPhoto' : 'sendMessage'\n    }`;\n    const notificationPayload = this.getNotificationPayload(type, payload);\n\n    // Send system notification\n    if (\n      payload.notifySystem &&\n      hasNotificationType(type, settings.types ?? 0) &&\n      settings.options.chatId\n    ) {\n      logger.debug('Sending Telegram notification', {\n        label: 'Notifications',\n        type: Notification[type],\n        subject: payload.subject,\n      });\n\n      try {\n        await axios.post(endpoint, {\n          ...notificationPayload,\n          chat_id: settings.options.chatId,\n          message_thread_id: settings.options.messageThreadId,\n          disable_notification: !!settings.options.sendSilently,\n        } as TelegramMessagePayload | TelegramPhotoPayload);\n      } catch (e) {\n        logger.error('Error sending Telegram notification', {\n          label: 'Notifications',\n          type: Notification[type],\n          subject: payload.subject,\n          errorMessage: e.message,\n          response: e?.response?.data,\n        });\n\n        return false;\n      }\n    }\n\n    if (payload.notifyUser) {\n      if (\n        payload.notifyUser.settings?.hasNotificationType(\n          NotificationAgentKey.TELEGRAM,\n          type\n        ) &&\n        payload.notifyUser.settings?.telegramChatId &&\n        payload.notifyUser.settings.telegramChatId !== settings.options.chatId\n      ) {\n        logger.debug('Sending Telegram notification', {\n          label: 'Notifications',\n          recipient: payload.notifyUser.displayName,\n          type: Notification[type],\n          subject: payload.subject,\n        });\n\n        try {\n          await axios.post(endpoint, {\n            ...notificationPayload,\n            chat_id: payload.notifyUser.settings.telegramChatId,\n            message_thread_id:\n              payload.notifyUser.settings.telegramMessageThreadId,\n            disable_notification:\n              !!payload.notifyUser.settings.telegramSendSilently,\n          } as TelegramMessagePayload | TelegramPhotoPayload);\n        } catch (e) {\n          logger.error('Error sending Telegram notification', {\n            label: 'Notifications',\n            recipient: payload.notifyUser.displayName,\n            type: Notification[type],\n            subject: payload.subject,\n            errorMessage: e.message,\n            response: e?.response?.data,\n          });\n\n          return false;\n        }\n      }\n    }\n\n    if (payload.notifyAdmin) {\n      const userRepository = getRepository(User);\n      const users = await userRepository.find();\n\n      await Promise.all(\n        users\n          .filter(\n            (user) =>\n              user.settings?.hasNotificationType(\n                NotificationAgentKey.TELEGRAM,\n                type\n              ) && shouldSendAdminNotification(type, user, payload)\n          )\n          .map(async (user) => {\n            if (\n              user.settings?.telegramChatId &&\n              user.settings.telegramChatId !== settings.options.chatId\n            ) {\n              logger.debug('Sending Telegram notification', {\n                label: 'Notifications',\n                recipient: user.displayName,\n                type: Notification[type],\n                subject: payload.subject,\n              });\n\n              try {\n                await axios.post(endpoint, {\n                  ...notificationPayload,\n                  chat_id: user.settings.telegramChatId,\n                  message_thread_id: user.settings.telegramMessageThreadId,\n                  disable_notification: !!user.settings?.telegramSendSilently,\n                } as TelegramMessagePayload | TelegramPhotoPayload);\n              } catch (e) {\n                logger.error('Error sending Telegram notification', {\n                  label: 'Notifications',\n                  recipient: user.displayName,\n                  type: Notification[type],\n                  subject: payload.subject,\n                  errorMessage: e.message,\n                  response: e?.response?.data,\n                });\n\n                return false;\n              }\n            }\n          })\n      );\n    }\n\n    return true;\n  }\n}\n\nexport default TelegramAgent;\n"
  },
  {
    "path": "server/lib/notifications/agents/webhook.ts",
    "content": "import { IssueStatus, IssueType } from '@server/constants/issue';\nimport { MediaStatus } from '@server/constants/media';\nimport type { NotificationAgentWebhook } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport axios from 'axios';\nimport { get } from 'lodash';\nimport { Notification, hasNotificationType } from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\ntype KeyMapFunction = (\n  payload: NotificationPayload,\n  type: Notification\n) => string;\n\nconst KeyMap: Record<string, string | KeyMapFunction> = {\n  notification_type: (_payload, type) => Notification[type],\n  event: 'event',\n  subject: 'subject',\n  message: 'message',\n  image: 'image',\n  notifyuser_username: 'notifyUser.displayName',\n  notifyuser_email: 'notifyUser.email',\n  notifyuser_avatar: 'notifyUser.avatar',\n  notifyuser_settings_discordId: 'notifyUser.settings.discordId',\n  notifyuser_settings_telegramChatId: 'notifyUser.settings.telegramChatId',\n  media_tmdbid: 'media.tmdbId',\n  media_tvdbid: 'media.tvdbId',\n  media_type: 'media.mediaType',\n  media_jellyfinMediaId: (payload) =>\n    payload.media?.jellyfinMediaId ?? payload.media?.jellyfinMediaId4k ?? '',\n  media_status: (payload) =>\n    payload.media ? MediaStatus[payload.media.status] : '',\n  media_status4k: (payload) =>\n    payload.media ? MediaStatus[payload.media.status4k] : '',\n  request_id: 'request.id',\n  requestedBy_jellyfinUserId: 'request.requestedBy.jellyfinUserId',\n  requestedBy_username: 'request.requestedBy.displayName',\n  requestedBy_email: 'request.requestedBy.email',\n  requestedBy_avatar: 'request.requestedBy.avatar',\n  requestedBy_settings_discordId: 'request.requestedBy.settings.discordId',\n  requestedBy_settings_telegramChatId:\n    'request.requestedBy.settings.telegramChatId',\n  issue_id: 'issue.id',\n  issue_type: (payload) =>\n    payload.issue ? IssueType[payload.issue.issueType] : '',\n  issue_status: (payload) =>\n    payload.issue ? IssueStatus[payload.issue.status] : '',\n  reportedBy_username: 'issue.createdBy.displayName',\n  reportedBy_email: 'issue.createdBy.email',\n  reportedBy_avatar: 'issue.createdBy.avatar',\n  reportedBy_settings_discordId: 'issue.createdBy.settings.discordId',\n  reportedBy_settings_telegramChatId: 'issue.createdBy.settings.telegramChatId',\n  comment_message: 'comment.message',\n  commentedBy_username: 'comment.user.displayName',\n  commentedBy_email: 'comment.user.email',\n  commentedBy_avatar: 'comment.user.avatar',\n  commentedBy_settings_discordId: 'comment.user.settings.discordId',\n  commentedBy_settings_telegramChatId: 'comment.user.settings.telegramChatId',\n};\n\nclass WebhookAgent\n  extends BaseAgent<NotificationAgentWebhook>\n  implements NotificationAgent\n{\n  protected getSettings(): NotificationAgentWebhook {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.webhook;\n  }\n\n  private parseKeys(\n    finalPayload: Record<string, unknown>,\n    payload: NotificationPayload,\n    type: Notification\n  ): Record<string, unknown> {\n    Object.keys(finalPayload).forEach((key) => {\n      if (key === '{{extra}}') {\n        finalPayload.extra = payload.extra ?? [];\n        delete finalPayload[key];\n        key = 'extra';\n      } else if (key === '{{media}}') {\n        if (payload.media) {\n          finalPayload.media = finalPayload[key];\n        } else {\n          finalPayload.media = null;\n        }\n        delete finalPayload[key];\n        key = 'media';\n      } else if (key === '{{request}}') {\n        if (payload.request) {\n          finalPayload.request = finalPayload[key];\n        } else {\n          finalPayload.request = null;\n        }\n        delete finalPayload[key];\n        key = 'request';\n      } else if (key === '{{issue}}') {\n        if (payload.issue) {\n          finalPayload.issue = finalPayload[key];\n        } else {\n          finalPayload.issue = null;\n        }\n        delete finalPayload[key];\n        key = 'issue';\n      } else if (key === '{{comment}}') {\n        if (payload.comment) {\n          finalPayload.comment = finalPayload[key];\n        } else {\n          finalPayload.comment = null;\n        }\n        delete finalPayload[key];\n        key = 'comment';\n      }\n\n      if (typeof finalPayload[key] === 'string') {\n        Object.keys(KeyMap).forEach((keymapKey) => {\n          const keymapValue = KeyMap[keymapKey as keyof typeof KeyMap];\n          finalPayload[key] = (finalPayload[key] as string).replace(\n            `{{${keymapKey}}}`,\n            typeof keymapValue === 'function'\n              ? keymapValue(payload, type)\n              : (get(payload, keymapValue) ?? '')\n          );\n        });\n      } else if (finalPayload[key] && typeof finalPayload[key] === 'object') {\n        finalPayload[key] = this.parseKeys(\n          finalPayload[key] as Record<string, unknown>,\n          payload,\n          type\n        );\n      }\n    });\n\n    return finalPayload;\n  }\n\n  private buildPayload(type: Notification, payload: NotificationPayload) {\n    const payloadString = Buffer.from(\n      this.getSettings().options.jsonPayload,\n      'base64'\n    ).toString('utf8');\n\n    const parsedJSON = JSON.parse(JSON.parse(payloadString));\n\n    return this.parseKeys(parsedJSON, payload, type);\n  }\n\n  public shouldSend(): boolean {\n    const settings = this.getSettings();\n\n    if (settings.enabled && settings.options.webhookUrl) {\n      return true;\n    }\n\n    return false;\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    const settings = this.getSettings();\n\n    if (\n      !payload.notifySystem ||\n      !hasNotificationType(type, settings.types ?? 0)\n    ) {\n      return true;\n    }\n\n    logger.debug('Sending webhook notification', {\n      label: 'Notifications',\n      type: Notification[type],\n      subject: payload.subject,\n    });\n\n    let webhookUrl = settings.options.webhookUrl;\n\n    if (settings.options.supportVariables) {\n      Object.keys(KeyMap).forEach((keymapKey) => {\n        const keymapValue = KeyMap[keymapKey as keyof typeof KeyMap];\n        const variableValue =\n          type === Notification.TEST_NOTIFICATION\n            ? 'test'\n            : typeof keymapValue === 'function'\n              ? keymapValue(payload, type)\n              : get(payload, keymapValue) || 'test';\n        webhookUrl = webhookUrl.replace(\n          new RegExp(`{{${keymapKey}}}`, 'g'),\n          encodeURIComponent(variableValue)\n        );\n      });\n    }\n\n    try {\n      const headers: Record<string, string> = {};\n\n      if (settings.options.authHeader) {\n        headers.Authorization = settings.options.authHeader;\n      }\n\n      if (\n        settings.options.customHeaders &&\n        settings.options.customHeaders.length > 0\n      ) {\n        settings.options.customHeaders.forEach((header) => {\n          const key = header.key?.trim();\n          const value = header.value?.trim();\n\n          if (key && value) {\n            // Don't override Authorization header if it's already set via authHeader\n            if (\n              key.toLowerCase() !== 'authorization' ||\n              !settings.options.authHeader\n            ) {\n              headers[key] = value;\n            }\n          }\n        });\n      }\n\n      await axios.post(\n        webhookUrl,\n        this.buildPayload(type, payload),\n        Object.keys(headers).length > 0 ? { headers } : undefined\n      );\n\n      return true;\n    } catch (e) {\n      logger.error('Error sending webhook notification', {\n        label: 'Notifications',\n        type: Notification[type],\n        subject: payload.subject,\n        errorMessage: e.message,\n        response: e?.response?.data,\n      });\n\n      return false;\n    }\n  }\n}\n\nexport default WebhookAgent;\n"
  },
  {
    "path": "server/lib/notifications/agents/webpush.ts",
    "content": "import { IssueType, IssueTypeName } from '@server/constants/issue';\nimport { MediaRequestStatus, MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport MediaRequest from '@server/entity/MediaRequest';\nimport { User } from '@server/entity/User';\nimport { UserPushSubscription } from '@server/entity/UserPushSubscription';\nimport type { NotificationAgentConfig } from '@server/lib/settings';\nimport { NotificationAgentKey, getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport webpush from 'web-push';\nimport { Notification, shouldSendAdminNotification } from '..';\nimport type { NotificationAgent, NotificationPayload } from './agent';\nimport { BaseAgent } from './agent';\n\ninterface PushNotificationPayload {\n  notificationType: string;\n  subject: string;\n  message?: string;\n  image?: string;\n  actionUrl?: string;\n  actionUrlTitle?: string;\n  requestId?: number;\n  pendingRequestsCount?: number;\n  isAdmin?: boolean;\n}\n\ninterface WebPushError extends Error {\n  statusCode?: number;\n  status?: number;\n  body?: string | unknown;\n  response?: {\n    body?: string | unknown;\n  };\n}\n\nclass WebPushAgent\n  extends BaseAgent<NotificationAgentConfig>\n  implements NotificationAgent\n{\n  protected getSettings(): NotificationAgentConfig {\n    if (this.settings) {\n      return this.settings;\n    }\n\n    const settings = getSettings();\n\n    return settings.notifications.agents.webpush;\n  }\n\n  private getNotificationPayload(\n    type: Notification,\n    payload: NotificationPayload\n  ): PushNotificationPayload {\n    const { embedPoster } = getSettings().notifications.agents.webpush;\n\n    const mediaType = payload.media\n      ? payload.media.mediaType === MediaType.MOVIE\n        ? 'movie'\n        : 'series'\n      : undefined;\n    const is4k = payload.request?.is4k;\n\n    const issueType = payload.issue\n      ? payload.issue.issueType !== IssueType.OTHER\n        ? `${IssueTypeName[payload.issue.issueType].toLowerCase()} issue`\n        : 'issue'\n      : undefined;\n\n    let message: string | undefined;\n    switch (type) {\n      case Notification.TEST_NOTIFICATION:\n        message = payload.message;\n        break;\n      case Notification.MEDIA_AUTO_REQUESTED:\n        message = `Automatically submitted a new ${\n          is4k ? '4K ' : ''\n        }${mediaType} request.`;\n        break;\n      case Notification.MEDIA_APPROVED:\n        message = `Your ${\n          is4k ? '4K ' : ''\n        }${mediaType} request has been approved.`;\n        break;\n      case Notification.MEDIA_AUTO_APPROVED:\n        message = `Automatically approved a new ${\n          is4k ? '4K ' : ''\n        }${mediaType} request from ${\n          payload.request?.requestedBy.displayName\n        }.`;\n        break;\n      case Notification.MEDIA_AVAILABLE:\n        message = `Your ${\n          is4k ? '4K ' : ''\n        }${mediaType} request is now available!`;\n        break;\n      case Notification.MEDIA_DECLINED:\n        message = `Your ${is4k ? '4K ' : ''}${mediaType} request was declined.`;\n        break;\n      case Notification.MEDIA_FAILED:\n        message = `Failed to process ${is4k ? '4K ' : ''}${mediaType} request.`;\n        break;\n      case Notification.MEDIA_PENDING:\n        message = `Approval required for a new ${\n          is4k ? '4K ' : ''\n        }${mediaType} request from ${\n          payload.request?.requestedBy.displayName\n        }.`;\n        break;\n      case Notification.ISSUE_CREATED:\n        message = `A new ${issueType} was reported by ${payload.issue?.createdBy.displayName}.`;\n        break;\n      case Notification.ISSUE_COMMENT:\n        message = `${payload.comment?.user.displayName} commented on the ${issueType}.`;\n        break;\n      case Notification.ISSUE_RESOLVED:\n        message = `The ${issueType} was marked as resolved by ${payload.issue?.modifiedBy?.displayName}!`;\n        break;\n      case Notification.ISSUE_REOPENED:\n        message = `The ${issueType} was reopened by ${payload.issue?.modifiedBy?.displayName}.`;\n        break;\n      default:\n        return {\n          notificationType: Notification[type],\n          subject: 'Unknown',\n        };\n    }\n\n    const actionUrl = payload.issue\n      ? `/issues/${payload.issue.id}`\n      : payload.media\n        ? `/${payload.media.mediaType}/${payload.media.tmdbId}`\n        : undefined;\n\n    const actionUrlTitle = actionUrl\n      ? `View ${payload.issue ? 'Issue' : 'Media'}`\n      : undefined;\n\n    return {\n      notificationType: Notification[type],\n      subject: payload.subject,\n      message,\n      image: embedPoster ? payload.image : undefined,\n      requestId: payload.request?.id,\n      actionUrl,\n      actionUrlTitle,\n      pendingRequestsCount: payload.pendingRequestsCount,\n      isAdmin: payload.isAdmin,\n    };\n  }\n\n  public shouldSend(): boolean {\n    if (this.getSettings().enabled) {\n      return true;\n    }\n\n    return false;\n  }\n\n  public async send(\n    type: Notification,\n    payload: NotificationPayload\n  ): Promise<boolean> {\n    const userRepository = getRepository(User);\n    const userPushSubRepository = getRepository(UserPushSubscription);\n    const settings = getSettings();\n\n    const pushSubs: UserPushSubscription[] = [];\n\n    const mainUser = await userRepository.findOne({ where: { id: 1 } });\n\n    const requestRepository = getRepository(MediaRequest);\n\n    const pendingRequests = await requestRepository.find({\n      where: { status: MediaRequestStatus.PENDING },\n    });\n\n    const webPushNotification = async (\n      pushSub: UserPushSubscription,\n      notificationPayload: Buffer\n    ) => {\n      logger.debug('Sending web push notification', {\n        label: 'Notifications',\n        recipient: pushSub.user.displayName,\n        type: Notification[type],\n        subject: payload.subject,\n      });\n\n      try {\n        await webpush.sendNotification(\n          {\n            endpoint: pushSub.endpoint,\n            keys: {\n              auth: pushSub.auth,\n              p256dh: pushSub.p256dh,\n            },\n          },\n          notificationPayload\n        );\n      } catch (e) {\n        const webPushError = e as WebPushError;\n        const statusCode = webPushError.statusCode || webPushError.status;\n        const errorMessage = webPushError.message || String(e);\n\n        // RFC 8030: 410/404 are permanent failures, others are transient\n        const isPermanentFailure = statusCode === 410 || statusCode === 404;\n\n        logger.error(\n          isPermanentFailure\n            ? 'Error sending web push notification; removing invalid subscription'\n            : 'Error sending web push notification (transient error, keeping subscription)',\n          {\n            label: 'Notifications',\n            recipient: pushSub.user.displayName,\n            type: Notification[type],\n            subject: payload.subject,\n            errorMessage,\n            statusCode: statusCode || 'unknown',\n          }\n        );\n\n        if (isPermanentFailure) {\n          await userPushSubRepository.remove(pushSub);\n        }\n      }\n    };\n\n    if (\n      payload.notifyUser &&\n      // Check if user has webpush notifications enabled and fallback to true if undefined\n      // since web push should default to true\n      (payload.notifyUser.settings?.hasNotificationType(\n        NotificationAgentKey.WEBPUSH,\n        type\n      ) ??\n        true)\n    ) {\n      const notifySubs = await userPushSubRepository.find({\n        where: { user: { id: payload.notifyUser.id } },\n      });\n\n      pushSubs.push(...notifySubs);\n    }\n\n    if (\n      payload.notifyAdmin ||\n      type === Notification.MEDIA_APPROVED ||\n      type === Notification.MEDIA_DECLINED\n    ) {\n      const users = await userRepository.find();\n\n      const manageUsers = users.filter(\n        (user) =>\n          // Check if user has webpush notifications enabled and fallback to true if undefined\n          // since web push should default to true\n          (user.settings?.hasNotificationType(\n            NotificationAgentKey.WEBPUSH,\n            type\n          ) ??\n            true) &&\n          shouldSendAdminNotification(type, user, payload)\n      );\n\n      const allSubs =\n        manageUsers.length > 0\n          ? await userPushSubRepository\n              .createQueryBuilder('pushSub')\n              .leftJoinAndSelect('pushSub.user', 'user')\n              .where('pushSub.userId IN (:...users)', {\n                users: manageUsers.map((user) => user.id),\n              })\n              .getMany()\n          : [];\n\n      // We only want to send the custom notification when type is approved or declined\n      // Otherwise, default to the normal notification\n      if (\n        type === Notification.MEDIA_APPROVED ||\n        type === Notification.MEDIA_DECLINED\n      ) {\n        if (mainUser && allSubs.length > 0) {\n          webpush.setVapidDetails(\n            `mailto:${mainUser.email}`,\n            settings.vapidPublic,\n            settings.vapidPrivate\n          );\n\n          // Custom payload only for updating the app badge\n          const notificationBadgePayload = Buffer.from(\n            JSON.stringify(\n              this.getNotificationPayload(type, {\n                subject: payload.subject,\n                notifySystem: false,\n                notifyAdmin: true,\n                isAdmin: true,\n                pendingRequestsCount: pendingRequests.length,\n              })\n            ),\n            'utf-8'\n          );\n\n          await Promise.all(\n            allSubs.map(async (sub) => {\n              webPushNotification(sub, notificationBadgePayload);\n            })\n          );\n        }\n      } else {\n        pushSubs.push(...allSubs);\n      }\n    }\n\n    if (mainUser && pushSubs.length > 0) {\n      webpush.setVapidDetails(\n        `mailto:${mainUser.email}`,\n        settings.vapidPublic,\n        settings.vapidPrivate\n      );\n\n      if (type === Notification.MEDIA_PENDING) {\n        payload = { ...payload, pendingRequestsCount: pendingRequests.length };\n      }\n\n      const notificationPayload = Buffer.from(\n        JSON.stringify(this.getNotificationPayload(type, payload)),\n        'utf-8'\n      );\n\n      await Promise.all(\n        pushSubs.map(async (sub) => {\n          webPushNotification(sub, notificationPayload);\n        })\n      );\n    }\n\n    return true;\n  }\n}\n\nexport default WebPushAgent;\n"
  },
  {
    "path": "server/lib/notifications/index.ts",
    "content": "import type { User } from '@server/entity/User';\nimport { Permission } from '@server/lib/permissions';\nimport logger from '@server/logger';\nimport type { NotificationAgent, NotificationPayload } from './agents/agent';\n\nexport enum Notification {\n  NONE = 0,\n  MEDIA_PENDING = 2,\n  MEDIA_APPROVED = 4,\n  MEDIA_AVAILABLE = 8,\n  MEDIA_FAILED = 16,\n  TEST_NOTIFICATION = 32,\n  MEDIA_DECLINED = 64,\n  MEDIA_AUTO_APPROVED = 128,\n  ISSUE_CREATED = 256,\n  ISSUE_COMMENT = 512,\n  ISSUE_RESOLVED = 1024,\n  ISSUE_REOPENED = 2048,\n  MEDIA_AUTO_REQUESTED = 4096,\n}\n\nexport const hasNotificationType = (\n  types: Notification | Notification[],\n  value: number\n): boolean => {\n  let total: number;\n\n  // If we are not checking any notifications, bail out and return true\n  if (types === 0) {\n    return true;\n  }\n\n  if (Array.isArray(types)) {\n    // Combine all notification values into one\n    total = types.reduce((a, v) => a + v, 0);\n  } else {\n    total = types;\n  }\n\n  // Test notifications don't need to be enabled\n  if (!(value & Notification.TEST_NOTIFICATION)) {\n    value += Notification.TEST_NOTIFICATION;\n  }\n\n  return !!(value & total);\n};\n\nexport const getAdminPermission = (type: Notification): Permission => {\n  switch (type) {\n    case Notification.MEDIA_PENDING:\n    case Notification.MEDIA_APPROVED:\n    case Notification.MEDIA_AVAILABLE:\n    case Notification.MEDIA_FAILED:\n    case Notification.MEDIA_DECLINED:\n    case Notification.MEDIA_AUTO_APPROVED:\n      return Permission.MANAGE_REQUESTS;\n    case Notification.ISSUE_CREATED:\n    case Notification.ISSUE_COMMENT:\n    case Notification.ISSUE_RESOLVED:\n    case Notification.ISSUE_REOPENED:\n      return Permission.MANAGE_ISSUES;\n    default:\n      return Permission.ADMIN;\n  }\n};\n\nexport const shouldSendAdminNotification = (\n  type: Notification,\n  user: User,\n  payload: NotificationPayload\n): boolean => {\n  return (\n    user.id !== payload.notifyUser?.id &&\n    user.hasPermission(getAdminPermission(type)) &&\n    // Check if the user submitted this request (on behalf of themself OR another user)\n    (type !== Notification.MEDIA_AUTO_APPROVED ||\n      user.id !==\n        (payload.request?.modifiedBy ?? payload.request?.requestedBy)?.id) &&\n    // Check if the user created this issue\n    (type !== Notification.ISSUE_CREATED ||\n      user.id !== payload.issue?.createdBy.id) &&\n    // Check if the user submitted this issue comment\n    (type !== Notification.ISSUE_COMMENT ||\n      user.id !== payload.comment?.user.id) &&\n    // Check if the user resolved/reopened this issue\n    ((type !== Notification.ISSUE_RESOLVED &&\n      type !== Notification.ISSUE_REOPENED) ||\n      user.id !== payload.issue?.modifiedBy?.id)\n  );\n};\n\nclass NotificationManager {\n  private activeAgents: NotificationAgent[] = [];\n\n  public registerAgents = (agents: NotificationAgent[]): void => {\n    this.activeAgents = [...this.activeAgents, ...agents];\n    logger.info('Registered notification agents', { label: 'Notifications' });\n  };\n\n  public sendNotification(\n    type: Notification,\n    payload: NotificationPayload\n  ): void {\n    logger.info(`Sending notification(s) for ${Notification[type]}`, {\n      label: 'Notifications',\n      subject: payload.subject,\n    });\n\n    this.activeAgents.forEach((agent) => {\n      if (agent.shouldSend()) {\n        agent.send(type, payload);\n      }\n    });\n  }\n}\n\nconst notificationManager = new NotificationManager();\n\nexport default notificationManager;\n"
  },
  {
    "path": "server/lib/overseerrMerge.ts",
    "content": "import { MediaServerType } from '@server/constants/server';\nimport dataSource, { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport Settings from '@server/lib/settings';\nimport logger from '@server/logger';\nimport type { MigrationInterface, MixedList, QueryRunner } from 'typeorm';\n\nconst checkOverseerrMerge = async (): Promise<boolean> => {\n  // Load settings without running migrations\n  const settings = await new Settings().load(undefined, true);\n\n  if (settings.main.mediaServerType) {\n    return false; // The application has already been migrated\n  }\n\n  const jellyseerMigrations = [\n    [1613379909641, 'AddJellyfinUserParams1613379909641'],\n    [1613412948344, 'ServerTypeEnum1613412948344'],\n    [1613670041760, 'AddJellyfinDeviceId1613670041760'],\n    [1682608634546, 'AddWatchlists1682608634546'],\n    [1699901142442, 'AddBlacklist1699901142442'],\n    [1727907530757, 'AddUserSettingsStreamingRegion1727907530757'],\n    [1734287582736, 'AddTelegramMessageThreadId1734287582736'],\n    [1734805733535, 'AddOverrideRules1734805733535'],\n    [1737320080282, 'AddBlacklistTagsColumn1737320080282'],\n    [1743023610704, 'UpdateWebPush1743023610704'],\n    [1743107645301, 'AddUserAvatarCacheFields1743107645301'],\n    [1745492372230, 'UpdateWebPush1745492372230'],\n  ];\n\n  // Open the database connection to get the migrations and close it afterwards\n  const dbConnection = await dataSource.initialize();\n  const migrations = dbConnection.migrations;\n  await dbConnection.destroy();\n\n  // We have to replace Jellyseerr migrations not working with Overseerr with a custom one\n  try {\n    // Filter out the Jellyseerr migrations and replace them with the Seerr migration\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n    const newMigrations: MixedList<string | Function> = migrations\n      ?.filter(\n        (migration) =>\n          !jellyseerMigrations\n            .map(([, name]) => name)\n            .includes(migration.name as string) ||\n          migration.name === 'UpdateWebPush1745492372230'\n      )\n      .map((migration) =>\n        migration.name === 'UpdateWebPush1745492372230'\n          ? SeerrMigration1759769291608\n          : migration.constructor\n      );\n    dataSource.setOptions({\n      ...dataSource.options,\n      migrations: newMigrations,\n    });\n  } catch (error) {\n    logger.error('Failed to load migrations for Overseerr merge', {\n      label: 'Seerr Migration',\n      error: error.message,\n    });\n    process.exit(1);\n  }\n\n  // Reopen the database connection with the updated migrations\n  await dataSource.initialize();\n\n  // Add fake migration record to prevent running the already existing Overseerr migration again\n  try {\n    await dbConnection.query(\n      `INSERT INTO migrations (timestamp,name) VALUES\n        ${jellyseerMigrations\n          .map(([timestamp, name]) => `(${timestamp}, '${name}')`)\n          .join(', ')}\n      `\n    );\n  } catch (error) {\n    logger.error('Failed to insert migration records', {\n      label: 'Seerr Migration',\n      error: error.message,\n    });\n    process.exit(1);\n  }\n\n  // Manually run the migration to update the database schema\n  if (process.env.NODE_ENV === 'production') {\n    await dbConnection.query('PRAGMA foreign_keys=OFF');\n    await dbConnection.runMigrations();\n    await dbConnection.query('PRAGMA foreign_keys=ON');\n  }\n\n  // MediaStatus.Blacklisted was added before MediaStatus.Deleted in Jellyseerr\n  try {\n    const mediaRepository = getRepository(Media);\n    const mediaToUpdate = await mediaRepository.find({ where: { status: 6 } });\n    for (const media of mediaToUpdate) {\n      media.status = 7;\n      await mediaRepository.save(media);\n    }\n    const media4kToUpdate = await mediaRepository.find({\n      where: { status4k: 6 },\n    });\n    for (const media of media4kToUpdate) {\n      media.status4k = 7;\n      await mediaRepository.save(media);\n    }\n  } catch (error) {\n    logger.error('Failed to update Media status from Blacklisted to Deleted', {\n      label: 'Seerr Migration',\n      error: error.message,\n    });\n    process.exit(1);\n  }\n\n  // Set media server type to Plex (default for Overseerr)\n  settings.main.mediaServerType = MediaServerType.PLEX;\n\n  // Replace default Overseerr values with Seerr values\n  if (settings.main.applicationTitle === 'Overseerr') {\n    settings.main.applicationTitle = 'Seerr';\n  }\n  if (settings.notifications.agents.email.options.senderName === 'Overseerr') {\n    settings.notifications.agents.email.options.senderName = 'Seerr';\n  }\n\n  // Save the updated settings\n  try {\n    await settings.save();\n  } catch (error) {\n    logger.error('Failed to save updated settings for Overseerr merge', {\n      label: 'Seerr Migration',\n      error: error.message,\n    });\n    process.exit(1);\n  }\n\n  logger.info('Yeah! Overseerr to Seerr migration completed successfully!', {\n    label: 'Seerr Migration',\n  });\n\n  return true;\n};\n\n/**\n * Overseerr to Jellyseerr migration\n * Generated by TypeORM\n */\nclass SeerrMigration1759769291608 implements MigrationInterface {\n  name = 'SeerrMigration1759769291608';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar DEFAULT (NULL), \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blacklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"))`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"override_rule\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"radarrServiceId\" integer, \"sonarrServiceId\" integer, \"users\" varchar, \"genre\" varchar, \"language\" varchar, \"keywords\" varchar, \"profileId\" integer, \"rootFolder\" varchar, \"tags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"))`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"pushoverSound\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaId\" varchar, \"jellyfinMediaId4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"pushoverSound\" varchar, \"discoverRegion\" varchar, \"streamingRegion\" varchar, \"telegramMessageThreadId\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, \"jellyfinAuthToken\" varchar, \"avatarETag\" varchar, \"avatarVersion\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"requestId\" integer, CONSTRAINT \"FK_6f14737e346d6b27d8e50d2157a\" FOREIGN KEY (\"requestId\") REFERENCES \"media_request\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"season_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_season_request\" RENAME TO \"season_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"status\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"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, \"isAutoRequest\" boolean NOT NULL DEFAULT (0), 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)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\", \"isAutoRequest\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\", \"isAutoRequest\" FROM \"media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_season\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaId\" integer, \"status4k\" integer NOT NULL DEFAULT (1), CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_season\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\", \"status4k\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\", \"status4k\" FROM \"season\"`\n    );\n    await queryRunner.query(`DROP TABLE \"season\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_season\" RENAME TO \"season\"`\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime DEFAULT (CURRENT_TIMESTAMP), \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaId\" varchar, \"jellyfinMediaId4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, \"jellyfinAuthToken\" varchar, \"avatarETag\" varchar, \"avatarVersion\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"jellyfinAuthToken\", \"avatarETag\", \"avatarVersion\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"jellyfinAuthToken\", \"avatarETag\", \"avatarVersion\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_issue_comment\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"message\" text NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"issueId\" integer, CONSTRAINT \"FK_180710fead1c94ca499c57a7d42\" FOREIGN KEY (\"issueId\") REFERENCES \"issue\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_707b033c2d0653f75213614789d\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_issue_comment\"(\"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\") SELECT \"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\" FROM \"issue_comment\"`\n    );\n    await queryRunner.query(`DROP TABLE \"issue_comment\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_issue_comment\" RENAME TO \"issue_comment\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_issue\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"issueType\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"problemSeason\" integer NOT NULL DEFAULT (0), \"problemEpisode\" integer NOT NULL DEFAULT (0), \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaId\" integer, \"createdById\" integer, \"modifiedById\" integer, CONSTRAINT \"FK_da88a1019c850d1a7b143ca02e5\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_10b17b49d1ee77e7184216001e0\" FOREIGN KEY (\"createdById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_276e20d053f3cff1645803c95d8\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_issue\"(\"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\") SELECT \"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\" FROM \"issue\"`\n    );\n    await queryRunner.query(`DROP TABLE \"issue\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_issue\" RENAME TO \"issue\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_discover_slider\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"type\" integer NOT NULL, \"order\" integer NOT NULL, \"isBuiltIn\" boolean NOT NULL DEFAULT (0), \"enabled\" boolean NOT NULL DEFAULT (1), \"title\" varchar, \"data\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_discover_slider\"(\"id\", \"type\", \"order\", \"isBuiltIn\", \"enabled\", \"title\", \"data\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"type\", \"order\", \"isBuiltIn\", \"enabled\", \"title\", \"data\", \"createdAt\", \"updatedAt\" FROM \"discover_slider\"`\n    );\n    await queryRunner.query(`DROP TABLE \"discover_slider\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_discover_slider\" RENAME TO \"discover_slider\"`\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blacklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blacklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blacklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blacklist\" RENAME TO \"blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_939f205946256cc0d2a1ac51a8\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"), CONSTRAINT \"FK_ae34e6b153a90672eb9dc4857d7\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_watchlist\"(\"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\") SELECT \"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\" FROM \"watchlist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"watchlist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_watchlist\" RENAME TO \"watchlist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_939f205946256cc0d2a1ac51a8\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" RENAME TO \"temporary_watchlist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"watchlist\"(\"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\") SELECT \"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\" FROM \"temporary_watchlist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_watchlist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" RENAME TO \"temporary_blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blacklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blacklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blacklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blacklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"discover_slider\" RENAME TO \"temporary_discover_slider\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"discover_slider\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"type\" integer NOT NULL, \"order\" integer NOT NULL, \"isBuiltIn\" boolean NOT NULL DEFAULT (0), \"enabled\" boolean NOT NULL DEFAULT (1), \"title\" varchar, \"data\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"discover_slider\"(\"id\", \"type\", \"order\", \"isBuiltIn\", \"enabled\", \"title\", \"data\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"type\", \"order\", \"isBuiltIn\", \"enabled\", \"title\", \"data\", \"createdAt\", \"updatedAt\" FROM \"temporary_discover_slider\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_discover_slider\"`);\n    await queryRunner.query(`ALTER TABLE \"issue\" RENAME TO \"temporary_issue\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"issue\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"issueType\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"problemSeason\" integer NOT NULL DEFAULT (0), \"problemEpisode\" integer NOT NULL DEFAULT (0), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, \"createdById\" integer, \"modifiedById\" integer, CONSTRAINT \"FK_da88a1019c850d1a7b143ca02e5\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_10b17b49d1ee77e7184216001e0\" FOREIGN KEY (\"createdById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_276e20d053f3cff1645803c95d8\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"issue\"(\"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\") SELECT \"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\" FROM \"temporary_issue\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_issue\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"issue_comment\" RENAME TO \"temporary_issue_comment\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"issue_comment\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"message\" text NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"issueId\" integer, CONSTRAINT \"FK_180710fead1c94ca499c57a7d42\" FOREIGN KEY (\"issueId\") REFERENCES \"issue\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_707b033c2d0653f75213614789d\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"issue_comment\"(\"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\") SELECT \"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\" FROM \"temporary_issue_comment\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_issue_comment\"`);\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, \"jellyfinAuthToken\" varchar, \"avatarETag\" varchar, \"avatarVersion\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"jellyfinAuthToken\", \"avatarETag\", \"avatarVersion\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"jellyfinAuthToken\", \"avatarETag\", \"avatarVersion\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar DEFAULT (NULL), \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaId\" varchar, \"jellyfinMediaId4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" RENAME TO \"temporary_season\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, \"status4k\" integer NOT NULL DEFAULT (1), CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"season\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\", \"status4k\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\", \"status4k\" FROM \"temporary_season\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_season\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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, \"tags\" text, \"isAutoRequest\" boolean NOT NULL DEFAULT (0), 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)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\", \"isAutoRequest\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\", \"isAutoRequest\" FROM \"temporary_media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"season_request\" RENAME TO \"temporary_season_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestId\" integer, CONSTRAINT \"FK_6f14737e346d6b27d8e50d2157a\" FOREIGN KEY (\"requestId\") REFERENCES \"media_request\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"temporary_season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_season_request\"`);\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"pushoverSound\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"pushoverSound\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_939f205946256cc0d2a1ac51a8\"`);\n    await queryRunner.query(`DROP TABLE \"watchlist\"`);\n    await queryRunner.query(`DROP TABLE \"override_rule\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar DEFAULT (NULL), \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n  }\n}\n\nexport default checkOverseerrMerge;\n"
  },
  {
    "path": "server/lib/permissions.ts",
    "content": "export enum Permission {\n  NONE = 0,\n  ADMIN = 2,\n  MANAGE_SETTINGS = 4,\n  MANAGE_USERS = 8,\n  MANAGE_REQUESTS = 16,\n  REQUEST = 32,\n  VOTE = 64,\n  AUTO_APPROVE = 128,\n  AUTO_APPROVE_MOVIE = 256,\n  AUTO_APPROVE_TV = 512,\n  REQUEST_4K = 1024,\n  REQUEST_4K_MOVIE = 2048,\n  REQUEST_4K_TV = 4096,\n  REQUEST_ADVANCED = 8192,\n  REQUEST_VIEW = 16384,\n  AUTO_APPROVE_4K = 32768,\n  AUTO_APPROVE_4K_MOVIE = 65536,\n  AUTO_APPROVE_4K_TV = 131072,\n  REQUEST_MOVIE = 262144,\n  REQUEST_TV = 524288,\n  MANAGE_ISSUES = 1048576,\n  VIEW_ISSUES = 2097152,\n  CREATE_ISSUES = 4194304,\n  AUTO_REQUEST = 8388608,\n  AUTO_REQUEST_MOVIE = 16777216,\n  AUTO_REQUEST_TV = 33554432,\n  RECENT_VIEW = 67108864,\n  WATCHLIST_VIEW = 134217728,\n  MANAGE_BLOCKLIST = 268435456,\n  VIEW_BLOCKLIST = 1073741824,\n}\n\nexport interface PermissionCheckOptions {\n  type: 'and' | 'or';\n}\n\n/**\n * Takes a Permission and the users permission value and determines\n * if the user has access to the permission provided. If the user has\n * the admin permission, true will always be returned from this check!\n *\n * @param permissions Single permission or array of permissions\n * @param value users current permission value\n * @param options Extra options to control permission check behavior (mainly for arrays)\n */\nexport const hasPermission = (\n  permissions: Permission | Permission[],\n  value: number,\n  options: PermissionCheckOptions = { type: 'and' }\n): boolean => {\n  let total = 0;\n\n  // If we are not checking any permissions, bail out and return true\n  if (permissions === 0) {\n    return true;\n  }\n\n  if (Array.isArray(permissions)) {\n    if (value & Permission.ADMIN) {\n      return true;\n    }\n    switch (options.type) {\n      case 'and':\n        return permissions.every((permission) => !!(value & permission));\n      case 'or':\n        return permissions.some((permission) => !!(value & permission));\n    }\n  } else {\n    total = permissions;\n  }\n\n  return !!(value & Permission.ADMIN) || !!(value & total);\n};\n"
  },
  {
    "path": "server/lib/refreshToken.ts",
    "content": "import PlexTvAPI from '@server/api/plextv';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport logger from '@server/logger';\n\nclass RefreshToken {\n  public async run() {\n    const userRepository = getRepository(User);\n\n    const users = await userRepository\n      .createQueryBuilder('user')\n      .addSelect('user.plexToken')\n      .where(\"user.plexToken != ''\")\n      .getMany();\n\n    for (const user of users) {\n      await this.refreshUserToken(user);\n    }\n  }\n\n  private async refreshUserToken(user: User) {\n    if (!user.plexToken) {\n      logger.warn('Skipping user refresh token for user without plex token', {\n        label: 'Plex Refresh Token',\n        user: user.displayName,\n      });\n      return;\n    }\n\n    const plexTvApi = new PlexTvAPI(user.plexToken);\n    plexTvApi.pingToken();\n  }\n}\n\nconst refreshToken = new RefreshToken();\n\nexport default refreshToken;\n"
  },
  {
    "path": "server/lib/scanners/baseScanner.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport { MediaStatus, MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport Season from '@server/entity/Season';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport AsyncLock from '@server/utils/asyncLock';\nimport { randomUUID } from 'crypto';\n\n// Default scan rates (can be overidden)\nconst BUNDLE_SIZE = 20;\nconst UPDATE_RATE = 4 * 1000;\n\nexport type StatusBase = {\n  running: boolean;\n  progress: number;\n  total: number;\n};\n\nexport interface RunnableScanner<T> {\n  run: () => Promise<void>;\n  status: () => T & StatusBase;\n}\n\nexport interface MediaIds {\n  tmdbId: number;\n  imdbId?: string;\n  tvdbId?: number;\n  isHama?: boolean;\n}\n\ninterface ProcessOptions {\n  is4k?: boolean;\n  mediaAddedAt?: Date;\n  ratingKey?: string;\n  jellyfinMediaId?: string;\n  imdbId?: string;\n  serviceId?: number;\n  externalServiceId?: number;\n  externalServiceSlug?: string;\n  title?: string;\n  processing?: boolean;\n}\n\nexport interface ProcessableSeason {\n  seasonNumber: number;\n  totalEpisodes: number;\n  episodes: number;\n  episodes4k: number;\n  is4kOverride?: boolean;\n  processing?: boolean;\n}\n\nclass BaseScanner<T> {\n  private bundleSize;\n  private updateRate;\n  protected progress = 0;\n  protected items: T[] = [];\n  protected totalSize?: number = 0;\n  protected scannerName: string;\n  protected enable4kMovie = false;\n  protected enable4kShow = false;\n  protected sessionId: string;\n  protected running = false;\n  readonly asyncLock = new AsyncLock();\n  readonly tmdb = new TheMovieDb();\n\n  protected constructor(\n    scannerName: string,\n    {\n      updateRate,\n      bundleSize,\n    }: {\n      updateRate?: number;\n      bundleSize?: number;\n    } = {}\n  ) {\n    this.scannerName = scannerName;\n    this.bundleSize = bundleSize ?? BUNDLE_SIZE;\n    this.updateRate = updateRate ?? UPDATE_RATE;\n  }\n\n  private async getExisting(tmdbId: number, mediaType: MediaType) {\n    const mediaRepository = getRepository(Media);\n\n    const existing = await mediaRepository.findOne({\n      where: { tmdbId: tmdbId, mediaType },\n    });\n\n    return existing;\n  }\n\n  protected async processMovie(\n    tmdbId: number,\n    {\n      is4k = false,\n      mediaAddedAt,\n      ratingKey,\n      jellyfinMediaId,\n      imdbId,\n      serviceId,\n      externalServiceId,\n      externalServiceSlug,\n      processing = false,\n      title = 'Unknown Title',\n    }: ProcessOptions = {}\n  ): Promise<void> {\n    const mediaRepository = getRepository(Media);\n\n    await this.asyncLock.dispatch(tmdbId, async () => {\n      const existing = await this.getExisting(tmdbId, MediaType.MOVIE);\n\n      if (existing) {\n        let changedExisting = false;\n\n        if (existing[is4k ? 'status4k' : 'status'] !== MediaStatus.AVAILABLE) {\n          existing[is4k ? 'status4k' : 'status'] = !processing\n            ? MediaStatus.AVAILABLE\n            : existing[is4k ? 'status4k' : 'status'] === MediaStatus.DELETED\n              ? MediaStatus.DELETED\n              : MediaStatus.PROCESSING;\n          if (mediaAddedAt) {\n            existing.mediaAddedAt = mediaAddedAt;\n          }\n          changedExisting = true;\n        }\n\n        if (!changedExisting && !existing.mediaAddedAt && mediaAddedAt) {\n          existing.mediaAddedAt = mediaAddedAt;\n          changedExisting = true;\n        }\n\n        if (\n          ratingKey &&\n          existing[is4k ? 'ratingKey4k' : 'ratingKey'] !== ratingKey\n        ) {\n          existing[is4k ? 'ratingKey4k' : 'ratingKey'] = ratingKey;\n          changedExisting = true;\n        }\n\n        if (\n          jellyfinMediaId &&\n          existing[is4k ? 'jellyfinMediaId4k' : 'jellyfinMediaId'] !==\n            jellyfinMediaId\n        ) {\n          existing[is4k ? 'jellyfinMediaId4k' : 'jellyfinMediaId'] =\n            jellyfinMediaId;\n          changedExisting = true;\n        }\n\n        if (imdbId && !existing.imdbId) {\n          existing.imdbId = imdbId;\n          changedExisting = true;\n        }\n\n        if (\n          serviceId !== undefined &&\n          existing[is4k ? 'serviceId4k' : 'serviceId'] !== serviceId\n        ) {\n          existing[is4k ? 'serviceId4k' : 'serviceId'] = serviceId;\n          changedExisting = true;\n        }\n\n        if (\n          externalServiceId !== undefined &&\n          existing[is4k ? 'externalServiceId4k' : 'externalServiceId'] !==\n            externalServiceId\n        ) {\n          existing[is4k ? 'externalServiceId4k' : 'externalServiceId'] =\n            externalServiceId;\n          changedExisting = true;\n        }\n\n        if (\n          externalServiceSlug !== undefined &&\n          existing[is4k ? 'externalServiceSlug4k' : 'externalServiceSlug'] !==\n            externalServiceSlug\n        ) {\n          existing[is4k ? 'externalServiceSlug4k' : 'externalServiceSlug'] =\n            externalServiceSlug;\n          changedExisting = true;\n        }\n\n        if (changedExisting) {\n          await mediaRepository.save(existing);\n          this.log(\n            `Media for ${title} exists. Changes were detected and the title will be updated.`,\n            'info'\n          );\n        } else {\n          this.log(`Title already exists and no changes detected for ${title}`);\n        }\n      } else {\n        const newMedia = new Media();\n        newMedia.tmdbId = tmdbId;\n        newMedia.imdbId = imdbId;\n\n        newMedia.status =\n          !is4k && !processing\n            ? MediaStatus.AVAILABLE\n            : !is4k && processing\n              ? MediaStatus.PROCESSING\n              : MediaStatus.UNKNOWN;\n        newMedia.status4k =\n          is4k && this.enable4kMovie && !processing\n            ? MediaStatus.AVAILABLE\n            : is4k && this.enable4kMovie && processing\n              ? MediaStatus.PROCESSING\n              : MediaStatus.UNKNOWN;\n        newMedia.mediaType = MediaType.MOVIE;\n        newMedia.serviceId = !is4k ? serviceId : undefined;\n        newMedia.serviceId4k = is4k ? serviceId : undefined;\n        newMedia.externalServiceId = !is4k ? externalServiceId : undefined;\n        newMedia.externalServiceId4k = is4k ? externalServiceId : undefined;\n        newMedia.externalServiceSlug = !is4k ? externalServiceSlug : undefined;\n        newMedia.externalServiceSlug4k = is4k ? externalServiceSlug : undefined;\n\n        if (mediaAddedAt) {\n          newMedia.mediaAddedAt = mediaAddedAt;\n        }\n\n        if (ratingKey) {\n          newMedia.ratingKey = !is4k ? ratingKey : undefined;\n          newMedia.ratingKey4k =\n            is4k && this.enable4kMovie ? ratingKey : undefined;\n        }\n\n        if (jellyfinMediaId) {\n          newMedia.jellyfinMediaId = !is4k ? jellyfinMediaId : undefined;\n          newMedia.jellyfinMediaId4k =\n            is4k && this.enable4kMovie ? jellyfinMediaId : undefined;\n        }\n\n        await mediaRepository.save(newMedia);\n        this.log(`Saved new media: ${title}`);\n      }\n    });\n  }\n\n  /**\n   * processShow takes a TMDB ID and an array of ProcessableSeasons, which\n   * should include the total episodes a sesaon has + the total available\n   * episodes that each season currently has. Unlike processMovie, this method\n   * does not take an `is4k` option. We handle both the 4k _and_ non 4k status\n   * in one method.\n   *\n   * Note: If 4k is not enable, ProcessableSeasons should combine their episode counts\n   * into the normal episodes properties and avoid using the 4k properties.\n   */\n  protected async processShow(\n    tmdbId: number,\n    tvdbId: number | undefined,\n    seasons: ProcessableSeason[],\n    {\n      mediaAddedAt,\n      ratingKey,\n      jellyfinMediaId,\n      serviceId,\n      externalServiceId,\n      externalServiceSlug,\n      is4k = false,\n      title = 'Unknown Title',\n    }: ProcessOptions = {}\n  ): Promise<void> {\n    const mediaRepository = getRepository(Media);\n\n    await this.asyncLock.dispatch(tmdbId, async () => {\n      const media = await this.getExisting(tmdbId, MediaType.TV);\n\n      const newSeasons: Season[] = [];\n\n      const currentStandardSeasonsAvailable = (\n        media?.seasons.filter(\n          (season) => season.status === MediaStatus.AVAILABLE\n        ) ?? []\n      ).length;\n\n      const current4kSeasonsAvailable = (\n        media?.seasons.filter(\n          (season) => season.status4k === MediaStatus.AVAILABLE\n        ) ?? []\n      ).length;\n\n      for (const season of seasons) {\n        const existingSeason = media?.seasons.find(\n          (es) => es.seasonNumber === season.seasonNumber\n        );\n\n        // We update the rating keys and jellyfinMediaId in the seasons loop because we need episode counts\n        if (media && season.episodes > 0 && media.ratingKey !== ratingKey) {\n          media.ratingKey = ratingKey;\n        }\n\n        if (\n          media &&\n          season.episodes4k > 0 &&\n          this.enable4kShow &&\n          media.ratingKey4k !== ratingKey\n        ) {\n          media.ratingKey4k = ratingKey;\n        }\n\n        if (\n          media &&\n          season.episodes > 0 &&\n          media.jellyfinMediaId !== jellyfinMediaId\n        ) {\n          media.jellyfinMediaId = jellyfinMediaId;\n        }\n\n        if (\n          media &&\n          season.episodes4k > 0 &&\n          this.enable4kShow &&\n          media.jellyfinMediaId4k !== jellyfinMediaId\n        ) {\n          media.jellyfinMediaId4k = jellyfinMediaId;\n        }\n\n        if (existingSeason) {\n          // Here we update seasons if they already exist.\n          // If the season is already marked as available, we\n          // force it to stay available (to avoid competing scanners)\n          existingSeason.status =\n            (season.totalEpisodes === season.episodes && season.episodes > 0) ||\n            existingSeason.status === MediaStatus.AVAILABLE\n              ? MediaStatus.AVAILABLE\n              : season.episodes > 0\n                ? MediaStatus.PARTIALLY_AVAILABLE\n                : !season.is4kOverride &&\n                    season.processing &&\n                    existingSeason.status !== MediaStatus.DELETED\n                  ? MediaStatus.PROCESSING\n                  : !season.is4kOverride &&\n                      !season.processing &&\n                      season.episodes === 0 &&\n                      existingSeason.status === MediaStatus.PROCESSING\n                    ? MediaStatus.UNKNOWN\n                    : existingSeason.status;\n\n          // Same thing here, except we only do updates if 4k is enabled\n          existingSeason.status4k =\n            (this.enable4kShow &&\n              season.episodes4k === season.totalEpisodes &&\n              season.episodes4k > 0) ||\n            existingSeason.status4k === MediaStatus.AVAILABLE\n              ? MediaStatus.AVAILABLE\n              : this.enable4kShow && season.episodes4k > 0\n                ? MediaStatus.PARTIALLY_AVAILABLE\n                : season.is4kOverride &&\n                    season.processing &&\n                    existingSeason.status4k !== MediaStatus.DELETED\n                  ? MediaStatus.PROCESSING\n                  : season.is4kOverride &&\n                      !season.processing &&\n                      season.episodes4k === 0 &&\n                      existingSeason.status4k === MediaStatus.PROCESSING\n                    ? MediaStatus.UNKNOWN\n                    : existingSeason.status4k;\n        } else {\n          newSeasons.push(\n            new Season({\n              seasonNumber: season.seasonNumber,\n              status:\n                season.totalEpisodes === season.episodes && season.episodes > 0\n                  ? MediaStatus.AVAILABLE\n                  : season.episodes > 0\n                    ? MediaStatus.PARTIALLY_AVAILABLE\n                    : !season.is4kOverride && season.processing\n                      ? MediaStatus.PROCESSING\n                      : MediaStatus.UNKNOWN,\n              status4k:\n                this.enable4kShow &&\n                season.totalEpisodes === season.episodes4k &&\n                season.episodes4k > 0\n                  ? MediaStatus.AVAILABLE\n                  : this.enable4kShow && season.episodes4k > 0\n                    ? MediaStatus.PARTIALLY_AVAILABLE\n                    : season.is4kOverride && season.processing\n                      ? MediaStatus.PROCESSING\n                      : MediaStatus.UNKNOWN,\n            })\n          );\n        }\n      }\n\n      if (media) {\n        media.seasons = [...media.seasons, ...newSeasons];\n\n        const newStandardSeasonsAvailable = (\n          media.seasons.filter(\n            (season) => season.status === MediaStatus.AVAILABLE\n          ) ?? []\n        ).length;\n\n        const new4kSeasonsAvailable = (\n          media.seasons.filter(\n            (season) => season.status4k === MediaStatus.AVAILABLE\n          ) ?? []\n        ).length;\n\n        // If at least one new season has become available, update\n        // the lastSeasonChange field so we can trigger notifications\n        if (newStandardSeasonsAvailable > currentStandardSeasonsAvailable) {\n          this.log(\n            `Detected ${\n              newStandardSeasonsAvailable - currentStandardSeasonsAvailable\n            } new standard season(s) for ${title}`,\n            'debug'\n          );\n          media.lastSeasonChange = new Date();\n\n          if (mediaAddedAt) {\n            media.mediaAddedAt = mediaAddedAt;\n          }\n        }\n\n        if (new4kSeasonsAvailable > current4kSeasonsAvailable) {\n          this.log(\n            `Detected ${\n              new4kSeasonsAvailable - current4kSeasonsAvailable\n            } new 4K season(s) for ${title}`,\n            'debug'\n          );\n          media.lastSeasonChange = new Date();\n        }\n\n        if (!media.mediaAddedAt && mediaAddedAt) {\n          media.mediaAddedAt = mediaAddedAt;\n        }\n\n        if (serviceId !== undefined) {\n          media[is4k ? 'serviceId4k' : 'serviceId'] = serviceId;\n        }\n\n        if (externalServiceId !== undefined) {\n          media[is4k ? 'externalServiceId4k' : 'externalServiceId'] =\n            externalServiceId;\n        }\n\n        if (externalServiceSlug !== undefined) {\n          media[is4k ? 'externalServiceSlug4k' : 'externalServiceSlug'] =\n            externalServiceSlug;\n        }\n\n        const nonSpecialSeasons = media.seasons.filter(\n          (s) => s.seasonNumber !== 0\n        );\n\n        // Check the actual season objects instead scanner input\n        // to determine overall availability status\n        const isAllStandardSeasonsAvailable =\n          nonSpecialSeasons.length > 0 &&\n          nonSpecialSeasons.every((s) => s.status === MediaStatus.AVAILABLE);\n\n        const isAll4kSeasonsAvailable =\n          nonSpecialSeasons.length > 0 &&\n          nonSpecialSeasons.every((s) => s.status4k === MediaStatus.AVAILABLE);\n\n        media.status = isAllStandardSeasonsAvailable\n          ? MediaStatus.AVAILABLE\n          : media.seasons.some(\n                (season) =>\n                  season.status === MediaStatus.PARTIALLY_AVAILABLE ||\n                  season.status === MediaStatus.AVAILABLE\n              )\n            ? MediaStatus.PARTIALLY_AVAILABLE\n            : (!seasons.length && media.status !== MediaStatus.DELETED) ||\n                media.seasons.some(\n                  (season) => season.status === MediaStatus.PROCESSING\n                )\n              ? MediaStatus.PROCESSING\n              : media.status === MediaStatus.DELETED\n                ? MediaStatus.DELETED\n                : MediaStatus.UNKNOWN;\n        media.status4k =\n          isAll4kSeasonsAvailable && this.enable4kShow\n            ? MediaStatus.AVAILABLE\n            : this.enable4kShow &&\n                media.seasons.some(\n                  (season) =>\n                    season.status4k === MediaStatus.PARTIALLY_AVAILABLE ||\n                    season.status4k === MediaStatus.AVAILABLE\n                )\n              ? MediaStatus.PARTIALLY_AVAILABLE\n              : (!seasons.length && media.status4k !== MediaStatus.DELETED) ||\n                  media.seasons.some(\n                    (season) => season.status4k === MediaStatus.PROCESSING\n                  )\n                ? MediaStatus.PROCESSING\n                : media.status4k === MediaStatus.DELETED\n                  ? MediaStatus.DELETED\n                  : MediaStatus.UNKNOWN;\n        await mediaRepository.save(media);\n        this.log(`Updating existing title: ${title}`);\n      } else {\n        // For new media, check actual newSeasons objects instead of scanner\n        // input to determine overall availability status\n        const nonSpecialNewSeasons = newSeasons.filter(\n          (s) => s.seasonNumber !== 0\n        );\n\n        const isAllStandardSeasonsAvailable =\n          nonSpecialNewSeasons.length > 0 &&\n          nonSpecialNewSeasons.every((s) => s.status === MediaStatus.AVAILABLE);\n\n        const isAll4kSeasonsAvailable =\n          nonSpecialNewSeasons.length > 0 &&\n          nonSpecialNewSeasons.every(\n            (s) => s.status4k === MediaStatus.AVAILABLE\n          );\n\n        const newMedia = new Media({\n          mediaType: MediaType.TV,\n          seasons: newSeasons,\n          tmdbId,\n          tvdbId,\n          mediaAddedAt,\n          serviceId: !is4k ? serviceId : undefined,\n          serviceId4k: is4k ? serviceId : undefined,\n          externalServiceId: !is4k ? externalServiceId : undefined,\n          externalServiceId4k: is4k ? externalServiceId : undefined,\n          externalServiceSlug: !is4k ? externalServiceSlug : undefined,\n          externalServiceSlug4k: is4k ? externalServiceSlug : undefined,\n          ratingKey: newSeasons.some(\n            (sn) =>\n              sn.status === MediaStatus.PARTIALLY_AVAILABLE ||\n              sn.status === MediaStatus.AVAILABLE\n          )\n            ? ratingKey\n            : undefined,\n          ratingKey4k:\n            this.enable4kShow &&\n            newSeasons.some(\n              (sn) =>\n                sn.status4k === MediaStatus.PARTIALLY_AVAILABLE ||\n                sn.status4k === MediaStatus.AVAILABLE\n            )\n              ? ratingKey\n              : undefined,\n          jellyfinMediaId: newSeasons.some(\n            (sn) =>\n              sn.status === MediaStatus.PARTIALLY_AVAILABLE ||\n              sn.status === MediaStatus.AVAILABLE\n          )\n            ? jellyfinMediaId\n            : undefined,\n          jellyfinMediaId4k:\n            this.enable4kShow &&\n            newSeasons.some(\n              (sn) =>\n                sn.status4k === MediaStatus.PARTIALLY_AVAILABLE ||\n                sn.status4k === MediaStatus.AVAILABLE\n            )\n              ? jellyfinMediaId\n              : undefined,\n          status: isAllStandardSeasonsAvailable\n            ? MediaStatus.AVAILABLE\n            : newSeasons.some(\n                  (season) =>\n                    season.status === MediaStatus.PARTIALLY_AVAILABLE ||\n                    season.status === MediaStatus.AVAILABLE\n                )\n              ? MediaStatus.PARTIALLY_AVAILABLE\n              : newSeasons.some(\n                    (season) => season.status === MediaStatus.PROCESSING\n                  )\n                ? MediaStatus.PROCESSING\n                : MediaStatus.UNKNOWN,\n          status4k:\n            isAll4kSeasonsAvailable && this.enable4kShow\n              ? MediaStatus.AVAILABLE\n              : this.enable4kShow &&\n                  newSeasons.some(\n                    (season) =>\n                      season.status4k === MediaStatus.PARTIALLY_AVAILABLE ||\n                      season.status4k === MediaStatus.AVAILABLE\n                  )\n                ? MediaStatus.PARTIALLY_AVAILABLE\n                : newSeasons.some(\n                      (season) => season.status4k === MediaStatus.PROCESSING\n                    )\n                  ? MediaStatus.PROCESSING\n                  : MediaStatus.UNKNOWN,\n        });\n        await mediaRepository.save(newMedia);\n        this.log(`Saved ${title}`);\n      }\n    });\n  }\n\n  /**\n   * Call startRun from child class whenever a run is starting to\n   * ensure required values are set\n   *\n   * Returns the session ID which is requried for the cleanup method\n   */\n  protected startRun(): string {\n    const settings = getSettings();\n    const sessionId = randomUUID();\n    this.sessionId = sessionId;\n\n    this.log('Scan starting', 'info', { sessionId });\n\n    this.enable4kMovie = settings.radarr.some((radarr) => radarr.is4k);\n    if (this.enable4kMovie) {\n      this.log(\n        'At least one 4K Radarr server was detected. 4K movie detection is now enabled',\n        'info'\n      );\n    }\n\n    this.enable4kShow = settings.sonarr.some((sonarr) => sonarr.is4k);\n    if (this.enable4kShow) {\n      this.log(\n        'At least one 4K Sonarr server was detected. 4K series detection is now enabled',\n        'info'\n      );\n    }\n\n    this.running = true;\n\n    return sessionId;\n  }\n\n  /**\n   * Call at end of run loop to perform cleanup\n   */\n  protected endRun(sessionId: string): void {\n    if (this.sessionId === sessionId) {\n      this.running = false;\n    }\n  }\n\n  public cancel(): void {\n    this.running = false;\n  }\n\n  protected async loop(\n    processFn: (item: T) => Promise<void>,\n    {\n      start = 0,\n      end = this.bundleSize,\n      sessionId,\n    }: {\n      start?: number;\n      end?: number;\n      sessionId?: string;\n    } = {}\n  ): Promise<void> {\n    const slicedItems = this.items.slice(start, end);\n\n    if (!this.running) {\n      throw new Error('Sync was aborted.');\n    }\n\n    if (this.sessionId !== sessionId) {\n      throw new Error('New session was started. Old session aborted.');\n    }\n\n    if (start < this.items.length) {\n      this.progress = start;\n      await this.processItems(processFn, slicedItems);\n\n      await new Promise<void>((resolve, reject) =>\n        setTimeout(() => {\n          this.loop(processFn, {\n            start: start + this.bundleSize,\n            end: end + this.bundleSize,\n            sessionId,\n          })\n            .then(() => resolve())\n            .catch((e) => reject(new Error(e.message)));\n        }, this.updateRate)\n      );\n    }\n  }\n\n  private async processItems(\n    processFn: (items: T) => Promise<void>,\n    items: T[]\n  ) {\n    await Promise.all(\n      items.map(async (item) => {\n        await processFn(item);\n      })\n    );\n  }\n\n  protected log(\n    message: string,\n    level: 'info' | 'error' | 'debug' | 'warn' = 'debug',\n    optional?: Record<string, unknown>\n  ): void {\n    logger[level](message, { label: this.scannerName, ...optional });\n  }\n\n  get protectedUpdateRate(): number {\n    return this.updateRate;\n  }\n\n  get protectedBundleSize(): number {\n    return this.bundleSize;\n  }\n}\n\nexport default BaseScanner;\n"
  },
  {
    "path": "server/lib/scanners/jellyfin/index.ts",
    "content": "import animeList from '@server/api/animelist';\nimport type {\n  JellyfinLibraryItem,\n  JellyfinLibraryItemExtended,\n} from '@server/api/jellyfin';\nimport JellyfinAPI from '@server/api/jellyfin';\nimport { getMetadataProvider } from '@server/api/metadata';\nimport TheMovieDb from '@server/api/themoviedb';\nimport { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants';\nimport type {\n  TmdbKeyword,\n  TmdbTvDetails,\n} from '@server/api/themoviedb/interfaces';\nimport { MediaServerType } from '@server/constants/server';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport type {\n  ProcessableSeason,\n  RunnableScanner,\n  StatusBase,\n} from '@server/lib/scanners/baseScanner';\nimport BaseScanner from '@server/lib/scanners/baseScanner';\nimport type { Library } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport { getHostname } from '@server/utils/getHostname';\nimport { uniqWith } from 'lodash';\n\ninterface JellyfinSyncStatus extends StatusBase {\n  currentLibrary: Library;\n  libraries: Library[];\n}\n\nclass JellyfinScanner\n  extends BaseScanner<JellyfinLibraryItem>\n  implements RunnableScanner<JellyfinSyncStatus>\n{\n  private jfClient: JellyfinAPI;\n  private libraries: Library[];\n  private currentLibrary: Library;\n  private isRecentOnly = false;\n  private processedAnidbSeason: Map<number, Map<number, number>>;\n\n  constructor({ isRecentOnly }: { isRecentOnly?: boolean } = {}) {\n    super('Jellyfin Sync');\n    this.isRecentOnly = isRecentOnly ?? false;\n  }\n\n  private async extractMovieIds(jellyfinitem: JellyfinLibraryItem): Promise<{\n    tmdbId: number;\n    imdbId?: string;\n    metadata: JellyfinLibraryItemExtended;\n  } | null> {\n    let metadata = await this.jfClient.getItemData(jellyfinitem.Id);\n\n    if (!metadata?.Id) {\n      this.log('No Id metadata for this title. Skipping', 'debug', {\n        jellyfinItemId: jellyfinitem.Id,\n      });\n      return null;\n    }\n\n    const anidbId = Number(metadata.ProviderIds.AniDB ?? null);\n    let tmdbId = Number(\n      metadata.ProviderIds.Tmdb || metadata.ProviderIds.TheMovieDb || null\n    );\n    let imdbId = metadata.ProviderIds.Imdb;\n\n    // We use anidb only if we have the anidbId and nothing else\n    if (anidbId && !imdbId && !tmdbId) {\n      const result = animeList.getFromAnidbId(anidbId);\n      tmdbId = Number(result?.tmdbId ?? null);\n      imdbId = result?.imdbId;\n    }\n\n    if (imdbId && !tmdbId) {\n      const tmdbMovie = await this.tmdb.getMediaByImdbId({\n        imdbId: imdbId,\n      });\n      tmdbId = tmdbMovie.id;\n    }\n\n    if (!tmdbId) {\n      throw new Error('Unable to find TMDb ID');\n    }\n\n    // With AniDB we can have mixed libraries with movies in a \"show\" library\n    // We take the first episode of the first season (the movie) and use it to\n    // get more information, like the MediaSource\n    if (anidbId && metadata.Type === 'Series') {\n      const season = (await this.jfClient.getSeasons(jellyfinitem.Id)).find(\n        (md) => {\n          return md.IndexNumber === 1;\n        }\n      );\n      if (!season) {\n        this.log('No season found for anidb movie', 'debug', {\n          jellyfinitem,\n        });\n        return null;\n      }\n      const episodes = await this.jfClient.getEpisodes(\n        jellyfinitem.Id,\n        season.Id\n      );\n      if (!episodes[0]) {\n        this.log('No episode found for anidb movie', 'debug', {\n          jellyfinitem,\n        });\n        return null;\n      }\n      metadata = await this.jfClient.getItemData(episodes[0].Id);\n      if (!metadata) {\n        this.log('No metadata found for anidb movie', 'debug', {\n          jellyfinitem,\n        });\n        return null;\n      }\n    }\n\n    return { tmdbId, imdbId, metadata };\n  }\n\n  private async processJellyfinMovie(jellyfinitem: JellyfinLibraryItem) {\n    try {\n      const extracted = await this.extractMovieIds(jellyfinitem);\n      if (!extracted) return;\n\n      const { tmdbId, imdbId, metadata } = extracted;\n\n      const has4k = metadata.MediaSources?.some((MediaSource) => {\n        return MediaSource.MediaStreams.filter(\n          (MediaStream) => MediaStream.Type === 'Video'\n        ).some((MediaStream) => {\n          return (MediaStream.Width ?? 0) > 2000;\n        });\n      });\n\n      const hasOtherResolution = metadata.MediaSources?.some((MediaSource) => {\n        return MediaSource.MediaStreams.filter(\n          (MediaStream) => MediaStream.Type === 'Video'\n        ).some((MediaStream) => {\n          return (MediaStream.Width ?? 0) <= 2000;\n        });\n      });\n\n      const mediaAddedAt = metadata.DateCreated\n        ? new Date(metadata.DateCreated)\n        : undefined;\n\n      if (hasOtherResolution || (!this.enable4kMovie && has4k)) {\n        await this.processMovie(tmdbId, {\n          is4k: false,\n          mediaAddedAt,\n          jellyfinMediaId: metadata.Id,\n          imdbId,\n          title: metadata.Name,\n        });\n      }\n\n      if (has4k && this.enable4kMovie) {\n        await this.processMovie(tmdbId, {\n          is4k: true,\n          mediaAddedAt,\n          jellyfinMediaId: metadata.Id,\n          imdbId,\n          title: metadata.Name,\n        });\n      }\n    } catch (e) {\n      this.log(\n        `Failed to process Jellyfin item, id: ${jellyfinitem.Id}`,\n        'error',\n        {\n          errorMessage: e.message,\n          jellyfinitem,\n        }\n      );\n    }\n  }\n\n  private async getTvShow({\n    tmdbId,\n    tvdbId,\n  }: {\n    tmdbId?: number;\n    tvdbId?: number;\n  }): Promise<TmdbTvDetails> {\n    let tvShow;\n\n    if (tmdbId) {\n      tvShow = await this.tmdb.getTvShow({\n        tvId: Number(tmdbId),\n      });\n    } else if (tvdbId) {\n      tvShow = await this.tmdb.getShowByTvdbId({\n        tvdbId: Number(tvdbId),\n      });\n    } else {\n      throw new Error('No ID provided');\n    }\n\n    const metadataProvider = tvShow.keywords.results.some(\n      (keyword: TmdbKeyword) => keyword.id === ANIME_KEYWORD_ID\n    )\n      ? await getMetadataProvider('anime')\n      : await getMetadataProvider('tv');\n\n    if (!(metadataProvider instanceof TheMovieDb)) {\n      tvShow = await metadataProvider.getTvShow({\n        tvId: Number(tmdbId),\n      });\n    }\n\n    return tvShow;\n  }\n\n  private async processJellyfinShow(jellyfinitem: JellyfinLibraryItem) {\n    let tvShow: TmdbTvDetails | null = null;\n\n    try {\n      const Id =\n        jellyfinitem.SeriesId ?? jellyfinitem.SeasonId ?? jellyfinitem.Id;\n      const metadata = await this.jfClient.getItemData(Id);\n\n      if (!metadata?.Id) {\n        this.log('No Id metadata for this title. Skipping', 'debug', {\n          jellyfinItemId: jellyfinitem.Id,\n        });\n        return;\n      }\n\n      if (metadata.ProviderIds.Tmdb || metadata.ProviderIds.TheMovieDb) {\n        try {\n          tvShow = await this.getTvShow({\n            tmdbId: Number(\n              metadata.ProviderIds.Tmdb || metadata.ProviderIds.TheMovieDb\n            ),\n          });\n        } catch {\n          this.log('Unable to find TMDb ID for this title.', 'debug', {\n            jellyfinitem,\n          });\n        }\n      }\n\n      if (!tvShow && metadata.ProviderIds.Tvdb) {\n        try {\n          tvShow = await this.getTvShow({\n            tvdbId: Number(metadata.ProviderIds.Tvdb),\n          });\n        } catch {\n          this.log('Unable to find TVDb ID for this title.', 'debug', {\n            jellyfinitem,\n          });\n        }\n      }\n\n      let tvdbSeasonFromAnidb: number | undefined;\n      if (!tvShow && metadata.ProviderIds.AniDB) {\n        const anidbId = Number(metadata.ProviderIds.AniDB);\n        const result = animeList.getFromAnidbId(anidbId);\n        tvdbSeasonFromAnidb = result?.tvdbSeason;\n        if (result?.tvdbId) {\n          try {\n            tvShow = await this.tmdb.getShowByTvdbId({\n              tvdbId: result.tvdbId,\n            });\n          } catch {\n            this.log('Unable to find AniDB ID for this title.', 'debug', {\n              jellyfinitem,\n            });\n          }\n        }\n        // With AniDB we can have mixed libraries with movies in a \"show\" library\n        else if (result?.imdbId || result?.tmdbId) {\n          await this.processJellyfinMovie(jellyfinitem);\n          return;\n        }\n      }\n\n      if (tvShow) {\n        const seasons = tvShow.seasons;\n        const jellyfinSeasons = await this.jfClient.getSeasons(Id);\n\n        const processableSeasons: ProcessableSeason[] = [];\n\n        const settings = getSettings();\n        const filteredSeasons = settings.main.enableSpecialEpisodes\n          ? seasons\n          : seasons.filter((sn) => sn.season_number !== 0);\n\n        for (const season of filteredSeasons) {\n          const matchedJellyfinSeason = jellyfinSeasons.find((md) => {\n            if (tvdbSeasonFromAnidb) {\n              // In AniDB we don't have the concept of seasons,\n              // we have multiple shows with only Season 1 (and sometimes a season with index 0 for specials).\n              // We use tvdbSeasonFromAnidb to check if we are on the correct TMDB season and\n              // md.IndexNumber === 1 to be sure to find the correct season on jellyfin\n              return (\n                tvdbSeasonFromAnidb === season.season_number &&\n                md.IndexNumber === 1\n              );\n            } else {\n              return Number(md.IndexNumber) === season.season_number;\n            }\n          });\n\n          // Check if we found the matching season and it has all the available episodes\n          if (matchedJellyfinSeason) {\n            let totalStandard = 0;\n            let total4k = 0;\n\n            if (!this.enable4kShow) {\n              const episodes = await this.jfClient.getEpisodes(\n                Id,\n                matchedJellyfinSeason.Id\n              );\n\n              for (const episode of episodes) {\n                let episodeCount = 1;\n\n                // count number of combined episodes\n                if (\n                  episode.IndexNumber !== undefined &&\n                  episode.IndexNumberEnd !== undefined\n                ) {\n                  episodeCount =\n                    episode.IndexNumberEnd - episode.IndexNumber + 1;\n                }\n\n                totalStandard += episodeCount;\n              }\n            } else {\n              // 4K detection enabled - request media info to check resolution\n              const episodes = await this.jfClient.getEpisodes(\n                Id,\n                matchedJellyfinSeason.Id,\n                { includeMediaInfo: true }\n              );\n\n              for (const episode of episodes) {\n                let episodeCount = 1;\n\n                // count number of combined episodes\n                if (\n                  episode.IndexNumber !== undefined &&\n                  episode.IndexNumberEnd !== undefined\n                ) {\n                  episodeCount =\n                    episode.IndexNumberEnd - episode.IndexNumber + 1;\n                }\n\n                const has4k = episode.MediaSources?.some((MediaSource) =>\n                  MediaSource.MediaStreams.some(\n                    (MediaStream) =>\n                      MediaStream.Type === 'Video' &&\n                      (MediaStream.Width ?? 0) > 2000\n                  )\n                );\n\n                const hasStandard = episode.MediaSources?.some((MediaSource) =>\n                  MediaSource.MediaStreams.some(\n                    (MediaStream) =>\n                      MediaStream.Type === 'Video' &&\n                      (MediaStream.Width ?? 0) <= 2000\n                  )\n                );\n\n                // Count in both if episode has both versions\n                // TODO: Make this more robust in the future\n                // Currently, this detection is based solely on file resolution, not which\n                // Radarr/Sonarr instance the file came from. If a 4K request results in\n                // 1080p files (no 4K release available yet), those files will be counted\n                // as \"standard\" even though they're in the 4K library. This can cause\n                // non-4K users to see content as \"available\" when they can't access it.\n                // See issue https://github.com/seerr-team/seerr/issues/1744 for details.\n                if (hasStandard) totalStandard += episodeCount;\n                if (has4k) total4k += episodeCount;\n              }\n            }\n\n            // With AniDB we can have multiple shows for one season, so we need to save\n            // the episode from all the jellyfin entries to get the total\n            if (tvdbSeasonFromAnidb) {\n              let show = this.processedAnidbSeason.get(tvShow.id);\n\n              if (!show) {\n                show = new Map([[season.season_number, totalStandard]]);\n                this.processedAnidbSeason.set(tvShow.id, show);\n              } else {\n                const currentCount = show.get(season.season_number) ?? 0;\n                const newCount = currentCount + totalStandard;\n                show.set(season.season_number, newCount);\n                totalStandard = newCount;\n              }\n            }\n\n            processableSeasons.push({\n              seasonNumber: season.season_number,\n              totalEpisodes: season.episode_count,\n              episodes: totalStandard,\n              episodes4k: total4k,\n            });\n          } else {\n            processableSeasons.push({\n              seasonNumber: season.season_number,\n              totalEpisodes: season.episode_count,\n              episodes: 0,\n              episodes4k: 0,\n            });\n          }\n        }\n\n        await this.processShow(\n          tvShow.id,\n          tvShow.external_ids?.tvdb_id,\n          processableSeasons,\n          {\n            mediaAddedAt: metadata.DateCreated\n              ? new Date(metadata.DateCreated)\n              : undefined,\n            jellyfinMediaId: Id,\n            title: tvShow.name,\n          }\n        );\n      } else {\n        this.log(\n          `No information found for the show: ${metadata.Name}`,\n          'debug',\n          {\n            jellyfinitem,\n          }\n        );\n      }\n    } catch (e) {\n      this.log(\n        `Failed to process Jellyfin item. Id: ${\n          jellyfinitem.SeriesId ?? jellyfinitem.SeasonId ?? jellyfinitem.Id\n        }`,\n        'error',\n        { errorMessage: e.message, jellyfinitem }\n      );\n    }\n  }\n\n  private async processItem(item: JellyfinLibraryItem): Promise<void> {\n    if (item.Type === 'Movie') {\n      await this.processJellyfinMovie(item);\n    } else if (item.Type === 'Series') {\n      await this.processJellyfinShow(item);\n    }\n  }\n\n  public async run(): Promise<void> {\n    const settings = getSettings();\n\n    if (\n      settings.main.mediaServerType != MediaServerType.JELLYFIN &&\n      settings.main.mediaServerType != MediaServerType.EMBY\n    ) {\n      return;\n    }\n\n    const sessionId = this.startRun();\n\n    try {\n      const userRepository = getRepository(User);\n      const admin = await userRepository.findOne({\n        where: { id: 1 },\n        select: ['id', 'jellyfinUserId', 'jellyfinDeviceId'],\n        order: { id: 'ASC' },\n      });\n\n      if (!admin) {\n        return this.log('No admin configured. Jellyfin sync skipped.', 'warn');\n      }\n\n      this.jfClient = new JellyfinAPI(\n        getHostname(),\n        settings.jellyfin.apiKey,\n        admin.jellyfinDeviceId\n      );\n\n      this.jfClient.setUserId(admin.jellyfinUserId ?? '');\n\n      this.libraries = settings.jellyfin.libraries.filter(\n        (library) => library.enabled\n      );\n\n      await animeList.sync();\n\n      if (this.isRecentOnly) {\n        for (const library of this.libraries) {\n          this.currentLibrary = library;\n          // Reset AniDB season tracking per library\n          this.processedAnidbSeason = new Map();\n          this.log(\n            `Beginning to process recently added for library: ${library.name}`,\n            'info'\n          );\n          const libraryItems = await this.jfClient.getRecentlyAdded(library.id);\n\n          // Bundle items up by rating keys\n          this.items = uniqWith(libraryItems, (mediaA, mediaB) => {\n            if (mediaA.SeriesId && mediaB.SeriesId) {\n              return mediaA.SeriesId === mediaB.SeriesId;\n            }\n\n            if (mediaA.SeasonId && mediaB.SeasonId) {\n              return mediaA.SeasonId === mediaB.SeasonId;\n            }\n\n            return mediaA.Id === mediaB.Id;\n          });\n\n          await this.loop(this.processItem.bind(this), { sessionId });\n        }\n      } else {\n        for (const library of this.libraries) {\n          this.currentLibrary = library;\n          // Reset AniDB season tracking per library\n          this.processedAnidbSeason = new Map();\n          this.log(`Beginning to process library: ${library.name}`, 'info');\n          this.items = await this.jfClient.getLibraryContents(library.id);\n          await this.loop(this.processItem.bind(this), { sessionId });\n        }\n      }\n\n      this.log(\n        this.isRecentOnly\n          ? 'Recently Added Scan Complete'\n          : 'Full Scan Complete',\n        'info'\n      );\n    } catch (e) {\n      this.log('Sync interrupted', 'error', { errorMessage: e.message });\n    } finally {\n      this.endRun(sessionId);\n    }\n  }\n\n  public status(): JellyfinSyncStatus {\n    return {\n      running: this.running,\n      progress: this.progress,\n      total: this.items.length,\n      currentLibrary: this.currentLibrary,\n      libraries: this.libraries,\n    };\n  }\n}\n\nexport const jellyfinFullScanner = new JellyfinScanner();\nexport const jellyfinRecentScanner = new JellyfinScanner({\n  isRecentOnly: true,\n});\n"
  },
  {
    "path": "server/lib/scanners/plex/index.ts",
    "content": "import animeList from '@server/api/animelist';\nimport { getMetadataProvider } from '@server/api/metadata';\nimport type { PlexLibraryItem, PlexMetadata } from '@server/api/plexapi';\nimport PlexAPI from '@server/api/plexapi';\nimport TheMovieDb from '@server/api/themoviedb';\nimport { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants';\nimport type {\n  TmdbKeyword,\n  TmdbTvDetails,\n} from '@server/api/themoviedb/interfaces';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport cacheManager from '@server/lib/cache';\nimport type {\n  MediaIds,\n  ProcessableSeason,\n  RunnableScanner,\n  StatusBase,\n} from '@server/lib/scanners/baseScanner';\nimport BaseScanner from '@server/lib/scanners/baseScanner';\nimport type { Library } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport { uniqWith } from 'lodash';\n\nconst imdbRegex = new RegExp(/imdb:\\/\\/(tt[0-9]+)/);\nconst tmdbRegex = new RegExp(/tmdb:\\/\\/([0-9]+)/);\nconst tvdbRegex = new RegExp(/tvdb:\\/\\/([0-9]+)/);\nconst tmdbShowRegex = new RegExp(/themoviedb:\\/\\/([0-9]+)/);\nconst plexRegex = new RegExp(/plex:\\/\\//);\n// Hama agent uses ASS naming, see details here:\n// https://github.com/ZeroQI/Absolute-Series-Scanner/blob/master/README.md#forcing-the-movieseries-id\nconst hamaTvdbRegex = new RegExp(/hama:\\/\\/tvdb[0-9]?-([0-9]+)/);\nconst hamaAnidbRegex = new RegExp(/hama:\\/\\/anidb[0-9]?-([0-9]+)/);\nconst HAMA_AGENT = 'com.plexapp.agents.hama';\n\ntype SyncStatus = StatusBase & {\n  currentLibrary: Library;\n  libraries: Library[];\n};\n\nclass PlexScanner\n  extends BaseScanner<PlexLibraryItem>\n  implements RunnableScanner<SyncStatus>\n{\n  private plexClient: PlexAPI;\n  private libraries: Library[];\n  private currentLibrary: Library;\n  private isRecentOnly = false;\n\n  public constructor(isRecentOnly = false) {\n    super('Plex Scan', { bundleSize: 50 });\n    this.isRecentOnly = isRecentOnly;\n  }\n\n  public status(): SyncStatus {\n    return {\n      running: this.running,\n      progress: this.progress,\n      total: this.totalSize ?? 0,\n      currentLibrary: this.currentLibrary,\n      libraries: this.libraries,\n    };\n  }\n\n  public async run(): Promise<void> {\n    const settings = getSettings();\n    const sessionId = this.startRun();\n    try {\n      const userRepository = getRepository(User);\n      const admin = await userRepository.findOne({\n        select: { id: true, plexToken: true },\n        where: { id: 1 },\n      });\n\n      if (!admin) {\n        return this.log('No admin configured. Plex scan skipped.', 'warn');\n      }\n\n      this.plexClient = new PlexAPI({ plexToken: admin.plexToken });\n\n      this.libraries = settings.plex.libraries.filter(\n        (library) => library.enabled\n      );\n\n      const hasHama = await this.hasHamaAgent();\n      if (hasHama) {\n        await animeList.sync();\n      }\n\n      if (this.isRecentOnly) {\n        for (const library of this.libraries) {\n          this.currentLibrary = library;\n          this.log(\n            `Beginning to process recently added for library: ${library.name}`,\n            'info',\n            { lastScan: library.lastScan }\n          );\n          const libraryItems = await this.plexClient.getRecentlyAdded(\n            library.id,\n            library.lastScan\n              ? {\n                  // We remove 10 minutes from the last scan as a buffer\n                  addedAt: library.lastScan - 1000 * 60 * 10,\n                }\n              : undefined,\n            library.type\n          );\n\n          // Bundle items up by rating keys\n          this.items = uniqWith(libraryItems, (mediaA, mediaB) => {\n            if (mediaA.grandparentRatingKey && mediaB.grandparentRatingKey) {\n              return (\n                mediaA.grandparentRatingKey === mediaB.grandparentRatingKey\n              );\n            }\n\n            if (mediaA.parentRatingKey && mediaB.parentRatingKey) {\n              return mediaA.parentRatingKey === mediaB.parentRatingKey;\n            }\n\n            return mediaA.ratingKey === mediaB.ratingKey;\n          });\n\n          await this.loop(this.processItem.bind(this), { sessionId });\n\n          // After run completes, update last scan time\n          const newLibraries = settings.plex.libraries.map((lib) => {\n            if (lib.id === library.id) {\n              return {\n                ...lib,\n                lastScan: Date.now(),\n              };\n            }\n            return lib;\n          });\n\n          settings.plex.libraries = newLibraries;\n          await settings.save();\n        }\n      } else {\n        for (const library of this.libraries) {\n          this.currentLibrary = library;\n          this.log(`Beginning to process library: ${library.name}`, 'info');\n          await this.paginateLibrary(library, { sessionId });\n        }\n      }\n      this.log(\n        this.isRecentOnly\n          ? 'Recently Added Scan Complete'\n          : 'Full Scan Complete',\n        'info'\n      );\n    } catch (e) {\n      this.log('Scan interrupted', 'error', {\n        errorMessage: e.message,\n      });\n    } finally {\n      this.endRun(sessionId);\n    }\n  }\n\n  private async paginateLibrary(\n    library: Library,\n    { start = 0, sessionId }: { start?: number; sessionId: string }\n  ) {\n    if (!this.running) {\n      throw new Error('Sync was aborted.');\n    }\n\n    if (this.sessionId !== sessionId) {\n      throw new Error('New session was started. Old session aborted.');\n    }\n\n    const response = await this.plexClient.getLibraryContents(library.id, {\n      size: this.protectedBundleSize,\n      offset: start,\n    });\n\n    this.progress = start;\n    this.totalSize = response.totalSize;\n\n    if (response.items.length === 0) {\n      return;\n    }\n\n    await Promise.all(\n      response.items.map(async (item) => {\n        await this.processItem(item);\n      })\n    );\n\n    if (response.items.length < this.protectedBundleSize) {\n      return;\n    }\n\n    await new Promise<void>((resolve, reject) =>\n      setTimeout(() => {\n        this.paginateLibrary(library, {\n          start: start + this.protectedBundleSize,\n          sessionId,\n        })\n          .then(() => resolve())\n          .catch((e) => reject(new Error(e.message)));\n      }, this.protectedUpdateRate)\n    );\n  }\n\n  private async processItem(plexitem: PlexLibraryItem) {\n    try {\n      if (plexitem.type === 'movie') {\n        await this.processPlexMovie(plexitem);\n      } else if (\n        plexitem.type === 'show' ||\n        plexitem.type === 'episode' ||\n        plexitem.type === 'season'\n      ) {\n        await this.processPlexShow(plexitem);\n      }\n    } catch (e) {\n      this.log('Failed to process Plex media', 'error', {\n        errorMessage: e.message,\n        title: plexitem.title,\n      });\n    }\n  }\n\n  private async processPlexMovie(plexitem: PlexLibraryItem) {\n    const mediaIds = await this.getMediaIds(plexitem);\n\n    const has4k = plexitem.Media.some(\n      (media) => media.videoResolution === '4k'\n    );\n\n    await this.processMovie(mediaIds.tmdbId, {\n      is4k: has4k && this.enable4kMovie,\n      mediaAddedAt: new Date(plexitem.addedAt * 1000),\n      ratingKey: plexitem.ratingKey,\n      title: plexitem.title,\n    });\n  }\n\n  private async processPlexMovieByTmdbId(\n    plexitem: PlexMetadata,\n    tmdbId: number\n  ) {\n    const has4k = plexitem.Media.some(\n      (media) => media.videoResolution === '4k'\n    );\n\n    await this.processMovie(tmdbId, {\n      is4k: has4k && this.enable4kMovie,\n      mediaAddedAt: new Date(plexitem.addedAt * 1000),\n      ratingKey: plexitem.ratingKey,\n      title: plexitem.title,\n    });\n  }\n\n  private async getTvShow({\n    tmdbId,\n    tvdbId,\n  }: {\n    tmdbId?: number;\n    tvdbId?: number;\n  }): Promise<TmdbTvDetails> {\n    let tvShow;\n\n    if (tmdbId) {\n      tvShow = await this.tmdb.getTvShow({\n        tvId: Number(tmdbId),\n      });\n    } else if (tvdbId) {\n      tvShow = await this.tmdb.getShowByTvdbId({\n        tvdbId: Number(tvdbId),\n      });\n    } else {\n      throw new Error('No ID provided');\n    }\n\n    const metadataProvider = tvShow.keywords.results.some(\n      (keyword: TmdbKeyword) => keyword.id === ANIME_KEYWORD_ID\n    )\n      ? await getMetadataProvider('anime')\n      : await getMetadataProvider('tv');\n\n    if (!(metadataProvider instanceof TheMovieDb)) {\n      tvShow = await metadataProvider.getTvShow({\n        tvId: Number(tmdbId),\n      });\n    }\n\n    return tvShow;\n  }\n\n  private async processPlexShow(plexitem: PlexLibraryItem) {\n    const ratingKey =\n      plexitem.grandparentRatingKey ??\n      plexitem.parentRatingKey ??\n      plexitem.ratingKey;\n    const metadata = await this.plexClient.getMetadata(ratingKey, {\n      includeChildren: true,\n    });\n\n    const mediaIds = await this.getMediaIds(metadata);\n\n    // If the media is from HAMA, and doesn't have a TVDb ID, we will treat it\n    // as a special HAMA movie\n    if (mediaIds.tmdbId && !mediaIds.tvdbId && mediaIds.isHama) {\n      this.processHamaMovie(metadata, mediaIds.tmdbId);\n      return;\n    }\n\n    // If the media is from HAMA and we have a TVDb ID, we will attempt\n    // to process any specials that may exist\n    if (mediaIds.tvdbId && mediaIds.isHama) {\n      await this.processHamaSpecials(metadata, mediaIds.tvdbId);\n    }\n\n    const tvShow = await this.getTvShow({\n      tmdbId: mediaIds.tmdbId,\n    });\n\n    const seasons = tvShow.seasons;\n    const processableSeasons: ProcessableSeason[] = [];\n    const settings = getSettings();\n\n    const filteredSeasons = settings.main.enableSpecialEpisodes\n      ? seasons\n      : seasons.filter((sn) => sn.season_number !== 0);\n\n    for (const season of filteredSeasons) {\n      const matchedPlexSeason = metadata.Children?.Metadata.find(\n        (md) => Number(md.index) === season.season_number\n      );\n\n      if (matchedPlexSeason) {\n        // If we have a matched Plex season, get its children metadata so we can check details\n        const episodes = await this.plexClient.getChildrenMetadata(\n          matchedPlexSeason.ratingKey\n        );\n        // Total episodes that are in standard definition (not 4k)\n        const totalStandard = episodes.filter((episode) =>\n          !this.enable4kShow\n            ? true\n            : episode.Media.some((media) => media.videoResolution !== '4k')\n        ).length;\n\n        // Total episodes that are in 4k\n        const total4k = this.enable4kShow\n          ? episodes.filter((episode) =>\n              episode.Media.some((media) => media.videoResolution === '4k')\n            ).length\n          : 0;\n\n        processableSeasons.push({\n          seasonNumber: season.season_number,\n          episodes: totalStandard,\n          episodes4k: total4k,\n          totalEpisodes: season.episode_count,\n        });\n      } else {\n        processableSeasons.push({\n          seasonNumber: season.season_number,\n          episodes: 0,\n          episodes4k: 0,\n          totalEpisodes: season.episode_count,\n        });\n      }\n    }\n\n    await this.processShow(\n      mediaIds.tmdbId,\n      mediaIds.tvdbId ?? tvShow.external_ids.tvdb_id,\n      processableSeasons,\n      {\n        mediaAddedAt: new Date(metadata.addedAt * 1000),\n        ratingKey: ratingKey,\n        title: metadata.title,\n      }\n    );\n  }\n\n  private async getMediaIds(plexitem: PlexLibraryItem): Promise<MediaIds> {\n    let mediaIds: Partial<MediaIds> = {};\n    // Check if item is using new plex movie/tv agent\n    if (plexitem.guid.match(plexRegex)) {\n      const guidCache = cacheManager.getCache('plexguid');\n\n      const cachedGuids = guidCache.data.get<MediaIds>(plexitem.ratingKey);\n\n      if (cachedGuids) {\n        this.log('GUIDs are cached. Skipping metadata request.', 'debug', {\n          mediaIds: cachedGuids,\n          title: plexitem.title,\n        });\n        mediaIds = cachedGuids;\n      }\n\n      const metadata =\n        plexitem.Guid && plexitem.Guid.length > 0\n          ? plexitem\n          : await this.plexClient.getMetadata(plexitem.ratingKey);\n\n      // If there is no Guid field at all, then we bail\n      if (!metadata.Guid) {\n        throw new Error(\n          'No Guid metadata for this title. Skipping. (Try refreshing the metadata in Plex for this media!)'\n        );\n      }\n\n      // Map all IDs to MediaId object\n      metadata.Guid.forEach((ref) => {\n        if (ref.id.match(imdbRegex)) {\n          mediaIds.imdbId = ref.id.match(imdbRegex)?.[1] ?? undefined;\n        } else if (ref.id.match(tmdbRegex)) {\n          const tmdbMatch = ref.id.match(tmdbRegex)?.[1];\n          mediaIds.tmdbId = Number(tmdbMatch);\n        } else if (ref.id.match(tvdbRegex)) {\n          const tvdbMatch = ref.id.match(tvdbRegex)?.[1];\n          mediaIds.tvdbId = Number(tvdbMatch);\n        }\n      });\n\n      // If we got an IMDb ID, but no TMDB ID, lookup the TMDB ID with the IMDb ID\n      if (mediaIds.imdbId && !mediaIds.tmdbId) {\n        const tmdbMedia = await this.tmdb.getMediaByImdbId({\n          imdbId: mediaIds.imdbId,\n        });\n        mediaIds.tmdbId = tmdbMedia.id;\n      }\n\n      if (mediaIds.tvdbId && !mediaIds.tmdbId) {\n        const show = await this.tmdb.getShowByTvdbId({\n          tvdbId: mediaIds.tvdbId,\n        });\n        mediaIds.tmdbId = show.id;\n      }\n\n      // Cache GUIDs\n      guidCache.data.set(plexitem.ratingKey, mediaIds);\n\n      // Check if the agent is IMDb\n    } else if (plexitem.guid.match(imdbRegex)) {\n      const imdbMatch = plexitem.guid.match(imdbRegex);\n      if (imdbMatch) {\n        mediaIds.imdbId = imdbMatch[1];\n        const tmdbMedia = await this.tmdb.getMediaByImdbId({\n          imdbId: mediaIds.imdbId,\n        });\n        mediaIds.tmdbId = tmdbMedia.id;\n      }\n      // Check if the agent is TMDB\n    } else if (plexitem.guid.match(tmdbRegex)) {\n      const tmdbMatch = plexitem.guid.match(tmdbRegex);\n      if (tmdbMatch) {\n        mediaIds.tmdbId = Number(tmdbMatch[1]);\n      }\n      // Check if the agent is TVDb\n    } else if (plexitem.guid.match(tvdbRegex)) {\n      const matchedtvdb = plexitem.guid.match(tvdbRegex);\n\n      // If we can find a tvdb Id, use it to get the full tmdb show details\n      if (matchedtvdb) {\n        const show = await this.tmdb.getShowByTvdbId({\n          tvdbId: Number(matchedtvdb[1]),\n        });\n\n        mediaIds.tvdbId = Number(matchedtvdb[1]);\n        mediaIds.tmdbId = show.id;\n      }\n      // Check if the agent (for shows) is TMDB\n    } else if (plexitem.guid.match(tmdbShowRegex)) {\n      const matchedtmdb = plexitem.guid.match(tmdbShowRegex);\n      if (matchedtmdb) {\n        mediaIds.tmdbId = Number(matchedtmdb[1]);\n      }\n      // Check for HAMA (with TVDb guid)\n    } else if (plexitem.guid.match(hamaTvdbRegex)) {\n      const matchedtvdb = plexitem.guid.match(hamaTvdbRegex);\n\n      if (matchedtvdb) {\n        const show = await this.tmdb.getShowByTvdbId({\n          tvdbId: Number(matchedtvdb[1]),\n        });\n\n        mediaIds.tvdbId = Number(matchedtvdb[1]);\n        mediaIds.tmdbId = show.id;\n        // Set isHama to true, so we can know to add special processing to this item\n        mediaIds.isHama = true;\n      }\n      // Check for HAMA (with anidb guid)\n    } else if (plexitem.guid.match(hamaAnidbRegex)) {\n      const matchedhama = plexitem.guid.match(hamaAnidbRegex);\n\n      if (!animeList.isLoaded()) {\n        this.log(\n          `Hama ID ${plexitem.guid} detected, but library agent is not set to Hama`,\n          'warn',\n          { title: plexitem.title }\n        );\n      } else if (matchedhama) {\n        const anidbId = Number(matchedhama[1]);\n        const result = animeList.getFromAnidbId(anidbId);\n        let tvShow: TmdbTvDetails | null = null;\n\n        // Set isHama to true, so we can know to add special processing to this item\n        mediaIds.isHama = true;\n\n        // First try to lookup the show by TVDb ID\n        if (result?.tvdbId) {\n          const extResponse = await this.tmdb.getByExternalId({\n            externalId: result.tvdbId,\n            type: 'tvdb',\n          });\n          if (extResponse.tv_results[0]) {\n            tvShow = await this.tmdb.getTvShow({\n              tvId: extResponse.tv_results[0].id,\n            });\n            mediaIds.tvdbId = result.tvdbId;\n            mediaIds.tmdbId = tvShow.id;\n          } else {\n            this.log(\n              `Missing TVDB ${result.tvdbId} entry in TMDB for AniDB ${anidbId}`\n            );\n          }\n        }\n\n        if (!tvShow) {\n          // if lookup of tvshow above failed, then try movie with tmdbid/imdbid\n          // note - some tv shows have imdbid set too, that's why this need to go second\n          if (result?.tmdbId) {\n            mediaIds.tmdbId = result.tmdbId;\n            mediaIds.imdbId = result?.imdbId;\n          } else if (result?.imdbId) {\n            const tmdbMovie = await this.tmdb.getMediaByImdbId({\n              imdbId: result.imdbId,\n            });\n            mediaIds.tmdbId = tmdbMovie.id;\n            mediaIds.imdbId = result.imdbId;\n          }\n        }\n      }\n    }\n\n    if (!mediaIds.tmdbId) {\n      throw new Error('Unable to find TMDB ID');\n    }\n\n    // We check above if we have the TMDB ID, so we can safely assert the type below\n    return mediaIds as MediaIds;\n  }\n\n  // movies with hama agent actually are tv shows with at least one episode in it\n  // try to get first episode of any season - cannot hardcode season or episode number\n  // because sometimes user can have it in other season/ep than s01e01\n  private async processHamaMovie(metadata: PlexMetadata, tmdbId: number) {\n    const season = metadata.Children?.Metadata[0];\n    if (season) {\n      const episodes = await this.plexClient.getChildrenMetadata(\n        season.ratingKey\n      );\n      if (episodes) {\n        await this.processPlexMovieByTmdbId(episodes[0], tmdbId);\n      }\n    }\n  }\n\n  // this adds all movie episodes from specials season for Hama agent\n  private async processHamaSpecials(metadata: PlexMetadata, tvdbId: number) {\n    const specials = metadata.Children?.Metadata.find(\n      (md) => Number(md.index) === 0\n    );\n    if (specials) {\n      const episodes = await this.plexClient.getChildrenMetadata(\n        specials.ratingKey\n      );\n      if (episodes) {\n        for (const episode of episodes) {\n          const special = animeList.getSpecialEpisode(tvdbId, episode.index);\n          if (special) {\n            if (special.tmdbId) {\n              await this.processPlexMovieByTmdbId(episode, special.tmdbId);\n            } else if (special.imdbId) {\n              const tmdbMovie = await this.tmdb.getMediaByImdbId({\n                imdbId: special.imdbId,\n              });\n              await this.processPlexMovieByTmdbId(episode, tmdbMovie.id);\n            }\n          }\n        }\n      }\n    }\n  }\n\n  // checks if any of this.libraries has Hama agent set in Plex\n  private async hasHamaAgent() {\n    const plexLibraries = await this.plexClient.getLibraries();\n    return this.libraries.some((library) =>\n      plexLibraries.some(\n        (plexLibrary) =>\n          plexLibrary.agent === HAMA_AGENT && library.id === plexLibrary.key\n      )\n    );\n  }\n}\n\nexport const plexFullScanner = new PlexScanner();\nexport const plexRecentScanner = new PlexScanner(true);\n"
  },
  {
    "path": "server/lib/scanners/radarr/index.ts",
    "content": "import type { RadarrMovie } from '@server/api/servarr/radarr';\nimport RadarrAPI from '@server/api/servarr/radarr';\nimport type {\n  RunnableScanner,\n  StatusBase,\n} from '@server/lib/scanners/baseScanner';\nimport BaseScanner from '@server/lib/scanners/baseScanner';\nimport type { RadarrSettings } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport { uniqWith } from 'lodash';\n\ntype SyncStatus = StatusBase & {\n  currentServer: RadarrSettings;\n  servers: RadarrSettings[];\n};\n\nclass RadarrScanner\n  extends BaseScanner<RadarrMovie>\n  implements RunnableScanner<SyncStatus>\n{\n  private servers: RadarrSettings[];\n  private currentServer: RadarrSettings;\n  private radarrApi: RadarrAPI;\n\n  constructor() {\n    super('Radarr Scan', { bundleSize: 50 });\n  }\n\n  public status(): SyncStatus {\n    return {\n      running: this.running,\n      progress: this.progress,\n      total: this.items.length,\n      currentServer: this.currentServer,\n      servers: this.servers,\n    };\n  }\n\n  public async run(): Promise<void> {\n    const settings = getSettings();\n    const sessionId = this.startRun();\n\n    try {\n      this.servers = uniqWith(settings.radarr, (radarrA, radarrB) => {\n        return (\n          radarrA.hostname === radarrB.hostname &&\n          radarrA.port === radarrB.port &&\n          radarrA.baseUrl === radarrB.baseUrl\n        );\n      });\n\n      for (const server of this.servers) {\n        this.currentServer = server;\n        if (server.syncEnabled) {\n          this.log(\n            `Beginning to process Radarr server: ${server.name}`,\n            'info'\n          );\n\n          this.radarrApi = new RadarrAPI({\n            apiKey: server.apiKey,\n            url: RadarrAPI.buildUrl(server, '/api/v3'),\n          });\n\n          this.items = await this.radarrApi.getMovies();\n\n          await this.loop(this.processRadarrMovie.bind(this), { sessionId });\n        } else {\n          this.log(`Sync not enabled. Skipping Radarr server: ${server.name}`);\n        }\n      }\n\n      this.log('Radarr scan complete', 'info');\n    } catch (e) {\n      this.log('Scan interrupted', 'error', { errorMessage: e.message });\n    } finally {\n      this.endRun(sessionId);\n    }\n  }\n\n  private async processRadarrMovie(radarrMovie: RadarrMovie): Promise<void> {\n    if (!radarrMovie.monitored && !radarrMovie.hasFile) {\n      this.log(\n        'Title is unmonitored and has not been downloaded. Skipping item.',\n        'debug',\n        {\n          title: radarrMovie.title,\n        }\n      );\n      return;\n    }\n\n    try {\n      const server4k = this.enable4kMovie && this.currentServer.is4k;\n      await this.processMovie(radarrMovie.tmdbId, {\n        is4k: server4k,\n        serviceId: this.currentServer.id,\n        externalServiceId: radarrMovie.id,\n        externalServiceSlug: radarrMovie.titleSlug,\n        title: radarrMovie.title,\n        processing: !radarrMovie.hasFile,\n      });\n    } catch (e) {\n      this.log('Failed to process Radarr media', 'error', {\n        errorMessage: e.message,\n        title: radarrMovie.title,\n      });\n    }\n  }\n}\n\nexport const radarrScanner = new RadarrScanner();\n"
  },
  {
    "path": "server/lib/scanners/sonarr/index.ts",
    "content": "import { getMetadataProvider } from '@server/api/metadata';\nimport type { SonarrSeries } from '@server/api/servarr/sonarr';\nimport SonarrAPI from '@server/api/servarr/sonarr';\nimport TheMovieDb from '@server/api/themoviedb';\nimport { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants';\nimport type {\n  TmdbKeyword,\n  TmdbTvDetails,\n} from '@server/api/themoviedb/interfaces';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport type {\n  ProcessableSeason,\n  RunnableScanner,\n  StatusBase,\n} from '@server/lib/scanners/baseScanner';\nimport BaseScanner from '@server/lib/scanners/baseScanner';\nimport type { SonarrSettings } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport { uniqWith } from 'lodash';\n\ntype SyncStatus = StatusBase & {\n  currentServer: SonarrSettings;\n  servers: SonarrSettings[];\n};\n\nclass SonarrScanner\n  extends BaseScanner<SonarrSeries>\n  implements RunnableScanner<SyncStatus>\n{\n  private servers: SonarrSettings[];\n  private currentServer: SonarrSettings;\n  private sonarrApi: SonarrAPI;\n\n  constructor() {\n    super('Sonarr Scan', { bundleSize: 50 });\n  }\n\n  public status(): SyncStatus {\n    return {\n      running: this.running,\n      progress: this.progress,\n      total: this.items.length,\n      currentServer: this.currentServer,\n      servers: this.servers,\n    };\n  }\n\n  public async run(): Promise<void> {\n    const settings = getSettings();\n    const sessionId = this.startRun();\n\n    try {\n      this.servers = uniqWith(settings.sonarr, (sonarrA, sonarrB) => {\n        return (\n          sonarrA.hostname === sonarrB.hostname &&\n          sonarrA.port === sonarrB.port &&\n          sonarrA.baseUrl === sonarrB.baseUrl\n        );\n      });\n\n      for (const server of this.servers) {\n        this.currentServer = server;\n        if (server.syncEnabled) {\n          this.log(\n            `Beginning to process Sonarr server: ${server.name}`,\n            'info'\n          );\n\n          this.sonarrApi = new SonarrAPI({\n            apiKey: server.apiKey,\n            url: SonarrAPI.buildUrl(server, '/api/v3'),\n          });\n\n          this.items = await this.sonarrApi.getSeries();\n\n          await this.loop(this.processSonarrSeries.bind(this), { sessionId });\n        } else {\n          this.log(`Sync not enabled. Skipping Sonarr server: ${server.name}`);\n        }\n      }\n\n      this.log('Sonarr scan complete', 'info');\n    } catch (e) {\n      this.log('Scan interrupted', 'error', { errorMessage: e.message });\n    } finally {\n      this.endRun(sessionId);\n    }\n  }\n\n  private async processSonarrSeries(sonarrSeries: SonarrSeries) {\n    try {\n      const mediaRepository = getRepository(Media);\n      const server4k = this.enable4kShow && this.currentServer.is4k;\n      const processableSeasons: ProcessableSeason[] = [];\n      let tvShow: TmdbTvDetails;\n\n      const media = await mediaRepository.findOne({\n        where: { tvdbId: sonarrSeries.tvdbId },\n      });\n\n      if (!media || !media.tmdbId) {\n        tvShow = await this.tmdb.getShowByTvdbId({\n          tvdbId: sonarrSeries.tvdbId,\n        });\n      } else {\n        tvShow = await this.tmdb.getTvShow({ tvId: media.tmdbId });\n      }\n\n      const tmdbId = tvShow.id;\n      const metadataProvider = tvShow.keywords.results.some(\n        (keyword: TmdbKeyword) => keyword.id === ANIME_KEYWORD_ID\n      )\n        ? await getMetadataProvider('anime')\n        : await getMetadataProvider('tv');\n\n      if (!(metadataProvider instanceof TheMovieDb)) {\n        tvShow = await metadataProvider.getTvShow({ tvId: tmdbId });\n      }\n      const settings = getSettings();\n\n      const filteredSeasons = sonarrSeries.seasons.filter(\n        (sn) =>\n          tvShow.seasons.find((s) => s.season_number === sn.seasonNumber) &&\n          (!settings.main.enableSpecialEpisodes ? sn.seasonNumber !== 0 : true)\n      );\n\n      for (const season of filteredSeasons) {\n        const totalAvailableEpisodes = season.statistics?.episodeFileCount ?? 0;\n\n        processableSeasons.push({\n          seasonNumber: season.seasonNumber,\n          episodes: !server4k ? totalAvailableEpisodes : 0,\n          episodes4k: server4k ? totalAvailableEpisodes : 0,\n          totalEpisodes: season.statistics?.totalEpisodeCount ?? 0,\n          processing: season.monitored && totalAvailableEpisodes === 0,\n          is4kOverride: server4k,\n        });\n      }\n\n      await this.processShow(tmdbId, sonarrSeries.tvdbId, processableSeasons, {\n        serviceId: this.currentServer.id,\n        externalServiceId: sonarrSeries.id,\n        externalServiceSlug: sonarrSeries.titleSlug,\n        title: sonarrSeries.title,\n        is4k: server4k,\n      });\n    } catch (e) {\n      this.log('Failed to process Sonarr media', 'error', {\n        errorMessage: e.message,\n        title: sonarrSeries.title,\n      });\n    }\n  }\n}\n\nexport const sonarrScanner = new SonarrScanner();\n"
  },
  {
    "path": "server/lib/search.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport type {\n  TmdbMovieDetails,\n  TmdbMovieResult,\n  TmdbPersonDetails,\n  TmdbPersonResult,\n  TmdbSearchMovieResponse,\n  TmdbSearchMultiResponse,\n  TmdbSearchTvResponse,\n  TmdbTvDetails,\n  TmdbTvResult,\n} from '@server/api/themoviedb/interfaces';\nimport {\n  mapMovieDetailsToResult,\n  mapPersonDetailsToResult,\n  mapTvDetailsToResult,\n} from '@server/models/Search';\nimport {\n  isMovie,\n  isMovieDetails,\n  isTvDetails,\n} from '@server/utils/typeHelpers';\n\ninterface SearchProvider {\n  pattern: RegExp;\n  search: ({\n    id,\n    language,\n    query,\n  }: {\n    id: string;\n    language?: string;\n    query?: string;\n  }) => Promise<TmdbSearchMultiResponse>;\n}\n\nconst searchProviders: SearchProvider[] = [];\n\nexport const findSearchProvider = (\n  query: string\n): SearchProvider | undefined => {\n  return searchProviders.find((provider) => provider.pattern.test(query));\n};\n\nsearchProviders.push({\n  pattern: new RegExp(/(?<=tmdb:)\\d+/),\n  search: async ({ id, language }) => {\n    const tmdb = new TheMovieDb();\n\n    const moviePromise = tmdb.getMovie({ movieId: parseInt(id), language });\n    const tvShowPromise = tmdb.getTvShow({ tvId: parseInt(id), language });\n    const personPromise = tmdb.getPerson({ personId: parseInt(id), language });\n\n    const responses = await Promise.allSettled([\n      moviePromise,\n      tvShowPromise,\n      personPromise,\n    ]);\n\n    const successfulResponses = responses.filter(\n      (r) => r.status === 'fulfilled'\n    ) as (\n      | PromiseFulfilledResult<TmdbMovieDetails>\n      | PromiseFulfilledResult<TmdbTvDetails>\n      | PromiseFulfilledResult<TmdbPersonDetails>\n    )[];\n\n    const results: (TmdbMovieResult | TmdbTvResult | TmdbPersonResult)[] = [];\n\n    if (successfulResponses.length) {\n      results.push(\n        ...successfulResponses.map((r) => {\n          if (isMovieDetails(r.value)) {\n            return mapMovieDetailsToResult(r.value);\n          } else if (isTvDetails(r.value)) {\n            return mapTvDetailsToResult(r.value);\n          } else {\n            return mapPersonDetailsToResult(r.value);\n          }\n        })\n      );\n    }\n\n    return {\n      page: 1,\n      total_pages: 1,\n      total_results: results.length,\n      results,\n    };\n  },\n});\n\nsearchProviders.push({\n  pattern: new RegExp(/(?<=imdb:)(tt|nm)\\d+/),\n  search: async ({ id, language }) => {\n    const tmdb = new TheMovieDb();\n\n    const responses = await tmdb.getByExternalId({\n      externalId: id,\n      type: 'imdb',\n      language,\n    });\n\n    const results: (TmdbMovieResult | TmdbTvResult | TmdbPersonResult)[] = [];\n\n    // set the media_type here since searching by external id doesn't return it\n    results.push(\n      ...(responses.movie_results.map((movie) => ({\n        ...movie,\n        media_type: 'movie',\n      })) as TmdbMovieResult[]),\n      ...(responses.tv_results.map((tv) => ({\n        ...tv,\n        media_type: 'tv',\n      })) as TmdbTvResult[]),\n      ...(responses.person_results.map((person) => ({\n        ...person,\n        media_type: 'person',\n      })) as TmdbPersonResult[])\n    );\n\n    return {\n      page: 1,\n      total_pages: 1,\n      total_results: results.length,\n      results,\n    };\n  },\n});\n\nsearchProviders.push({\n  pattern: new RegExp(/(?<=tvdb:)\\d+/),\n  search: async ({ id, language }) => {\n    const tmdb = new TheMovieDb();\n\n    const responses = await tmdb.getByExternalId({\n      externalId: parseInt(id),\n      type: 'tvdb',\n      language,\n    });\n\n    const results: (TmdbMovieResult | TmdbTvResult | TmdbPersonResult)[] = [];\n\n    // set the media_type here since searching by external id doesn't return it\n    results.push(\n      ...(responses.movie_results.map((movie) => ({\n        ...movie,\n        media_type: 'movie',\n      })) as TmdbMovieResult[]),\n      ...(responses.tv_results.map((tv) => ({\n        ...tv,\n        media_type: 'tv',\n      })) as TmdbTvResult[]),\n      ...(responses.person_results.map((person) => ({\n        ...person,\n        media_type: 'person',\n      })) as TmdbPersonResult[])\n    );\n\n    return {\n      page: 1,\n      total_pages: 1,\n      total_results: results.length,\n      results,\n    };\n  },\n});\n\nsearchProviders.push({\n  pattern: new RegExp(/(?<=year:)\\d{4}/),\n  search: async ({ id: year, query }) => {\n    const tmdb = new TheMovieDb();\n\n    const moviesPromise = tmdb.searchMovies({\n      query: query?.replace(new RegExp(/year:\\d{4}/), '') ?? '',\n      year: parseInt(year),\n    });\n    const tvShowsPromise = tmdb.searchTvShows({\n      query: query?.replace(new RegExp(/year:\\d{4}/), '') ?? '',\n      year: parseInt(year),\n    });\n\n    const responses = await Promise.allSettled([moviesPromise, tvShowsPromise]);\n\n    const successfulResponses = responses.filter(\n      (r) => r.status === 'fulfilled'\n    ) as (\n      | PromiseFulfilledResult<TmdbSearchMovieResponse>\n      | PromiseFulfilledResult<TmdbSearchTvResponse>\n    )[];\n\n    const results: (TmdbMovieResult | TmdbTvResult)[] = [];\n\n    if (successfulResponses.length) {\n      successfulResponses.forEach((response) => {\n        response.value.results.forEach((result) =>\n          // set the media_type here since the search endpoints don't return it\n          results.push(\n            isMovie(result)\n              ? { ...result, media_type: 'movie' }\n              : { ...result, media_type: 'tv' }\n          )\n        );\n      });\n    }\n\n    return {\n      page: 1,\n      total_pages: 1,\n      total_results: results.length,\n      results,\n    };\n  },\n});\n"
  },
  {
    "path": "server/lib/settings/index.ts",
    "content": "import { MediaServerType } from '@server/constants/server';\nimport { Permission } from '@server/lib/permissions';\nimport { runMigrations } from '@server/lib/settings/migrator';\nimport { randomUUID } from 'crypto';\nimport fs from 'fs/promises';\nimport { mergeWith } from 'lodash';\nimport path from 'path';\nimport webpush from 'web-push';\n\n// Prevents stale array entries when incoming data has fewer elements\nconst mergeSettings = <T>(current: T, incoming: Partial<T>): T =>\n  mergeWith({}, current, incoming, (_objValue, srcValue) =>\n    Array.isArray(srcValue) ? srcValue : undefined\n  ) as T;\n\nexport interface Library {\n  id: string;\n  name: string;\n  enabled: boolean;\n  type: 'show' | 'movie';\n  lastScan?: number;\n}\n\nexport interface Region {\n  iso_3166_1: string;\n  english_name: string;\n  name?: string;\n}\n\nexport interface Language {\n  iso_639_1: string;\n  english_name: string;\n  name: string;\n}\n\nexport interface PlexSettings {\n  name: string;\n  machineId?: string;\n  ip: string;\n  port: number;\n  useSsl?: boolean;\n  libraries: Library[];\n  webAppUrl?: string;\n}\n\nexport interface JellyfinSettings {\n  name: string;\n  ip: string;\n  port: number;\n  useSsl?: boolean;\n  urlBase?: string;\n  externalHostname?: string;\n  jellyfinForgotPasswordUrl?: string;\n  libraries: Library[];\n  serverId: string;\n  apiKey: string;\n}\nexport interface TautulliSettings {\n  hostname?: string;\n  port?: number;\n  useSsl?: boolean;\n  urlBase?: string;\n  apiKey?: string;\n  externalUrl?: string;\n}\n\nexport interface DVRSettings {\n  id: number;\n  name: string;\n  hostname: string;\n  port: number;\n  apiKey: string;\n  useSsl: boolean;\n  baseUrl?: string;\n  activeProfileId: number;\n  activeProfileName: string;\n  activeDirectory: string;\n  tags: number[];\n  is4k: boolean;\n  isDefault: boolean;\n  externalUrl?: string;\n  syncEnabled: boolean;\n  preventSearch: boolean;\n  tagRequests: boolean;\n  overrideRule: number[];\n}\n\nexport interface RadarrSettings extends DVRSettings {\n  minimumAvailability: string;\n}\n\nexport interface SonarrSettings extends DVRSettings {\n  seriesType: 'standard' | 'daily' | 'anime';\n  animeSeriesType: 'standard' | 'daily' | 'anime';\n  activeAnimeProfileId?: number;\n  activeAnimeProfileName?: string;\n  activeAnimeDirectory?: string;\n  activeAnimeLanguageProfileId?: number;\n  activeLanguageProfileId?: number;\n  animeTags?: number[];\n  enableSeasonFolders: boolean;\n  monitorNewItems: 'all' | 'none';\n}\n\ninterface Quota {\n  quotaLimit?: number;\n  quotaDays?: number;\n}\n\nexport enum MetadataProviderType {\n  TMDB = 'tmdb',\n  TVDB = 'tvdb',\n}\n\nexport interface MetadataSettings {\n  tv: MetadataProviderType;\n  anime: MetadataProviderType;\n}\n\nexport interface ProxySettings {\n  enabled: boolean;\n  hostname: string;\n  port: number;\n  useSsl: boolean;\n  user: string;\n  password: string;\n  bypassFilter: string;\n  bypassLocalAddresses: boolean;\n}\n\nexport interface MainSettings {\n  apiKey: string;\n  applicationTitle: string;\n  applicationUrl: string;\n  cacheImages: boolean;\n  defaultPermissions: number;\n  defaultQuotas: {\n    movie: Quota;\n    tv: Quota;\n  };\n  hideAvailable: boolean;\n  hideBlocklisted: boolean;\n  localLogin: boolean;\n  mediaServerLogin: boolean;\n  newPlexLogin: boolean;\n  discoverRegion: string;\n  streamingRegion: string;\n  originalLanguage: string;\n  blocklistedTags: string;\n  blocklistedTagsLimit: number;\n  mediaServerType: number;\n  partialRequestsEnabled: boolean;\n  enableSpecialEpisodes: boolean;\n  locale: string;\n  youtubeUrl: string;\n}\n\nexport interface ProxySettings {\n  enabled: boolean;\n  hostname: string;\n  port: number;\n  useSsl: boolean;\n  user: string;\n  password: string;\n  bypassFilter: string;\n  bypassLocalAddresses: boolean;\n}\n\nexport interface DnsCacheSettings {\n  enabled: boolean;\n  forceMinTtl?: number;\n  forceMaxTtl?: number;\n}\n\nexport interface NetworkSettings {\n  csrfProtection: boolean;\n  forceIpv4First: boolean;\n  trustProxy: boolean;\n  proxy: ProxySettings;\n  dnsCache: DnsCacheSettings;\n  apiRequestTimeout: number;\n}\n\ninterface PublicSettings {\n  initialized: boolean;\n}\n\ninterface FullPublicSettings extends PublicSettings {\n  applicationTitle: string;\n  applicationUrl: string;\n  hideAvailable: boolean;\n  hideBlocklisted: boolean;\n  localLogin: boolean;\n  mediaServerLogin: boolean;\n  movie4kEnabled: boolean;\n  series4kEnabled: boolean;\n  discoverRegion: string;\n  streamingRegion: string;\n  originalLanguage: string;\n  mediaServerType: number;\n  jellyfinExternalHost?: string;\n  jellyfinForgotPasswordUrl?: string;\n  jellyfinServerName?: string;\n  partialRequestsEnabled: boolean;\n  enableSpecialEpisodes: boolean;\n  cacheImages: boolean;\n  vapidPublic: string;\n  enablePushRegistration: boolean;\n  locale: string;\n  emailEnabled: boolean;\n  userEmailRequired: boolean;\n  newPlexLogin: boolean;\n  youtubeUrl: string;\n}\n\nexport interface NotificationAgentConfig {\n  enabled: boolean;\n  embedPoster: boolean;\n  types?: number;\n  options: Record<string, unknown>;\n}\nexport interface NotificationAgentDiscord extends NotificationAgentConfig {\n  options: {\n    botUsername?: string;\n    botAvatarUrl?: string;\n    webhookUrl: string;\n    webhookRoleId?: string;\n    enableMentions: boolean;\n  };\n}\n\nexport interface NotificationAgentSlack extends NotificationAgentConfig {\n  options: {\n    webhookUrl: string;\n  };\n}\n\nexport interface NotificationAgentEmail extends NotificationAgentConfig {\n  options: {\n    userEmailRequired: boolean;\n    emailFrom: string;\n    smtpHost: string;\n    smtpPort: number;\n    secure: boolean;\n    ignoreTls: boolean;\n    requireTls: boolean;\n    authUser?: string;\n    authPass?: string;\n    allowSelfSigned: boolean;\n    senderName: string;\n    pgpPrivateKey?: string;\n    pgpPassword?: string;\n  };\n}\n\nexport interface NotificationAgentTelegram extends NotificationAgentConfig {\n  options: {\n    botUsername?: string;\n    botAPI: string;\n    chatId: string;\n    messageThreadId: string;\n    sendSilently: boolean;\n  };\n}\n\nexport interface NotificationAgentPushbullet extends NotificationAgentConfig {\n  options: {\n    accessToken: string;\n    channelTag?: string;\n  };\n}\n\nexport interface NotificationAgentPushover extends NotificationAgentConfig {\n  options: {\n    accessToken: string;\n    userToken: string;\n    sound: string;\n  };\n}\n\nexport interface NotificationAgentWebhook extends NotificationAgentConfig {\n  options: {\n    webhookUrl: string;\n    jsonPayload: string;\n    authHeader?: string;\n    customHeaders?: { key: string; value: string }[];\n    supportVariables?: boolean;\n  };\n}\n\nexport interface NotificationAgentGotify extends NotificationAgentConfig {\n  options: {\n    url: string;\n    token: string;\n    priority: number;\n  };\n}\n\nexport interface NotificationAgentNtfy extends NotificationAgentConfig {\n  options: {\n    url: string;\n    topic: string;\n    authMethodUsernamePassword?: boolean;\n    username?: string;\n    password?: string;\n    authMethodToken?: boolean;\n    token?: string;\n    priority?: number;\n  };\n}\n\nexport enum NotificationAgentKey {\n  DISCORD = 'discord',\n  EMAIL = 'email',\n  GOTIFY = 'gotify',\n  NTFY = 'ntfy',\n  PUSHBULLET = 'pushbullet',\n  PUSHOVER = 'pushover',\n  SLACK = 'slack',\n  TELEGRAM = 'telegram',\n  WEBHOOK = 'webhook',\n  WEBPUSH = 'webpush',\n}\n\ninterface NotificationAgents {\n  discord: NotificationAgentDiscord;\n  email: NotificationAgentEmail;\n  gotify: NotificationAgentGotify;\n  ntfy: NotificationAgentNtfy;\n  pushbullet: NotificationAgentPushbullet;\n  pushover: NotificationAgentPushover;\n  slack: NotificationAgentSlack;\n  telegram: NotificationAgentTelegram;\n  webhook: NotificationAgentWebhook;\n  webpush: NotificationAgentConfig;\n}\n\ninterface NotificationSettings {\n  agents: NotificationAgents;\n}\n\ninterface JobSettings {\n  schedule: string;\n}\n\nexport type JobId =\n  | 'plex-recently-added-scan'\n  | 'plex-full-scan'\n  | 'plex-watchlist-sync'\n  | 'plex-refresh-token'\n  | 'radarr-scan'\n  | 'sonarr-scan'\n  | 'download-sync'\n  | 'download-sync-reset'\n  | 'jellyfin-recently-added-scan'\n  | 'jellyfin-full-scan'\n  | 'image-cache-cleanup'\n  | 'availability-sync'\n  | 'process-blocklisted-tags';\n\nexport interface AllSettings {\n  clientId: string;\n  vapidPublic: string;\n  vapidPrivate: string;\n  main: MainSettings;\n  plex: PlexSettings;\n  jellyfin: JellyfinSettings;\n  tautulli: TautulliSettings;\n  radarr: RadarrSettings[];\n  sonarr: SonarrSettings[];\n  public: PublicSettings;\n  notifications: NotificationSettings;\n  jobs: Record<JobId, JobSettings>;\n  network: NetworkSettings;\n  metadataSettings: MetadataSettings;\n  migrations: string[];\n}\n\nconst SETTINGS_PATH = process.env.CONFIG_DIRECTORY\n  ? `${process.env.CONFIG_DIRECTORY}/settings.json`\n  : path.join(__dirname, '../../../config/settings.json');\n\nclass Settings {\n  private data: AllSettings;\n  private saveLock: Promise<void> = Promise.resolve();\n\n  constructor(initialSettings?: AllSettings) {\n    this.data = {\n      clientId: randomUUID(),\n      vapidPrivate: '',\n      vapidPublic: '',\n      main: {\n        apiKey: '',\n        applicationTitle: 'Seerr',\n        applicationUrl: '',\n        cacheImages: false,\n        defaultPermissions: Permission.REQUEST,\n        defaultQuotas: {\n          movie: {},\n          tv: {},\n        },\n        hideAvailable: false,\n        hideBlocklisted: false,\n        localLogin: true,\n        mediaServerLogin: true,\n        newPlexLogin: true,\n        discoverRegion: '',\n        streamingRegion: '',\n        originalLanguage: '',\n        blocklistedTags: '',\n        blocklistedTagsLimit: 50,\n        mediaServerType: MediaServerType.NOT_CONFIGURED,\n        partialRequestsEnabled: true,\n        enableSpecialEpisodes: false,\n        locale: 'en',\n        youtubeUrl: '',\n      },\n      plex: {\n        name: '',\n        ip: '',\n        port: 32400,\n        useSsl: false,\n        libraries: [],\n      },\n      jellyfin: {\n        name: '',\n        ip: '',\n        port: 8096,\n        useSsl: false,\n        urlBase: '',\n        externalHostname: '',\n        jellyfinForgotPasswordUrl: '',\n        libraries: [],\n        serverId: '',\n        apiKey: '',\n      },\n      tautulli: {},\n      metadataSettings: {\n        tv: MetadataProviderType.TMDB,\n        anime: MetadataProviderType.TMDB,\n      },\n      radarr: [],\n      sonarr: [],\n      public: {\n        initialized: false,\n      },\n      notifications: {\n        agents: {\n          email: {\n            enabled: false,\n            embedPoster: true,\n            options: {\n              userEmailRequired: false,\n              emailFrom: '',\n              smtpHost: '',\n              smtpPort: 587,\n              secure: false,\n              ignoreTls: false,\n              requireTls: false,\n              allowSelfSigned: false,\n              senderName: 'Seerr',\n            },\n          },\n          discord: {\n            enabled: false,\n            embedPoster: true,\n            types: 0,\n            options: {\n              webhookUrl: '',\n              webhookRoleId: '',\n              enableMentions: true,\n            },\n          },\n          slack: {\n            enabled: false,\n            embedPoster: true,\n            types: 0,\n            options: {\n              webhookUrl: '',\n            },\n          },\n          telegram: {\n            enabled: false,\n            embedPoster: true,\n            types: 0,\n            options: {\n              botAPI: '',\n              chatId: '',\n              messageThreadId: '',\n              sendSilently: false,\n            },\n          },\n          pushbullet: {\n            enabled: false,\n            embedPoster: false,\n            types: 0,\n            options: {\n              accessToken: '',\n            },\n          },\n          pushover: {\n            enabled: false,\n            embedPoster: true,\n            types: 0,\n            options: {\n              accessToken: '',\n              userToken: '',\n              sound: '',\n            },\n          },\n          webhook: {\n            enabled: false,\n            embedPoster: true,\n            types: 0,\n            options: {\n              webhookUrl: '',\n              jsonPayload:\n                'IntcbiAgXCJub3RpZmljYXRpb25fdHlwZVwiOiBcInt7bm90aWZpY2F0aW9uX3R5cGV9fVwiLFxuICBcImV2ZW50XCI6IFwie3tldmVudH19XCIsXG4gIFwic3ViamVjdFwiOiBcInt7c3ViamVjdH19XCIsXG4gIFwibWVzc2FnZVwiOiBcInt7bWVzc2FnZX19XCIsXG4gIFwiaW1hZ2VcIjogXCJ7e2ltYWdlfX1cIixcbiAgXCJ7e21lZGlhfX1cIjoge1xuICAgIFwibWVkaWFfdHlwZVwiOiBcInt7bWVkaWFfdHlwZX19XCIsXG4gICAgXCJ0bWRiSWRcIjogXCJ7e21lZGlhX3RtZGJpZH19XCIsXG4gICAgXCJ0dmRiSWRcIjogXCJ7e21lZGlhX3R2ZGJpZH19XCIsXG4gICAgXCJzdGF0dXNcIjogXCJ7e21lZGlhX3N0YXR1c319XCIsXG4gICAgXCJzdGF0dXM0a1wiOiBcInt7bWVkaWFfc3RhdHVzNGt9fVwiXG4gIH0sXG4gIFwie3tyZXF1ZXN0fX1cIjoge1xuICAgIFwicmVxdWVzdF9pZFwiOiBcInt7cmVxdWVzdF9pZH19XCIsXG4gICAgXCJyZXF1ZXN0ZWRCeV9lbWFpbFwiOiBcInt7cmVxdWVzdGVkQnlfZW1haWx9fVwiLFxuICAgIFwicmVxdWVzdGVkQnlfdXNlcm5hbWVcIjogXCJ7e3JlcXVlc3RlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICBcInJlcXVlc3RlZEJ5X2F2YXRhclwiOiBcInt7cmVxdWVzdGVkQnlfYXZhdGFyfX1cIixcbiAgICBcInJlcXVlc3RlZEJ5X3NldHRpbmdzX2Rpc2NvcmRJZFwiOiBcInt7cmVxdWVzdGVkQnlfc2V0dGluZ3NfZGlzY29yZElkfX1cIixcbiAgICBcInJlcXVlc3RlZEJ5X3NldHRpbmdzX3RlbGVncmFtQ2hhdElkXCI6IFwie3tyZXF1ZXN0ZWRCeV9zZXR0aW5nc190ZWxlZ3JhbUNoYXRJZH19XCJcbiAgfSxcbiAgXCJ7e2lzc3VlfX1cIjoge1xuICAgIFwiaXNzdWVfaWRcIjogXCJ7e2lzc3VlX2lkfX1cIixcbiAgICBcImlzc3VlX3R5cGVcIjogXCJ7e2lzc3VlX3R5cGV9fVwiLFxuICAgIFwiaXNzdWVfc3RhdHVzXCI6IFwie3tpc3N1ZV9zdGF0dXN9fVwiLFxuICAgIFwicmVwb3J0ZWRCeV9lbWFpbFwiOiBcInt7cmVwb3J0ZWRCeV9lbWFpbH19XCIsXG4gICAgXCJyZXBvcnRlZEJ5X3VzZXJuYW1lXCI6IFwie3tyZXBvcnRlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICBcInJlcG9ydGVkQnlfYXZhdGFyXCI6IFwie3tyZXBvcnRlZEJ5X2F2YXRhcn19XCIsXG4gICAgXCJyZXBvcnRlZEJ5X3NldHRpbmdzX2Rpc2NvcmRJZFwiOiBcInt7cmVwb3J0ZWRCeV9zZXR0aW5nc19kaXNjb3JkSWR9fVwiLFxuICAgIFwicmVwb3J0ZWRCeV9zZXR0aW5nc190ZWxlZ3JhbUNoYXRJZFwiOiBcInt7cmVwb3J0ZWRCeV9zZXR0aW5nc190ZWxlZ3JhbUNoYXRJZH19XCJcbiAgfSxcbiAgXCJ7e2NvbW1lbnR9fVwiOiB7XG4gICAgXCJjb21tZW50X21lc3NhZ2VcIjogXCJ7e2NvbW1lbnRfbWVzc2FnZX19XCIsXG4gICAgXCJjb21tZW50ZWRCeV9lbWFpbFwiOiBcInt7Y29tbWVudGVkQnlfZW1haWx9fVwiLFxuICAgIFwiY29tbWVudGVkQnlfdXNlcm5hbWVcIjogXCJ7e2NvbW1lbnRlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICBcImNvbW1lbnRlZEJ5X2F2YXRhclwiOiBcInt7Y29tbWVudGVkQnlfYXZhdGFyfX1cIixcbiAgICBcImNvbW1lbnRlZEJ5X3NldHRpbmdzX2Rpc2NvcmRJZFwiOiBcInt7Y29tbWVudGVkQnlfc2V0dGluZ3NfZGlzY29yZElkfX1cIixcbiAgICBcImNvbW1lbnRlZEJ5X3NldHRpbmdzX3RlbGVncmFtQ2hhdElkXCI6IFwie3tjb21tZW50ZWRCeV9zZXR0aW5nc190ZWxlZ3JhbUNoYXRJZH19XCJcbiAgfSxcbiAgXCJ7e2V4dHJhfX1cIjogW11cbn0i',\n            },\n          },\n          webpush: {\n            enabled: false,\n            embedPoster: true,\n            options: {},\n          },\n          gotify: {\n            enabled: false,\n            embedPoster: false,\n            types: 0,\n            options: {\n              url: '',\n              token: '',\n              priority: 0,\n            },\n          },\n          ntfy: {\n            enabled: false,\n            embedPoster: true,\n            types: 0,\n            options: {\n              url: '',\n              topic: '',\n              priority: 3,\n            },\n          },\n        },\n      },\n      jobs: {\n        'plex-recently-added-scan': {\n          schedule: '0 */5 * * * *',\n        },\n        'plex-full-scan': {\n          schedule: '0 0 3 * * *',\n        },\n        'plex-watchlist-sync': {\n          schedule: '0 */3 * * * *',\n        },\n        'plex-refresh-token': {\n          schedule: '0 0 5 * * *',\n        },\n        'radarr-scan': {\n          schedule: '0 0 4 * * *',\n        },\n        'sonarr-scan': {\n          schedule: '0 30 4 * * *',\n        },\n        'availability-sync': {\n          schedule: '0 0 5 * * *',\n        },\n        'download-sync': {\n          schedule: '0 * * * * *',\n        },\n        'download-sync-reset': {\n          schedule: '0 0 1 * * *',\n        },\n        'jellyfin-recently-added-scan': {\n          schedule: '0 */5 * * * *',\n        },\n        'jellyfin-full-scan': {\n          schedule: '0 0 3 * * *',\n        },\n        'image-cache-cleanup': {\n          schedule: '0 0 5 * * *',\n        },\n        'process-blocklisted-tags': {\n          schedule: '0 30 1 */7 * *',\n        },\n      },\n      network: {\n        csrfProtection: false,\n        forceIpv4First: false,\n        trustProxy: false,\n        proxy: {\n          enabled: false,\n          hostname: '',\n          port: 8080,\n          useSsl: false,\n          user: '',\n          password: '',\n          bypassFilter: '',\n          bypassLocalAddresses: true,\n        },\n        dnsCache: {\n          enabled: false,\n          forceMinTtl: 0,\n          forceMaxTtl: -1,\n        },\n        apiRequestTimeout: 10000,\n      },\n      migrations: [],\n    };\n    if (initialSettings) {\n      this.data = mergeSettings(this.data, initialSettings);\n    }\n  }\n\n  get main(): MainSettings {\n    return this.data.main;\n  }\n\n  set main(data: MainSettings) {\n    this.data.main = mergeSettings(this.data.main, data);\n  }\n\n  get plex(): PlexSettings {\n    return this.data.plex;\n  }\n\n  set plex(data: PlexSettings) {\n    this.data.plex = mergeSettings(this.data.plex, data);\n  }\n\n  get jellyfin(): JellyfinSettings {\n    return this.data.jellyfin;\n  }\n\n  set jellyfin(data: JellyfinSettings) {\n    this.data.jellyfin = mergeSettings(this.data.jellyfin, data);\n  }\n\n  get tautulli(): TautulliSettings {\n    return this.data.tautulli;\n  }\n\n  set tautulli(data: TautulliSettings) {\n    this.data.tautulli = mergeSettings(this.data.tautulli, data);\n  }\n\n  get metadataSettings(): MetadataSettings {\n    return this.data.metadataSettings;\n  }\n\n  set metadataSettings(data: MetadataSettings) {\n    this.data.metadataSettings = mergeSettings(\n      this.data.metadataSettings,\n      data\n    );\n  }\n\n  get radarr(): RadarrSettings[] {\n    return this.data.radarr;\n  }\n\n  set radarr(data: RadarrSettings[]) {\n    this.data.radarr = data;\n  }\n\n  get sonarr(): SonarrSettings[] {\n    return this.data.sonarr;\n  }\n\n  set sonarr(data: SonarrSettings[]) {\n    this.data.sonarr = data;\n  }\n\n  get public(): PublicSettings {\n    return this.data.public;\n  }\n\n  set public(data: PublicSettings) {\n    this.data.public = mergeSettings(this.data.public, data);\n  }\n\n  get fullPublicSettings(): FullPublicSettings {\n    return {\n      ...this.data.public,\n      applicationTitle: this.data.main.applicationTitle,\n      applicationUrl: this.data.main.applicationUrl,\n      hideAvailable: this.data.main.hideAvailable,\n      hideBlocklisted: this.data.main.hideBlocklisted,\n      localLogin: this.data.main.localLogin,\n      mediaServerLogin: this.data.main.mediaServerLogin,\n      jellyfinExternalHost: this.data.jellyfin.externalHostname,\n      jellyfinForgotPasswordUrl: this.data.jellyfin.jellyfinForgotPasswordUrl,\n      movie4kEnabled: this.data.radarr.some(\n        (radarr) => radarr.is4k && radarr.isDefault\n      ),\n      series4kEnabled: this.data.sonarr.some(\n        (sonarr) => sonarr.is4k && sonarr.isDefault\n      ),\n      discoverRegion: this.data.main.discoverRegion,\n      streamingRegion: this.data.main.streamingRegion,\n      originalLanguage: this.data.main.originalLanguage,\n      mediaServerType: this.main.mediaServerType,\n      partialRequestsEnabled: this.data.main.partialRequestsEnabled,\n      enableSpecialEpisodes: this.data.main.enableSpecialEpisodes,\n      cacheImages: this.data.main.cacheImages,\n      vapidPublic: this.vapidPublic,\n      enablePushRegistration: this.data.notifications.agents.webpush.enabled,\n      locale: this.data.main.locale,\n      emailEnabled: this.data.notifications.agents.email.enabled,\n      userEmailRequired:\n        this.data.notifications.agents.email.options.userEmailRequired,\n      newPlexLogin: this.data.main.newPlexLogin,\n      youtubeUrl: this.data.main.youtubeUrl,\n    };\n  }\n\n  get notifications(): NotificationSettings {\n    return this.data.notifications;\n  }\n\n  set notifications(data: NotificationSettings) {\n    this.data.notifications = mergeSettings(this.data.notifications, data);\n  }\n\n  get jobs(): Record<JobId, JobSettings> {\n    return this.data.jobs;\n  }\n\n  set jobs(data: Record<JobId, JobSettings>) {\n    this.data.jobs = mergeSettings(this.data.jobs, data);\n  }\n\n  get network(): NetworkSettings {\n    return this.data.network;\n  }\n\n  set network(data: NetworkSettings) {\n    this.data.network = mergeSettings(this.data.network, data);\n  }\n\n  get migrations(): string[] {\n    return this.data.migrations;\n  }\n\n  set migrations(data: string[]) {\n    this.data.migrations = data;\n  }\n\n  get clientId(): string {\n    return this.data.clientId;\n  }\n\n  get vapidPublic(): string {\n    return this.data.vapidPublic;\n  }\n\n  get vapidPrivate(): string {\n    return this.data.vapidPrivate;\n  }\n\n  public async regenerateApiKey(): Promise<MainSettings> {\n    this.main.apiKey = this.generateApiKey();\n    await this.save();\n    return this.main;\n  }\n\n  private generateApiKey(): string {\n    if (process.env.API_KEY) {\n      return process.env.API_KEY;\n    } else {\n      return Buffer.from(`${Date.now()}${randomUUID()}`).toString('base64');\n    }\n  }\n\n  /**\n   * Settings Load\n   *\n   * This will load settings from file unless an optional argument of the object structure\n   * is passed in.\n   * @param overrideSettings If passed in, will override all existing settings with these\n   * @param raw If true, will load the settings without running migrations or generating missing\n   * values\n   */\n  public async load(\n    overrideSettings?: AllSettings,\n    raw = false\n  ): Promise<Settings> {\n    if (overrideSettings) {\n      this.data = overrideSettings;\n      return this;\n    }\n\n    let data;\n    try {\n      data = await fs.readFile(SETTINGS_PATH, 'utf-8');\n    } catch {\n      await this.save();\n    }\n\n    if (data && !raw) {\n      const parsedJson = JSON.parse(data);\n      const migratedData = await runMigrations(parsedJson, SETTINGS_PATH);\n      this.data = mergeSettings(this.data, migratedData);\n    } else if (data) {\n      this.data = JSON.parse(data);\n    }\n\n    // generate keys and ids if it's missing\n    let change = false;\n    if (!this.data.main.apiKey) {\n      this.data.main.apiKey = this.generateApiKey();\n      change = true;\n    } else if (process.env.API_KEY) {\n      if (this.main.apiKey != process.env.API_KEY) {\n        this.main.apiKey = process.env.API_KEY;\n      }\n    }\n    if (!this.data.clientId) {\n      this.data.clientId = randomUUID();\n      change = true;\n    }\n    if (!this.data.vapidPublic || !this.data.vapidPrivate) {\n      const vapidKeys = webpush.generateVAPIDKeys();\n      this.data.vapidPrivate = vapidKeys.privateKey;\n      this.data.vapidPublic = vapidKeys.publicKey;\n      change = true;\n    }\n    if (change) {\n      await this.save();\n    }\n\n    return this;\n  }\n\n  public async save(): Promise<void> {\n    const savePromise = this.saveLock.then(async () => {\n      const tmp = SETTINGS_PATH + '.tmp';\n      await fs.writeFile(tmp, JSON.stringify(this.data, undefined, ' '));\n      await fs.rename(tmp, SETTINGS_PATH);\n    });\n\n    this.saveLock = savePromise.catch(() => {\n      // Keep the chain alive so future saves aren't blocked by past failures\n    });\n\n    return savePromise;\n  }\n}\n\nlet settings: Settings | undefined;\n\nexport const getSettings = (initialSettings?: AllSettings): Settings => {\n  if (!settings) {\n    settings = new Settings(initialSettings);\n  }\n\n  return settings;\n};\n\nexport default Settings;\n"
  },
  {
    "path": "server/lib/settings/migrations/0001_migrate_hostname.ts",
    "content": "import type { AllSettings } from '@server/lib/settings';\n\nconst migrateHostname = (settings: any): AllSettings => {\n  if (settings.jellyfin?.hostname) {\n    const { hostname } = settings.jellyfin;\n    const protocolMatch = hostname.match(/^(https?):\\/\\//i);\n    const useSsl = protocolMatch && protocolMatch[1].toLowerCase() === 'https';\n    const remainingUrl = hostname.replace(/^(https?):\\/\\//i, '');\n    const urlMatch = remainingUrl.match(/^([^:]+)(:([0-9]+))?(\\/.*)?$/);\n\n    delete settings.jellyfin.hostname;\n    if (urlMatch) {\n      const [, ip, , port, urlBase] = urlMatch;\n      settings.jellyfin = {\n        ...settings.jellyfin,\n        ip,\n        port: port || (useSsl ? 443 : 80),\n        useSsl,\n        urlBase: urlBase ? urlBase.replace(/\\/$/, '') : '',\n      };\n    }\n  }\n\n  return settings;\n};\n\nexport default migrateHostname;\n"
  },
  {
    "path": "server/lib/settings/migrations/0002_migrate_apitokens.ts",
    "content": "import JellyfinAPI from '@server/api/jellyfin';\nimport { MediaServerType } from '@server/constants/server';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport type { AllSettings } from '@server/lib/settings';\nimport { getHostname } from '@server/utils/getHostname';\n\nconst migrateApiTokens = async (settings: any): Promise<AllSettings> => {\n  const mediaServerType = settings.main.mediaServerType;\n  if (\n    !settings.jellyfin?.apiKey &&\n    (mediaServerType === MediaServerType.JELLYFIN ||\n      mediaServerType === MediaServerType.EMBY)\n  ) {\n    const userRepository = getRepository(User);\n    const admin = await userRepository.findOne({\n      where: { id: 1 },\n      select: ['id', 'jellyfinAuthToken', 'jellyfinUserId', 'jellyfinDeviceId'],\n      order: { id: 'ASC' },\n    });\n    if (!admin) {\n      return settings;\n    }\n    const jellyfinClient = new JellyfinAPI(\n      getHostname(settings.jellyfin),\n      admin.jellyfinAuthToken,\n      admin.jellyfinDeviceId\n    );\n    jellyfinClient.setUserId(admin.jellyfinUserId ?? '');\n    try {\n      const apiKey = await jellyfinClient.createApiToken('Seerr');\n      settings.jellyfin.apiKey = apiKey;\n    } catch {\n      throw new Error(\n        \"Failed to create Jellyfin API token from admin account. Please check your network configuration or edit your settings.json by adding an 'apiKey' field inside of the 'jellyfin' section to fix this issue.\"\n      );\n    }\n  }\n  return settings;\n};\n\nexport default migrateApiTokens;\n"
  },
  {
    "path": "server/lib/settings/migrations/0003_emby_media_server_type.ts",
    "content": "import { MediaServerType } from '@server/constants/server';\nimport type { AllSettings } from '@server/lib/settings';\n\nconst migrateHostname = (settings: any): AllSettings => {\n  const oldMediaServerType = settings.main.mediaServerType;\n  if (\n    oldMediaServerType === MediaServerType.JELLYFIN &&\n    process.env.JELLYFIN_TYPE === 'emby'\n  ) {\n    settings.main.mediaServerType = MediaServerType.EMBY;\n  }\n\n  return settings;\n};\n\nexport default migrateHostname;\n"
  },
  {
    "path": "server/lib/settings/migrations/0004_migrate_region_setting.ts",
    "content": "import type { AllSettings } from '@server/lib/settings';\n\nconst migrateRegionSetting = (settings: any): AllSettings => {\n  if (\n    settings.main.discoverRegion !== undefined &&\n    settings.main.streamingRegion !== undefined\n  ) {\n    return settings;\n  }\n\n  const oldRegion = settings.main.region;\n  if (oldRegion) {\n    settings.main.discoverRegion = oldRegion;\n    settings.main.streamingRegion = oldRegion;\n  } else {\n    settings.main.discoverRegion = '';\n    settings.main.streamingRegion = 'US';\n  }\n  delete settings.main.region;\n\n  return settings;\n};\n\nexport default migrateRegionSetting;\n"
  },
  {
    "path": "server/lib/settings/migrations/0005_migrate_network_settings.ts",
    "content": "import type { AllSettings } from '@server/lib/settings';\n\nconst migrateNetworkSettings = (settings: any): AllSettings => {\n  if (settings.network) {\n    return settings;\n  }\n  const newSettings = { ...settings };\n  newSettings.network = {\n    ...settings.network,\n    csrfProtection: settings.main.csrfProtection ?? false,\n    trustProxy: settings.main.trustProxy ?? false,\n    forceIpv4First: settings.main.forceIpv4First ?? false,\n    proxy: settings.main.proxy ?? {\n      enabled: false,\n      hostname: '',\n      port: 8080,\n      useSsl: false,\n      user: '',\n      password: '',\n      bypassFilter: '',\n      bypassLocalAddresses: true,\n    },\n  };\n  delete settings.main.csrfProtection;\n  delete settings.main.trustProxy;\n  delete settings.main.forceIpv4First;\n  delete settings.main.proxy;\n  return newSettings;\n};\n\nexport default migrateNetworkSettings;\n"
  },
  {
    "path": "server/lib/settings/migrations/0006_remove_lunasea.ts",
    "content": "import type { AllSettings } from '@server/lib/settings';\n\nconst removeLunaSeaSetting = (settings: any): AllSettings => {\n  if (\n    settings.notifications &&\n    settings.notifications.agents &&\n    settings.notifications.agents.lunasea\n  ) {\n    delete settings.notifications.agents.lunasea;\n  }\n  return settings;\n};\n\nexport default removeLunaSeaSetting;\n"
  },
  {
    "path": "server/lib/settings/migrations/0007_migrate_arr_tags.ts",
    "content": "import RadarrAPI from '@server/api/servarr/radarr';\nimport SonarrAPI from '@server/api/servarr/sonarr';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport type { AllSettings } from '@server/lib/settings';\n\nconst migrationArrTags = async (settings: any): Promise<AllSettings> => {\n  if (\n    Array.isArray(settings.migrations) &&\n    settings.migrations.includes('0007_migrate_arr_tags')\n  ) {\n    return settings;\n  }\n\n  const userRepository = getRepository(User);\n  const users = await userRepository.find();\n\n  let errorOccurred = false;\n\n  for (const radarrSettings of settings.radarr || []) {\n    if (!radarrSettings.tagRequests) {\n      continue;\n    }\n    try {\n      const radarr = new RadarrAPI({\n        apiKey: radarrSettings.apiKey,\n        url: RadarrAPI.buildUrl(radarrSettings, '/api/v3'),\n      });\n      const radarrTags = await radarr.getTags();\n      for (const user of users) {\n        const userTag = radarrTags.find(\n          (v) =>\n            v.label.startsWith(user.id + ' - ') ||\n            v.label.startsWith(user.id + '-')\n        );\n        if (!userTag) {\n          continue;\n        }\n        await radarr.renameTag({\n          id: userTag.id,\n          label:\n            user.id +\n            '-' +\n            user.displayName\n              .normalize('NFD')\n              .replace(/[\\u0300-\\u036f]/g, '')\n              .replace(/\\s+/g, '-')\n              .replace(/[^a-z0-9-]/gi, '')\n              .replace(/-+/g, '-')\n              .replace(/^-|-$/g, ''),\n        });\n      }\n    } catch (error) {\n      console.error(\n        `Unable to rename Radarr tags to the new format. Please check your Radarr connection settings for the instance \"${radarrSettings.name}\".`,\n        error.message\n      );\n      errorOccurred = true;\n    }\n  }\n\n  for (const sonarrSettings of settings.sonarr || []) {\n    if (!sonarrSettings.tagRequests) {\n      continue;\n    }\n    try {\n      const sonarr = new SonarrAPI({\n        apiKey: sonarrSettings.apiKey,\n        url: SonarrAPI.buildUrl(sonarrSettings, '/api/v3'),\n      });\n      const sonarrTags = await sonarr.getTags();\n      for (const user of users) {\n        const userTag = sonarrTags.find(\n          (v) =>\n            v.label.startsWith(user.id + ' - ') ||\n            v.label.startsWith(user.id + '-')\n        );\n        if (!userTag) {\n          continue;\n        }\n        await sonarr.renameTag({\n          id: userTag.id,\n          label:\n            user.id +\n            '-' +\n            user.displayName\n              .normalize('NFD')\n              .replace(/[\\u0300-\\u036f]/g, '')\n              .replace(/\\s+/g, '-')\n              .replace(/[^a-z0-9-]/gi, '')\n              .replace(/-+/g, '-')\n              .replace(/^-|-$/g, ''),\n        });\n      }\n    } catch (error) {\n      console.error(\n        `Unable to rename Sonarr tags to the new format. Please check your Sonarr connection settings for the instance \"${sonarrSettings.name}\".`,\n        error.message\n      );\n      errorOccurred = true;\n    }\n  }\n\n  if (!errorOccurred) {\n    if (!Array.isArray(settings.migrations)) {\n      settings.migrations = [];\n    }\n    settings.migrations.push('0007_migrate_arr_tags');\n  }\n  return settings;\n};\n\nexport default migrationArrTags;\n"
  },
  {
    "path": "server/lib/settings/migrations/0008_migrate_blacklist_to_blocklist.ts",
    "content": "import type { AllSettings } from '@server/lib/settings';\n\nconst migrateBlacklistToBlocklist = (settings: any): AllSettings => {\n  if (\n    Array.isArray(settings.migrations) &&\n    settings.migrations.includes('0008_migrate_blacklist_to_blocklist')\n  ) {\n    return settings;\n  }\n\n  if (settings.main?.hideBlacklisted !== undefined) {\n    settings.main.hideBlocklisted = settings.main.hideBlacklisted;\n    delete settings.main.hideBlacklisted;\n  }\n\n  if (settings.main?.blacklistedTags !== undefined) {\n    settings.main.blocklistedTags = settings.main.blacklistedTags;\n    delete settings.main.blacklistedTags;\n  }\n\n  if (settings.main?.blacklistedTagsLimit !== undefined) {\n    settings.main.blocklistedTagsLimit = settings.main.blacklistedTagsLimit;\n    delete settings.main.blacklistedTagsLimit;\n  }\n\n  if (settings.jobs?.['process-blacklisted-tags']) {\n    settings.jobs['process-blocklisted-tags'] =\n      settings.jobs['process-blacklisted-tags'];\n    delete settings.jobs['process-blacklisted-tags'];\n  }\n\n  if (!Array.isArray(settings.migrations)) {\n    settings.migrations = [];\n  }\n  settings.migrations.push('0008_migrate_blacklist_to_blocklist');\n\n  return settings;\n};\n\nexport default migrateBlacklistToBlocklist;\n"
  },
  {
    "path": "server/lib/settings/migrator.ts",
    "content": "import type { AllSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport fs from 'fs/promises';\nimport path from 'path';\n\nconst migrationsDir = path.join(__dirname, 'migrations');\n\nexport const runMigrations = async (\n  settings: AllSettings,\n  SETTINGS_PATH: string\n): Promise<AllSettings> => {\n  let migrated = settings;\n\n  try {\n    // we read old backup and create a backup of currents settings\n    const BACKUP_PATH = SETTINGS_PATH.replace('.json', '.old.json');\n    let oldBackup: string | null = null;\n    try {\n      oldBackup = await fs.readFile(BACKUP_PATH, 'utf-8');\n    } catch {\n      /* empty */\n    }\n    await fs.writeFile(BACKUP_PATH, JSON.stringify(settings, undefined, ' '));\n\n    const migrations = (await fs.readdir(migrationsDir)).filter(\n      (file) => file.endsWith('.js') || file.endsWith('.ts')\n    );\n\n    const settingsBefore = JSON.stringify(migrated);\n\n    for (const migration of migrations) {\n      try {\n        logger.debug(`Checking migration '${migration}'...`, {\n          label: 'Settings Migrator',\n        });\n        const { default: migrationFn } = await import(\n          path.join(migrationsDir, migration)\n        );\n        const newSettings = await migrationFn(structuredClone(migrated));\n        if (JSON.stringify(migrated) !== JSON.stringify(newSettings)) {\n          logger.debug(`Migration '${migration}' has been applied.`, {\n            label: 'Settings Migrator',\n          });\n        }\n        migrated = newSettings;\n      } catch (e) {\n        // we stop Seerr if the migration failed\n        logger.error(\n          `Error while running migration '${migration}': ${e.message}\\n${e.stack}`,\n          {\n            label: 'Settings Migrator',\n          }\n        );\n        logger.error(\n          'A common cause for this error is a permission issue with your configuration folder, a network issue or a corrupted database.',\n          {\n            label: 'Settings Migrator',\n          }\n        );\n        process.exit();\n      }\n    }\n\n    const settingsAfter = JSON.stringify(migrated);\n\n    if (settingsBefore !== settingsAfter) {\n      // a migration occured\n      // we check that the new config will be saved\n      await fs.writeFile(\n        SETTINGS_PATH,\n        JSON.stringify(migrated, undefined, ' ')\n      );\n      const fileSaved = JSON.parse(await fs.readFile(SETTINGS_PATH, 'utf-8'));\n      if (JSON.stringify(fileSaved) !== settingsAfter) {\n        // something went wrong while saving file\n        throw new Error('Unable to save settings after migration.');\n      }\n    } else if (oldBackup) {\n      // no migration occured\n      // we save the old backup (to avoid settings.json and settings.old.json being the same)\n      await fs.writeFile(BACKUP_PATH, oldBackup.toString());\n    }\n  } catch (e) {\n    // we stop Seerr if the migration failed\n    logger.error(\n      `Something went wrong while running settings migrations: ${e.message}`,\n      {\n        label: 'Settings Migrator',\n      }\n    );\n    logger.error(\n      'A common cause for this issue is a permission error of your configuration folder.',\n      {\n        label: 'Settings Migrator',\n      }\n    );\n    process.exit();\n  }\n\n  return migrated;\n};\n"
  },
  {
    "path": "server/lib/watchlistsync.ts",
    "content": "import PlexTvAPI from '@server/api/plextv';\nimport { MediaStatus, MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport {\n  BlocklistedMediaError,\n  DuplicateMediaRequestError,\n  MediaRequest,\n  NoSeasonsAvailableError,\n  QuotaRestrictedError,\n  RequestPermissionError,\n} from '@server/entity/MediaRequest';\nimport { User } from '@server/entity/User';\nimport logger from '@server/logger';\nimport { Permission } from './permissions';\n\nclass WatchlistSync {\n  public async syncWatchlist() {\n    const userRepository = getRepository(User);\n\n    // Get users who actually have plex tokens\n    const users = await userRepository\n      .createQueryBuilder('user')\n      .addSelect('user.plexToken')\n      .leftJoinAndSelect('user.settings', 'settings')\n      .where(\"user.plexToken != ''\")\n      .getMany();\n\n    for (const user of users) {\n      await this.syncUserWatchlist(user);\n    }\n  }\n\n  private async syncUserWatchlist(user: User) {\n    if (!user.plexToken) {\n      logger.warn('Skipping user watchlist sync for user without plex token', {\n        label: 'Plex Watchlist Sync',\n        user: user.displayName,\n      });\n      return;\n    }\n\n    if (\n      !user.hasPermission(\n        [\n          Permission.AUTO_REQUEST,\n          Permission.AUTO_REQUEST_MOVIE,\n          Permission.AUTO_REQUEST_TV,\n        ],\n        { type: 'or' }\n      )\n    ) {\n      return;\n    }\n\n    if (\n      !user.settings?.watchlistSyncMovies &&\n      !user.settings?.watchlistSyncTv\n    ) {\n      // Skip sync if user settings have it disabled\n      return;\n    }\n\n    const plexTvApi = new PlexTvAPI(user.plexToken);\n\n    const response = await plexTvApi.getWatchlist({ size: 20 });\n\n    const mediaItems = await Media.getRelatedMedia(\n      user,\n      response.items.map((i) => ({\n        tmdbId: i.tmdbId,\n        mediaType: i.type === 'show' ? MediaType.TV : MediaType.MOVIE,\n      }))\n    );\n\n    const watchlistTmdbIds = response.items.map((i) => i.tmdbId);\n\n    const requestRepository = getRepository(MediaRequest);\n    const existingAutoRequests = await requestRepository\n      .createQueryBuilder('request')\n      .leftJoinAndSelect('request.media', 'media')\n      .where('request.requestedBy = :userId', { userId: user.id })\n      .andWhere('request.isAutoRequest = true')\n      .andWhere('media.tmdbId IN (:...tmdbIds)', { tmdbIds: watchlistTmdbIds })\n      .getMany();\n\n    const autoRequestedTmdbIds = new Set(\n      existingAutoRequests\n        .filter((r) => r.media != null)\n        .map((r) => `${r.media.mediaType}:${r.media.tmdbId}`)\n    );\n\n    const unavailableItems = response.items.filter((i) => {\n      const itemMediaType = i.type === 'show' ? MediaType.TV : MediaType.MOVIE;\n\n      return (\n        !autoRequestedTmdbIds.has(`${itemMediaType}:${i.tmdbId}`) &&\n        !mediaItems.find(\n          (m) =>\n            m.tmdbId === i.tmdbId &&\n            m.mediaType === itemMediaType &&\n            (m.status === MediaStatus.BLOCKLISTED ||\n              (itemMediaType === MediaType.MOVIE &&\n                m.status !== MediaStatus.UNKNOWN) ||\n              (itemMediaType === MediaType.TV &&\n                m.status === MediaStatus.AVAILABLE))\n        )\n      );\n    });\n\n    for (const mediaItem of unavailableItems) {\n      try {\n        logger.info(\"Creating media request from user's Plex Watchlist\", {\n          label: 'Watchlist Sync',\n          userId: user.id,\n          mediaTitle: mediaItem.title,\n        });\n\n        if (mediaItem.type === 'show' && !mediaItem.tvdbId) {\n          throw new Error('Missing TVDB ID from Plex Metadata');\n        }\n\n        // Check if they have auto-request permissons and watchlist sync\n        // enabled for the media type\n        if (\n          ((!user.hasPermission(\n            [Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_MOVIE],\n            { type: 'or' }\n          ) ||\n            !user.settings?.watchlistSyncMovies) &&\n            mediaItem.type === 'movie') ||\n          ((!user.hasPermission(\n            [Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_TV],\n            { type: 'or' }\n          ) ||\n            !user.settings?.watchlistSyncTv) &&\n            mediaItem.type === 'show')\n        ) {\n          continue;\n        }\n\n        await MediaRequest.request(\n          {\n            mediaId: mediaItem.tmdbId,\n            mediaType:\n              mediaItem.type === 'show' ? MediaType.TV : MediaType.MOVIE,\n            seasons: mediaItem.type === 'show' ? 'all' : undefined,\n            tvdbId: mediaItem.tvdbId,\n            is4k: false,\n          },\n          user,\n          { isAutoRequest: true }\n        );\n      } catch (e) {\n        if (!(e instanceof Error)) {\n          continue;\n        }\n\n        switch (e.constructor) {\n          // During watchlist sync, these errors aren't necessarily\n          // a problem with Seerr. Since we are auto syncing these constantly, it's\n          // possible they are unexpectedly at their quota limit, for example. So we'll\n          // instead log these as debug messages.\n          case RequestPermissionError:\n          case DuplicateMediaRequestError:\n          case QuotaRestrictedError:\n          case NoSeasonsAvailableError:\n            logger.debug('Failed to create media request from watchlist', {\n              label: 'Watchlist Sync',\n              userId: user.id,\n              mediaTitle: mediaItem.title,\n              errorMessage: e.message,\n            });\n            break;\n          // Blocklisted media should be silently ignored during watchlist sync to avoid spam\n          case BlocklistedMediaError:\n            break;\n          default:\n            logger.error('Failed to create media request from watchlist', {\n              label: 'Watchlist Sync',\n              userId: user.id,\n              mediaTitle: mediaItem.title,\n              errorMessage: e.message,\n            });\n        }\n      }\n    }\n  }\n}\n\nconst watchlistSync = new WatchlistSync();\n\nexport default watchlistSync;\n"
  },
  {
    "path": "server/logger.ts",
    "content": "import path from 'path';\nimport * as winston from 'winston';\nimport 'winston-daily-rotate-file';\n\nconst hformat = winston.format.printf(\n  ({ level, label, message, timestamp, ...metadata }) => {\n    let msg = `${timestamp} [${level}]${\n      label ? `[${label}]` : ''\n    }: ${message} `;\n    if (Object.keys(metadata).length > 0) {\n      msg += JSON.stringify(metadata);\n    }\n    return msg;\n  }\n);\n\nconst logger = winston.createLogger({\n  level: process.env.LOG_LEVEL?.toLowerCase() || 'debug',\n  format: winston.format.combine(\n    winston.format.splat(),\n    winston.format.timestamp(),\n    hformat\n  ),\n  transports: [\n    new winston.transports.Console({\n      format: winston.format.combine(\n        winston.format.colorize(),\n        winston.format.splat(),\n        winston.format.timestamp(),\n        hformat\n      ),\n    }),\n    new winston.transports.DailyRotateFile({\n      filename: process.env.CONFIG_DIRECTORY\n        ? `${process.env.CONFIG_DIRECTORY}/logs/seerr-%DATE%.log`\n        : path.join(__dirname, '../config/logs/seerr-%DATE%.log'),\n      datePattern: 'YYYY-MM-DD',\n      zippedArchive: true,\n      maxSize: '20m',\n      maxFiles: '7d',\n      createSymlink: true,\n      symlinkName: 'seerr.log',\n    }),\n    new winston.transports.DailyRotateFile({\n      filename: process.env.CONFIG_DIRECTORY\n        ? `${process.env.CONFIG_DIRECTORY}/logs/.machinelogs-%DATE%.json`\n        : path.join(__dirname, '../config/logs/.machinelogs-%DATE%.json'),\n      datePattern: 'YYYY-MM-DD',\n      zippedArchive: true,\n      maxSize: '20m',\n      maxFiles: '1d',\n      createSymlink: true,\n      symlinkName: '.machinelogs.json',\n      format: winston.format.combine(\n        winston.format.splat(),\n        winston.format.timestamp(),\n        winston.format.json()\n      ),\n    }),\n  ],\n});\n\nexport default logger;\n"
  },
  {
    "path": "server/middleware/auth.ts",
    "content": "import { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport type {\n  Permission,\n  PermissionCheckOptions,\n} from '@server/lib/permissions';\nimport { getSettings } from '@server/lib/settings';\n\nexport const checkUser: Middleware = async (req, _res, next) => {\n  const settings = getSettings();\n  let user: User | undefined | null;\n\n  if (req.header('X-API-Key') === settings.main.apiKey) {\n    const userRepository = getRepository(User);\n\n    let userId = 1; // Work on original administrator account\n\n    // If a User ID is provided, we will act on that user's behalf\n    if (req.header('X-API-User')) {\n      userId = Number(req.header('X-API-User'));\n    }\n\n    user = await userRepository.findOne({ where: { id: userId } });\n  } else if (req.session?.userId) {\n    const userRepository = getRepository(User);\n\n    user = await userRepository.findOne({\n      where: { id: req.session.userId },\n    });\n  }\n\n  if (user) {\n    req.user = user;\n  }\n\n  req.locale = user?.settings?.locale\n    ? user.settings.locale\n    : settings.main.locale;\n\n  next();\n};\n\nexport const isAuthenticated = (\n  permissions?: Permission | Permission[],\n  options?: PermissionCheckOptions\n): Middleware => {\n  const authMiddleware: Middleware = (req, res, next) => {\n    if (!req.user || !req.user.hasPermission(permissions ?? 0, options)) {\n      res.status(403).json({\n        status: 403,\n        error: 'You do not have permission to access this endpoint',\n      });\n    } else {\n      next();\n    }\n  };\n  return authMiddleware;\n};\n"
  },
  {
    "path": "server/middleware/clearcookies.ts",
    "content": "const clearCookies: Middleware = (_req, res, next) => {\n  res.removeHeader('Set-Cookie');\n  next();\n};\n\nexport default clearCookies;\n"
  },
  {
    "path": "server/middleware/deprecation.ts",
    "content": "import logger from '@server/logger';\nimport type { NextFunction, Request, Response } from 'express';\n\ninterface DeprecationOptions {\n  oldPath: string;\n  newPath: string;\n  sunsetDate?: string;\n  documentationUrl?: string;\n}\n\n/**\n * Mark an API route as deprecated.\n * @see https://datatracker.ietf.org/doc/html/rfc8594\n */\nexport const deprecatedRoute = ({\n  oldPath,\n  newPath,\n  sunsetDate,\n  documentationUrl,\n}: DeprecationOptions) => {\n  return (req: Request, res: Response, next: NextFunction) => {\n    logger.warn(\n      `Deprecated API endpoint accessed: ${oldPath} → use ${newPath} instead`,\n      {\n        label: 'API Deprecation',\n        ip: req.ip,\n        userAgent: req.get('User-Agent'),\n        method: req.method,\n        path: req.originalUrl,\n      }\n    );\n\n    res.setHeader('Deprecation', 'true');\n\n    const links: string[] = [`<${newPath}>; rel=\"successor-version\"`];\n    if (documentationUrl) {\n      links.push(`<${documentationUrl}>; rel=\"deprecation\"`);\n    }\n    res.setHeader('Link', links.join(', '));\n\n    if (sunsetDate) {\n      res.setHeader('Sunset', new Date(sunsetDate).toUTCString());\n    }\n\n    next();\n  };\n};\n\nexport default deprecatedRoute;\n"
  },
  {
    "path": "server/migration/postgres/1734786061496-InitialMigration.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class InitialMigration1734786061496 implements MigrationInterface {\n  name = 'InitialMigration1734786061496';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" SERIAL NOT NULL, \"mediaType\" character varying NOT NULL, \"title\" character varying, \"tmdbId\" integer NOT NULL, \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"PK_04dc42a96bf0914cda31b579702\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season_request\" (\"id\" SERIAL NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT '1', \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), \"requestId\" integer, CONSTRAINT \"PK_4811e502081543bf620f1fa4328\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"media_request\" (\"id\" SERIAL NOT NULL, \"status\" integer NOT NULL, \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), \"type\" character varying NOT NULL, \"is4k\" boolean NOT NULL DEFAULT false, \"serverId\" integer, \"profileId\" integer, \"rootFolder\" character varying, \"languageProfileId\" integer, \"tags\" text, \"isAutoRequest\" boolean NOT NULL DEFAULT false, \"mediaId\" integer NOT NULL, \"requestedById\" integer, \"modifiedById\" integer, CONSTRAINT \"PK_f8334500e8e12db87536558c66c\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season\" (\"id\" SERIAL NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT '1', \"status4k\" integer NOT NULL DEFAULT '1', \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), \"mediaId\" integer NOT NULL, CONSTRAINT \"PK_8ac0d081dbdb7ab02d166bcda9f\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" SERIAL NOT NULL, \"mediaType\" character varying NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" character varying, \"status\" integer NOT NULL DEFAULT '1', \"status4k\" integer NOT NULL DEFAULT '1', \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), \"lastSeasonChange\" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), \"mediaAddedAt\" TIMESTAMP WITH TIME ZONE DEFAULT now(), \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" character varying, \"externalServiceSlug4k\" character varying, \"ratingKey\" character varying, \"ratingKey4k\" character varying, \"jellyfinMediaId\" character varying, \"jellyfinMediaId4k\" character varying, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"), CONSTRAINT \"PK_f4e0fcac36e050de337b670d8bd\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"watchlist\" (\"id\" SERIAL NOT NULL, \"ratingKey\" character varying NOT NULL, \"mediaType\" character varying NOT NULL, \"title\" character varying NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), \"requestedById\" integer, \"mediaId\" integer NOT NULL, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"), CONSTRAINT \"PK_0c8c0dbcc8d379117138e71ad5b\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" SERIAL NOT NULL, \"endpoint\" character varying NOT NULL, \"p256dh\" character varying NOT NULL, \"auth\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"PK_397020e7be9a4086cc798e0bb63\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" SERIAL NOT NULL, \"locale\" character varying NOT NULL DEFAULT '', \"discoverRegion\" character varying, \"streamingRegion\" character varying, \"originalLanguage\" character varying, \"pgpKey\" character varying, \"discordId\" character varying, \"pushbulletAccessToken\" character varying, \"pushoverApplicationToken\" character varying, \"pushoverUserKey\" character varying, \"pushoverSound\" character varying, \"telegramChatId\" character varying, \"telegramSendSilently\" boolean, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"notificationTypes\" text, \"userId\" integer, CONSTRAINT \"REL_986a2b6d3c05eb4091bb8066f7\" UNIQUE (\"userId\"), CONSTRAINT \"PK_00f004f5922a0744d174530d639\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" SERIAL NOT NULL, \"email\" character varying NOT NULL, \"plexUsername\" character varying, \"jellyfinUsername\" character varying, \"username\" character varying, \"password\" character varying, \"resetPasswordGuid\" character varying, \"recoveryLinkExpirationDate\" date, \"userType\" integer NOT NULL DEFAULT '1', \"plexId\" integer, \"jellyfinUserId\" character varying, \"jellyfinDeviceId\" character varying, \"jellyfinAuthToken\" character varying, \"plexToken\" character varying, \"permissions\" integer NOT NULL DEFAULT '0', \"avatar\" character varying NOT NULL, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"), CONSTRAINT \"PK_cace4a159ff9f2512dd42373760\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"issue_comment\" (\"id\" SERIAL NOT NULL, \"message\" text NOT NULL, \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), \"userId\" integer, \"issueId\" integer, CONSTRAINT \"PK_2ad05784e2ae661fa409e5e0248\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"issue\" (\"id\" SERIAL NOT NULL, \"issueType\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT '1', \"problemSeason\" integer NOT NULL DEFAULT '0', \"problemEpisode\" integer NOT NULL DEFAULT '0', \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), \"mediaId\" integer, \"createdById\" integer, \"modifiedById\" integer, CONSTRAINT \"PK_f80e086c249b9f3f3ff2fd321b7\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"discover_slider\" (\"id\" SERIAL NOT NULL, \"type\" integer NOT NULL, \"order\" integer NOT NULL, \"isBuiltIn\" boolean NOT NULL DEFAULT false, \"enabled\" boolean NOT NULL DEFAULT true, \"title\" character varying, \"data\" character varying, \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT \"PK_20a71a098d04bae448e4d51db23\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"session\" (\"expiredAt\" bigint NOT NULL, \"id\" character varying(255) NOT NULL, \"json\" text NOT NULL, CONSTRAINT \"PK_f55da76ac1c3ac420f444d2ff11\" PRIMARY KEY (\"id\"))`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_28c5d1d16da7908c97c9bc2f74\" ON \"session\" (\"expiredAt\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" ADD CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" ADD CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season_request\" ADD CONSTRAINT \"FK_6f14737e346d6b27d8e50d2157a\" FOREIGN KEY (\"requestId\") REFERENCES \"media_request\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" ADD CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" ADD CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" ADD CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\"(\"id\") ON DELETE SET NULL ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" ADD CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" ADD CONSTRAINT \"FK_ae34e6b153a90672eb9dc4857d7\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" ADD CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" ADD CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" ADD CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"issue_comment\" ADD CONSTRAINT \"FK_707b033c2d0653f75213614789d\" FOREIGN KEY (\"userId\") REFERENCES \"user\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"issue_comment\" ADD CONSTRAINT \"FK_180710fead1c94ca499c57a7d42\" FOREIGN KEY (\"issueId\") REFERENCES \"issue\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"issue\" ADD CONSTRAINT \"FK_276e20d053f3cff1645803c95d8\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"issue\" ADD CONSTRAINT \"FK_10b17b49d1ee77e7184216001e0\" FOREIGN KEY (\"createdById\") REFERENCES \"user\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"issue\" ADD CONSTRAINT \"FK_da88a1019c850d1a7b143ca02e5\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"issue\" DROP CONSTRAINT \"FK_da88a1019c850d1a7b143ca02e5\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"issue\" DROP CONSTRAINT \"FK_10b17b49d1ee77e7184216001e0\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"issue\" DROP CONSTRAINT \"FK_276e20d053f3cff1645803c95d8\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"issue_comment\" DROP CONSTRAINT \"FK_180710fead1c94ca499c57a7d42\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"issue_comment\" DROP CONSTRAINT \"FK_707b033c2d0653f75213614789d\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" DROP CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" DROP CONSTRAINT \"FK_03f7958328e311761b0de675fbe\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" DROP CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" DROP CONSTRAINT \"FK_ae34e6b153a90672eb9dc4857d7\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" DROP CONSTRAINT \"FK_087099b39600be695591da9a49c\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" DROP CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" DROP CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" DROP CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season_request\" DROP CONSTRAINT \"FK_6f14737e346d6b27d8e50d2157a\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" DROP CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" DROP CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_28c5d1d16da7908c97c9bc2f74\"`\n    );\n    await queryRunner.query(`DROP TABLE \"session\"`);\n    await queryRunner.query(`DROP TABLE \"discover_slider\"`);\n    await queryRunner.query(`DROP TABLE \"issue\"`);\n    await queryRunner.query(`DROP TABLE \"issue_comment\"`);\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_939f205946256cc0d2a1ac51a8\"`\n    );\n    await queryRunner.query(`DROP TABLE \"watchlist\"`);\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_7ff2d11f6a83cb52386eaebe74\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_41a289eb1fa489c1bc6f38d9c3\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_7157aad07c73f6a6ae3bbd5ef5\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`DROP TABLE \"season\"`);\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(`DROP TABLE \"season_request\"`);\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_6bbafa28411e6046421991ea21\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1734786596045-AddTelegramMessageThreadId.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddTelegramMessageThreadId1734786596045 implements MigrationInterface {\n  name = 'AddTelegramMessageThreadId1734786596045';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" ADD \"telegramMessageThreadId\" character varying`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" DROP COLUMN \"telegramMessageThreadId\"`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1734805738349-AddOverrideRules.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddOverrideRules1734805738349 implements MigrationInterface {\n  name = 'AddOverrideRules1734805738349';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"override_rule\" (\"id\" SERIAL NOT NULL, \"radarrServiceId\" integer, \"sonarrServiceId\" integer, \"users\" character varying, \"genre\" character varying, \"language\" character varying, \"keywords\" character varying, \"profileId\" integer, \"rootFolder\" character varying, \"tags\" character varying, \"createdAt\" TIMESTAMP NOT NULL DEFAULT now(), \"updatedAt\" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT \"PK_657f810c7b20a4fce45aee8f182\" PRIMARY KEY (\"id\"))`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP TABLE \"override_rule\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1734809898562-FixNullFields.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class FixNullFields1734809898562 implements MigrationInterface {\n  name = 'FixNullFields1734809898562';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" DROP CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" ALTER COLUMN \"mediaId\" DROP NOT NULL`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" DROP CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" ALTER COLUMN \"mediaId\" DROP NOT NULL`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" DROP CONSTRAINT \"FK_087099b39600be695591da9a49c\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" ALTER COLUMN \"mediaId\" DROP NOT NULL`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" ADD CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" ADD CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" ADD CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"season\" DROP CONSTRAINT \"FK_087099b39600be695591da9a49c\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" DROP CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" DROP CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" ALTER COLUMN \"mediaId\" SET NOT NULL`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" ADD CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" ALTER COLUMN \"mediaId\" SET NOT NULL`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" ADD CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" ALTER COLUMN \"mediaId\" SET NOT NULL`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" ADD CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1737320080282-AddBlacklistTagsColumn.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddBlacklistTagsColumn1737320080282 implements MigrationInterface {\n  name = 'AddBlacklistTagsColumn1737320080282';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" ADD blacklistedTags character varying`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" DROP COLUMN blacklistedTags`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1743023615532-UpdateWebPush.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class UpdateWebPush1743023615532 implements MigrationInterface {\n  name = 'UpdateWebPush1743023615532';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" ADD \"userAgent\" character varying`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" ADD \"createdAt\" TIMESTAMP DEFAULT now()`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" DROP CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" ADD CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\")`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" DROP COLUMN \"createdAt\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" DROP COLUMN \"userAgent\"`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1743107707465-AddUserAvatarCacheFields.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUserAvatarCacheFields1743107707465 implements MigrationInterface {\n  name = 'AddUserAvatarCacheFields1743107707465';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user\" ADD \"avatarETag\" character varying`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user\" ADD \"avatarVersion\" character varying`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`ALTER TABLE \"user\" DROP COLUMN \"avatarVersion\"`);\n    await queryRunner.query(`ALTER TABLE \"user\" DROP COLUMN \"avatarETag\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1745492376568-UpdateWebPush.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class UpdateWebPush1745492376568 implements MigrationInterface {\n  name = 'UpdateWebPush1745492376568';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" RENAME COLUMN \"blacklistedtags\" TO \"blacklistedTags\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" RENAME COLUMN \"blacklistedTags\" TO \"blacklistedtags\"`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1746811308203-FixIssueTimestamps.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class FixIssueTimestamps1746811308203 implements MigrationInterface {\n  name = 'FixIssueTimestamps1746811308203';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`\n        ALTER TABLE \"watchlist\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"watchlist\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"override_rule\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"override_rule\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"season_request\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"season_request\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"media_request\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"media_request\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"user_push_subscription\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"user\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"user\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"blacklist\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"season\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"season\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"media\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"media\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"issue\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"issue\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"issue_comment\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"issue_comment\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"discover_slider\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"discover_slider\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP WITH TIME ZONE\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`\n        ALTER TABLE \"discover_slider\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"discover_slider\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"issue_comment\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"issue_comment\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"issue\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"issue\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"media\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"media\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"season\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"season\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"blacklist\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"user\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"user\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"user_push_subscription\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"media_request\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"media_request\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"season_request\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"season_request\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"override_rule\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"override_rule\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"watchlist\"\n        ALTER COLUMN \"updatedAt\" TYPE TIMESTAMP\n        USING \"updatedAt\" AT TIME ZONE 'UTC'\n      `);\n    await queryRunner.query(`\n        ALTER TABLE \"watchlist\"\n        ALTER COLUMN \"createdAt\" TYPE TIMESTAMP\n        USING \"createdAt\" AT TIME ZONE 'UTC'\n      `);\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1765233385034-AddUniqueConstraintToPushSubscription.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUniqueConstraintToPushSubscription1765233385034 implements MigrationInterface {\n  name = 'AddUniqueConstraintToPushSubscription1765233385034';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`\n      DELETE FROM \"user_push_subscription\"\n      WHERE id NOT IN (\n        SELECT MAX(id)\n        FROM \"user_push_subscription\"\n        GROUP BY \"endpoint\", \"userId\"\n      )\n    `);\n\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" ADD CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\")`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" DROP CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\"`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1770627987304-AddPerformanceIndexes.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddPerformanceIndexes1770627987304 implements MigrationInterface {\n  name = 'AddPerformanceIndexes1770627987304';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_4c696e8ed36ae34fe18abe59d2\" ON \"media_request\" (\"status\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_c730c2d67f271a372c39a07b7e\" ON \"media\" (\"status\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_5d6218de4f547909391a5c1347\" ON \"media\" (\"status4k\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_f8233358694d1677a67899b90a\" ON \"media\" (\"tmdbId\", \"mediaType\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_f8233358694d1677a67899b90a\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_5d6218de4f547909391a5c1347\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_c730c2d67f271a372c39a07b7e\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_4c696e8ed36ae34fe18abe59d2\"`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1771080196816-RenameBlacklistToBlocklist.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class RenameBlacklistToBlocklist1771080196816 implements MigrationInterface {\n  name = 'RenameBlacklistToBlocklist1771080196816';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`ALTER TABLE \"blacklist\" RENAME TO \"blocklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" RENAME COLUMN \"blacklistedTags\" TO \"blocklistedTags\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" RENAME COLUMN \"blocklistedTags\" TO \"blacklistedTags\"`\n    );\n    await queryRunner.query(`ALTER TABLE \"blocklist\" RENAME TO \"blacklist\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1771259406751-AddForeignKeyIndexes.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddForeignKeyIndexes1771259406751 implements MigrationInterface {\n  name = 'AddForeignKeyIndexes1771259406751';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" DROP CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" DROP CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_6bbafa28411e6046421991ea21\"`\n    );\n    await queryRunner.query(\n      `CREATE SEQUENCE IF NOT EXISTS \"blocklist_id_seq\" OWNED BY \"blocklist\".\"id\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ALTER COLUMN \"id\" SET DEFAULT nextval('\"blocklist_id_seq\"')`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ALTER COLUMN \"id\" DROP DEFAULT`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_ae34e6b153a90672eb9dc4857d\" ON \"watchlist\" (\"requestedById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6641da8d831b93dfcb429f8b8b\" ON \"watchlist\" (\"mediaId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_707b033c2d0653f75213614789\" ON \"issue_comment\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_180710fead1c94ca499c57a7d4\" ON \"issue_comment\" (\"issueId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_53d04c07c3f4f54eae372ed665\" ON \"issue\" (\"issueType\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_276e20d053f3cff1645803c95d\" ON \"issue\" (\"mediaId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_10b17b49d1ee77e7184216001e\" ON \"issue\" (\"createdById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_da88a1019c850d1a7b143ca02e\" ON \"issue\" (\"modifiedById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6f14737e346d6b27d8e50d2157\" ON \"season_request\" (\"requestId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_a1aa713f41c99e9d10c48da75a\" ON \"media_request\" (\"mediaId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6997bee94720f1ecb7f3113709\" ON \"media_request\" (\"requestedById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_f4fc4efa14c3ba2b29c4525fa1\" ON \"media_request\" (\"modifiedById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_03f7958328e311761b0de675fb\" ON \"user_push_subscription\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_087099b39600be695591da9a49\" ON \"season\" (\"mediaId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ADD CONSTRAINT \"FK_356721a49f145aa439c16e6b999\" FOREIGN KEY (\"userId\") REFERENCES \"user\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ADD CONSTRAINT \"FK_5c8af2d0e83b3be6d250eccc19d\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" DROP CONSTRAINT \"FK_5c8af2d0e83b3be6d250eccc19d\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" DROP CONSTRAINT \"FK_356721a49f145aa439c16e6b999\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_087099b39600be695591da9a49\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_356721a49f145aa439c16e6b99\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_09b94c932e84635c5461f3c0a9\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_03f7958328e311761b0de675fb\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_f4fc4efa14c3ba2b29c4525fa1\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_6997bee94720f1ecb7f3113709\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_a1aa713f41c99e9d10c48da75a\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_6f14737e346d6b27d8e50d2157\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_da88a1019c850d1a7b143ca02e\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_10b17b49d1ee77e7184216001e\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_276e20d053f3cff1645803c95d\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_53d04c07c3f4f54eae372ed665\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_180710fead1c94ca499c57a7d4\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_707b033c2d0653f75213614789\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_6641da8d831b93dfcb429f8b8b\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX \"public\".\"IDX_ae34e6b153a90672eb9dc4857d\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ALTER COLUMN \"id\" SET DEFAULT nextval('blacklist_id_seq')`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ALTER COLUMN \"id\" DROP DEFAULT`\n    );\n    await queryRunner.query(`DROP SEQUENCE \"blocklist_id_seq\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ADD CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\"(\"id\") ON DELETE CASCADE ON UPDATE NO ACTION`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ADD CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1771337333450-RecoveryLinkExpirationDateTime.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class RecoveryLinkExpirationDateTime1771337333450 implements MigrationInterface {\n  name = 'RecoveryLinkExpirationDateTime1771337333450';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user\" ALTER COLUMN \"recoveryLinkExpirationDate\" TYPE TIMESTAMP WITH TIME ZONE`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user\" ALTER COLUMN \"recoveryLinkExpirationDate\" TYPE date USING (\"recoveryLinkExpirationDate\"::date)`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1772000000000-FixBlocklistIdDefault.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class FixBlocklistIdDefault1772000000000 implements MigrationInterface {\n  name = 'FixBlocklistIdDefault1772000000000';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ALTER COLUMN \"id\" SET DEFAULT nextval('public.\"blocklist_id_seq\"'::regclass)`\n    );\n\n    await queryRunner.query(\n      `SELECT setval('public.\"blocklist_id_seq\"', COALESCE((SELECT MAX(\"id\") FROM \"blocklist\"), 0) + 1, false)`\n    );\n  }\n\n  public async down(): Promise<void> {\n    // Intentionally left empty: dropping the DEFAULT on blocklist.id would\n    // reintroduce the original bug and break blocklist inserts.\n  }\n}\n"
  },
  {
    "path": "server/migration/postgres/1772048000333-AddMediaTypeToUniqueConstraints.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddMediaTypeToUniqueConstraints1772048000333 implements MigrationInterface {\n  name = 'AddMediaTypeToUniqueConstraints1772048000333';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    // Manually added: TypeORM migration:generate does not detect changes to named unique constraints.\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" DROP CONSTRAINT \"UNIQUE_USER_DB\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" ADD CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"mediaType\", \"requestedById\")`\n    );\n\n    // Auto-generated by TypeORM\n    await queryRunner.query(\n      `CREATE SEQUENCE IF NOT EXISTS \"blocklist_id_seq\" OWNED BY \"blocklist\".\"id\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ALTER COLUMN \"id\" SET DEFAULT nextval('\"blocklist_id_seq\"')`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" DROP CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ADD CONSTRAINT \"UQ_81504e02db89b4c1e3152729fa6\" UNIQUE (\"tmdbId\", \"mediaType\")`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    // Manually added: TypeORM migration:generate does not detect changes to named unique constraints.\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" DROP CONSTRAINT \"UNIQUE_USER_DB\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" ADD CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\")`\n    );\n\n    // Auto-generated by TypeORM\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" DROP CONSTRAINT \"UQ_81504e02db89b4c1e3152729fa6\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ADD CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\")`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" ALTER COLUMN \"id\" DROP DEFAULT`\n    );\n    await queryRunner.query(`DROP SEQUENCE \"blocklist_id_seq\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1603944374840-InitialMigration.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class InitialMigration1603944374840 implements MigrationInterface {\n  name = 'InitialMigration1603944374840';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar NOT NULL, \"plexId\" integer NOT NULL, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestId\" integer)`\n    );\n    await queryRunner.query(\n      `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)`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT \"UQ_7157aad07c73f6a6ae3bbd5ef5e\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"), CONSTRAINT \"UQ_7ff2d11f6a83cb52386eaebe74b\" UNIQUE (\"imdbId\"))`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"session\" (\"expiredAt\" bigint NOT NULL, \"id\" varchar(255) PRIMARY KEY NOT NULL, \"json\" text NOT NULL)`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_28c5d1d16da7908c97c9bc2f74\" ON \"session\" (\"expiredAt\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestId\" integer, CONSTRAINT \"FK_6f14737e346d6b27d8e50d2157a\" FOREIGN KEY (\"requestId\") REFERENCES \"media_request\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"season_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_season_request\" RENAME TO \"season_request\"`\n    );\n    await queryRunner.query(\n      `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, CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"temporary_media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"season_request\" RENAME TO \"temporary_season_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestId\" integer)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"temporary_season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_season_request\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_28c5d1d16da7908c97c9bc2f74\"`);\n    await queryRunner.query(`DROP TABLE \"session\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(`DROP TABLE \"season_request\"`);\n    await queryRunner.query(`DROP TABLE \"user\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1605085519544-SeasonStatus.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class SeasonStatus1605085519544 implements MigrationInterface {\n  name = 'SeasonStatus1605085519544';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"season\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer)`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP TABLE \"season\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1606730060700-CascadeMigration.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class CascadeMigration1606730060700 implements MigrationInterface {\n  name = 'CascadeMigration1606730060700';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestId\" integer)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"season_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_season_request\" RENAME TO \"season_request\"`\n    );\n    await queryRunner.query(\n      `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, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestId\" integer, CONSTRAINT \"FK_6f14737e346d6b27d8e50d2157a\" FOREIGN KEY (\"requestId\") REFERENCES \"media_request\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"season_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_season_request\" RENAME TO \"season_request\"`\n    );\n    await queryRunner.query(\n      `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, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_season\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_season\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\" FROM \"season\"`\n    );\n    await queryRunner.query(`DROP TABLE \"season\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_season\" RENAME TO \"season\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"season\" RENAME TO \"temporary_season\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"season\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\" FROM \"temporary_season\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_season\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"temporary_media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"season_request\" RENAME TO \"temporary_season_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestId\" integer)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"temporary_season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_season_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"temporary_media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"season_request\" RENAME TO \"temporary_season_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestId\" integer, CONSTRAINT \"FK_6f14737e346d6b27d8e50d2157a\" FOREIGN KEY (\"requestId\") REFERENCES \"media_request\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"temporary_season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_season_request\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1607928251245-DropImdbIdConstraint.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\nimport { TableUnique } from 'typeorm';\n\nexport class DropImdbIdConstraint1607928251245 implements MigrationInterface {\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.dropUniqueConstraint(\n      'media',\n      'UQ_7ff2d11f6a83cb52386eaebe74b'\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.createUniqueConstraint(\n      'media',\n      new TableUnique({\n        name: 'UQ_7ff2d11f6a83cb52386eaebe74b',\n        columnNames: ['imdbId'],\n      })\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1608217312474-AddUserRequestDeleteCascades.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUserRequestDeleteCascades1608219049304 implements MigrationInterface {\n  name = 'AddUserRequestDeleteCascades1608219049304';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `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, CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE SET NULL ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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, CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"temporary_media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1608477467935-AddLastSeasonChangeMedia.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddLastSeasonChangeMedia1608477467935 implements MigrationInterface {\n  name = 'AddLastSeasonChangeMedia1608477467935';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_7157aad07c73f6a6ae3bbd5ef5e\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT \"UQ_7157aad07c73f6a6ae3bbd5ef5e\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1608477467936-ForceDropImdbUniqueConstraint.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class ForceDropImdbUniqueConstraint1608477467935 implements MigrationInterface {\n  name = 'ForceDropImdbUniqueConstraint1608477467936';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_7157aad07c73f6a6ae3bbd5ef5e\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT \"UQ_7157aad07c73f6a6ae3bbd5ef5e\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1609236552057-RemoveTmdbIdUniqueConstraint.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class RemoveTmdbIdUniqueConstraint1609236552057 implements MigrationInterface {\n  name = 'RemoveTmdbIdUniqueConstraint1609236552057';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"), CONSTRAINT \"UQ_7157aad07c73f6a6ae3bbd5ef5e\" UNIQUE (\"tmdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1610070934506-LocalUsers.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class LocalUsers1610070934506 implements MigrationInterface {\n  name = 'LocalUsers1610070934506';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar NOT NULL, \"plexId\" integer NOT NULL, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar NOT NULL, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar NOT NULL, \"plexId\" integer NOT NULL, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar NOT NULL, \"plexId\" integer NOT NULL, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1610370640747-Add4kStatusFields.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class Add4kStatusFields1610370640747 implements MigrationInterface {\n  name = 'Add4kStatusFields1610370640747';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_season\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, \"status4k\" integer NOT NULL DEFAULT (1), CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_season\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\" FROM \"season\"`\n    );\n    await queryRunner.query(`DROP TABLE \"season\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_season\" RENAME TO \"season\"`\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `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, 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)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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, 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)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\" FROM \"temporary_media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" RENAME TO \"temporary_season\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"season\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\" FROM \"temporary_season\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_season\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1610522845513-AddMediaAddedFieldToMedia.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddMediaAddedFieldToMedia1610522845513 implements MigrationInterface {\n  name = 'AddMediaAddedFieldToMedia1610522845513';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1611508672722-AddDisplayNameToUser.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddDisplayNameToUser1611508672722 implements MigrationInterface {\n  name = 'AddDisplayNameToUser1611508672722';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar NOT NULL, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"username\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\") SELECT \"id\", \"email\", \"\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar NOT NULL, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar NOT NULL, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1611757511674-SonarrRadarrSyncServiceFields.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class SonarrRadarrSyncServiceFields1611757511674 implements MigrationInterface {\n  name = 'SonarrRadarrSyncServiceFields1611757511674';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1611801511397-AddRatingKeysToMedia.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddRatingKeysToMedia1611801511397 implements MigrationInterface {\n  name = 'AddRatingKeysToMedia1611801511397';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1612482778137-AddResetPasswordGuidAndExpiryDate.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddResetPasswordGuidAndExpiryDate1612482778137 implements MigrationInterface {\n  name = 'AddResetPasswordGuidAndExpiryDate1612482778137';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1612571545781-AddLanguageProfileId.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddLanguageProfileId1612571545781 implements MigrationInterface {\n  name = 'AddLanguageProfileId1612571545781';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `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, CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE SET NULL ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\" FROM \"media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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, CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE SET NULL ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\" FROM \"temporary_media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1613379909641-AddJellyfinUserParams.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddJellyfinUserParams1613379909641 implements MigrationInterface {\n  name = 'AddJellyfinUserParams1613379909641';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      'CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"jellyfinUsername\" varchar, \"jellyfinId\" varchar, \"jellyfinAuthToken\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\" FROM \"user\"'\n    );\n    await queryRunner.query('DROP TABLE \"user\"');\n    await queryRunner.query('ALTER TABLE \"temporary_user\" RENAME TO \"user\"');\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query(\n      'CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaID\" varchar, \"jellyfinMediaID4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"media\"'\n    );\n    await queryRunner.query('DROP TABLE \"media\"');\n    await queryRunner.query('ALTER TABLE \"temporary_media\" RENAME TO \"media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query('ALTER TABLE \"media\" RENAME TO \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"status4k\" integer NOT NULL DEFAULT (1), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"status4k\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"temporary_media\"'\n    );\n    await queryRunner.query('DROP TABLE \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n    await queryRunner.query('ALTER TABLE \"user\" RENAME TO \"temporary_user\"');\n    await queryRunner.query(\n      'CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\" FROM \"temporary_user\"'\n    );\n    await queryRunner.query('DROP TABLE \"temporary_user\"');\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1613412948344-ServerTypeEnum.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class ServerTypeEnum1613412948344 implements MigrationInterface {\n  name = 'ServerTypeEnum1613412948344';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query(\n      'CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"media\"'\n    );\n    await queryRunner.query('DROP TABLE \"media\"');\n    await queryRunner.query('ALTER TABLE \"temporary_media\" RENAME TO \"media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query(\n      'CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaID\" varchar, \"jellyfinMediaID4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"media\"'\n    );\n    await queryRunner.query('DROP TABLE \"media\"');\n    await queryRunner.query('ALTER TABLE \"temporary_media\" RENAME TO \"media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query('ALTER TABLE \"media\" RENAME TO \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"temporary_media\"'\n    );\n    await queryRunner.query('DROP TABLE \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query('ALTER TABLE \"media\" RENAME TO \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaId\" varchar, \"jellyfinMediaId4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"temporary_media\"'\n    );\n    await queryRunner.query('DROP TABLE \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1613615266968-CreateUserSettings.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class CreateUserSettings1613615266968 implements MigrationInterface {\n  name = 'CreateUserSettings1613615266968';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"enableNotifications\" boolean NOT NULL DEFAULT (1), \"discordId\" varchar, \"userId\" integer, CONSTRAINT \"REL_986a2b6d3c05eb4091bb8066f7\" UNIQUE (\"userId\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"enableNotifications\" boolean NOT NULL DEFAULT (1), \"discordId\" varchar, \"userId\" integer, CONSTRAINT \"REL_986a2b6d3c05eb4091bb8066f7\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"enableNotifications\", \"discordId\", \"userId\") SELECT \"id\", \"enableNotifications\", \"discordId\", \"userId\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"enableNotifications\" boolean NOT NULL DEFAULT (1), \"discordId\" varchar, \"userId\" integer, CONSTRAINT \"REL_986a2b6d3c05eb4091bb8066f7\" UNIQUE (\"userId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"enableNotifications\", \"discordId\", \"userId\") SELECT \"id\", \"enableNotifications\", \"discordId\", \"userId\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1613670041760-AddJellyfinDeviceId.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddJellyfinDeviceId1613670041760 implements MigrationInterface {\n  name = 'AddJellyfinDeviceId1613670041760';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      'CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\" FROM \"user\"'\n    );\n    await queryRunner.query('DROP TABLE \"user\"');\n    await queryRunner.query('ALTER TABLE \"temporary_user\" RENAME TO \"user\"');\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query(\n      'CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"media\"'\n    );\n    await queryRunner.query('DROP TABLE \"media\"');\n    await queryRunner.query('ALTER TABLE \"temporary_media\" RENAME TO \"media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\" FROM \"user\"'\n    );\n    await queryRunner.query('DROP TABLE \"user\"');\n    await queryRunner.query('ALTER TABLE \"temporary_user\" RENAME TO \"user\"');\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query(\n      'CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaId\" varchar, \"jellyfinMediaId4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"media\"'\n    );\n    await queryRunner.query('DROP TABLE \"media\"');\n    await queryRunner.query('ALTER TABLE \"temporary_media\" RENAME TO \"media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query('ALTER TABLE \"media\" RENAME TO \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"temporary_media\"'\n    );\n    await queryRunner.query('DROP TABLE \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n    await queryRunner.query('ALTER TABLE \"user\" RENAME TO \"temporary_user\"');\n    await queryRunner.query(\n      'CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\" FROM \"temporary_user\"'\n    );\n    await queryRunner.query('DROP TABLE \"temporary_user\"');\n    await queryRunner.query('DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"');\n    await queryRunner.query('DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"');\n    await queryRunner.query('DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"');\n    await queryRunner.query('ALTER TABLE \"media\" RENAME TO \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaID\" varchar, \"jellyfinMediaID4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\" FROM \"temporary_media\"'\n    );\n    await queryRunner.query('DROP TABLE \"temporary_media\"');\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") '\n    );\n    await queryRunner.query(\n      'CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") '\n    );\n    await queryRunner.query('ALTER TABLE \"user\" RENAME TO \"temporary_user\"');\n    await queryRunner.query(\n      'CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime(\\'now\\')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"jellyfinUsername\" varchar, \"jellyfinId\" varchar, \"jellyfinAuthToken\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))'\n    );\n    await queryRunner.query(\n      'INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\" FROM \"temporary_user\"'\n    );\n    await queryRunner.query('DROP TABLE \"temporary_user\"');\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1613955393450-UpdateUserSettingsRegions.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class UpdateUserSettingsRegions1613955393450 implements MigrationInterface {\n  name = 'UpdateUserSettingsRegions1613955393450';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"enableNotifications\" boolean NOT NULL DEFAULT (1), \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"enableNotifications\", \"discordId\", \"userId\") SELECT \"id\", \"enableNotifications\", \"discordId\", \"userId\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"enableNotifications\" boolean NOT NULL DEFAULT (1), \"discordId\" varchar, \"userId\" integer, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"enableNotifications\", \"discordId\", \"userId\") SELECT \"id\", \"enableNotifications\", \"discordId\", \"userId\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1614334195680-AddTelegramSettingsToUserSettings.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddTelegramSettingsToUserSettings1614334195680 implements MigrationInterface {\n  name = 'AddTelegramSettingsToUserSettings1614334195680';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_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, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"enableNotifications\", \"discordId\", \"userId\", \"region\", \"originalLanguage\") SELECT \"id\", \"enableNotifications\", \"discordId\", \"userId\", \"region\", \"originalLanguage\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `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, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"enableNotifications\", \"discordId\", \"userId\", \"region\", \"originalLanguage\") SELECT \"id\", \"enableNotifications\", \"discordId\", \"userId\", \"region\", \"originalLanguage\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1615333940450-AddPGPToUserSettings.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddPGPToUserSettings1615333940450 implements MigrationInterface {\n  name = 'AddPGPToUserSettings1615333940450';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_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)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"enableNotifications\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\") SELECT \"id\", \"enableNotifications\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `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, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"enableNotifications\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\") SELECT \"id\", \"enableNotifications\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1616576677254-AddUserQuotaFields.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUserQuotaFields1616576677254 implements MigrationInterface {\n  name = 'AddUserQuotaFields1616576677254';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1617624225464-CreateTagsFieldonMediaRequest.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class CreateTagsFieldonMediaRequest1617624225464 implements MigrationInterface {\n  name = 'CreateTagsFieldonMediaRequest1617624225464';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `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)`\n    );\n    await queryRunner.query(\n      `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\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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)`\n    );\n    await queryRunner.query(\n      `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\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1617730837489-AddUserSettingsNotificationAgentsField.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUserSettingsNotificationAgentsField1617730837489 implements MigrationInterface {\n  name = 'AddUserSettingsNotificationAgentsField1617730837489';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `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)`\n    );\n    await queryRunner.query(\n      `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\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n    await queryRunner.query(\n      `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)`\n    );\n    await queryRunner.query(\n      `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\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `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)`\n    );\n    await queryRunner.query(\n      `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\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `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)`\n    );\n    await queryRunner.query(\n      `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\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1618912653565-CreateUserPushSubscriptions.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class CreateUserPushSubscriptions1618912653565 implements MigrationInterface {\n  name = 'CreateUserPushSubscriptions1618912653565';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"))`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1619239659754-AddUserSettingsLocale.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUserSettingsLocale1619239659754 implements MigrationInterface {\n  name = 'AddUserSettingsLocale1619239659754';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `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, \"locale\" varchar NOT NULL DEFAULT (''), CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `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\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"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)`\n    );\n    await queryRunner.query(\n      `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\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1619339817343-AddUserSettingsNotificationTypes.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUserSettingsNotificationTypes1619339817343 implements MigrationInterface {\n  name = 'AddUserSettingsNotificationTypes1619339817343';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" integer NOT NULL DEFAULT (2), \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\") SELECT \"id\", \"notificationAgents\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" integer NOT NULL DEFAULT (2), \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"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, \"locale\" varchar NOT NULL DEFAULT (''), CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"notificationAgents\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1634904083966-AddIssues.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddIssues1634904083966 implements MigrationInterface {\n  name = 'AddIssues1634904083966';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"issue\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"issueType\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"problemSeason\" integer NOT NULL DEFAULT (0), \"problemEpisode\" integer NOT NULL DEFAULT (0), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, \"createdById\" integer, \"modifiedById\" integer)`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"issue_comment\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"message\" text NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"issueId\" integer)`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_issue\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"issueType\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"problemSeason\" integer NOT NULL DEFAULT (0), \"problemEpisode\" integer NOT NULL DEFAULT (0), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, \"createdById\" integer, \"modifiedById\" integer, CONSTRAINT \"FK_276e20d053f3cff1645803c95d8\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_10b17b49d1ee77e7184216001e0\" FOREIGN KEY (\"createdById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_da88a1019c850d1a7b143ca02e5\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_issue\"(\"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\") SELECT \"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\" FROM \"issue\"`\n    );\n    await queryRunner.query(`DROP TABLE \"issue\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_issue\" RENAME TO \"issue\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_issue_comment\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"message\" text NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"issueId\" integer, CONSTRAINT \"FK_707b033c2d0653f75213614789d\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_180710fead1c94ca499c57a7d42\" FOREIGN KEY (\"issueId\") REFERENCES \"issue\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_issue_comment\"(\"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\") SELECT \"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\" FROM \"issue_comment\"`\n    );\n    await queryRunner.query(`DROP TABLE \"issue_comment\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_issue_comment\" RENAME TO \"issue_comment\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"issue_comment\" RENAME TO \"temporary_issue_comment\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"issue_comment\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"message\" text NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"issueId\" integer)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"issue_comment\"(\"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\") SELECT \"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\" FROM \"temporary_issue_comment\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_issue_comment\"`);\n    await queryRunner.query(`ALTER TABLE \"issue\" RENAME TO \"temporary_issue\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"issue\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"issueType\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"problemSeason\" integer NOT NULL DEFAULT (0), \"problemEpisode\" integer NOT NULL DEFAULT (0), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, \"createdById\" integer, \"modifiedById\" integer)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"issue\"(\"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\") SELECT \"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\" FROM \"temporary_issue\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_issue\"`);\n    await queryRunner.query(`DROP TABLE \"issue_comment\"`);\n    await queryRunner.query(`DROP TABLE \"issue\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1635079863457-AddPushbulletPushoverUserSettings.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddPushbulletPushoverUserSettings1635079863457 implements MigrationInterface {\n  name = 'AddPushbulletPushoverUserSettings1635079863457';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1660632269368-AddWatchlistSyncUserSetting.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddWatchlistSyncUserSetting1660632269368 implements MigrationInterface {\n  name = 'AddWatchlistSyncUserSetting1660632269368';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1660714479373-AddMediaRequestIsAutoRequestedField.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddMediaRequestIsAutoRequestedField1660714479373 implements MigrationInterface {\n  name = 'AddMediaRequestIsAutoRequestedField1660714479373';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `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, \"isAutoRequest\" boolean NOT NULL DEFAULT (0), CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE SET NULL ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\" FROM \"media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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, \"tags\" text, CONSTRAINT \"FK_a1aa713f41c99e9d10c48da75a0\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_6997bee94720f1ecb7f31137095\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_f4fc4efa14c3ba2b29c4525fa15\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE SET NULL ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\" FROM \"temporary_media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1672041273674-AddDiscoverSlider.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddDiscoverSlider1672041273674 implements MigrationInterface {\n  name = 'AddDiscoverSlider1672041273674';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"discover_slider\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"type\" integer NOT NULL, \"order\" integer NOT NULL, \"isBuiltIn\" boolean NOT NULL DEFAULT (0), \"enabled\" boolean NOT NULL DEFAULT (1), \"title\" varchar, \"data\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')))`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP TABLE \"discover_slider\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1682608634546-AddWatchlists.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddWatchlists1682608634546 implements MigrationInterface {\n  name = 'AddWatchlists1682608634546';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"))`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_939f205946256cc0d2a1ac51a8\"`);\n    await queryRunner.query(`DROP TABLE \"watchlist\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1697393491630-AddUserPushoverSound.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUserPushoverSound1697393491630 implements MigrationInterface {\n  name = 'AddUserPushoverSound1697393491630';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"pushoverSound\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"region\" varchar, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"region\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1699901142442-AddBlacklist.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddBlacklist1699901142442 implements MigrationInterface {\n  name = 'AddBlacklist1699901142442';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')),\"userId\" integer, \"mediaId\" integer,CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\", \"userId\"))`\n    );\n\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1727907530757-AddUserSettingsStreamingRegion.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUserSettingsStreamingRegion1727907530757 implements MigrationInterface {\n  name = 'AddUserSettingsStreamingRegion1727907530757';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"pushoverSound\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"pushoverSound\" varchar, \"discoverRegion\" varchar, \"streamingRegion\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"pushoverSound\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"notificationTypes\" text, \"discordId\" varchar, \"userId\" integer, \"originalLanguage\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"pgpKey\" varchar, \"locale\" varchar NOT NULL DEFAULT (''), \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"pushoverSound\" varchar, \"region\" varchar, CONSTRAINT \"UQ_986a2b6d3c05eb4091bb8066f78\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\") SELECT \"id\", \"notificationTypes\", \"discordId\", \"userId\", \"originalLanguage\", \"telegramChatId\", \"telegramSendSilently\", \"pgpKey\", \"locale\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"pushoverSound\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1734287582736-AddTelegramMessageThreadId.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddTelegramMessageThreadId1734287582736 implements MigrationInterface {\n  name = 'AddTelegramMessageThreadId1734287582736';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"locale\" varchar NOT NULL DEFAULT (''), \"discoverRegion\" varchar, \"streamingRegion\" varchar, \"originalLanguage\" varchar, \"pgpKey\" varchar, \"discordId\" varchar, \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"pushoverSound\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"notificationTypes\" text, \"userId\" integer, \"telegramMessageThreadId\" varchar, CONSTRAINT \"REL_986a2b6d3c05eb4091bb8066f7\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_settings\"(\"id\", \"locale\", \"discoverRegion\", \"streamingRegion\", \"originalLanguage\", \"pgpKey\", \"discordId\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"pushoverSound\", \"telegramChatId\", \"telegramSendSilently\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"notificationTypes\", \"userId\") SELECT \"id\", \"locale\", \"discoverRegion\", \"streamingRegion\", \"originalLanguage\", \"pgpKey\", \"discordId\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"pushoverSound\", \"telegramChatId\", \"telegramSendSilently\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"notificationTypes\", \"userId\" FROM \"user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_settings\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_settings\" RENAME TO \"user_settings\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_settings\" RENAME TO \"temporary_user_settings\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_settings\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"locale\" varchar NOT NULL DEFAULT (''), \"discoverRegion\" varchar, \"streamingRegion\" varchar, \"originalLanguage\" varchar, \"pgpKey\" varchar, \"discordId\" varchar, \"pushbulletAccessToken\" varchar, \"pushoverApplicationToken\" varchar, \"pushoverUserKey\" varchar, \"pushoverSound\" varchar, \"telegramChatId\" varchar, \"telegramSendSilently\" boolean, \"watchlistSyncMovies\" boolean, \"watchlistSyncTv\" boolean, \"notificationTypes\" text, \"userId\" integer, CONSTRAINT \"REL_986a2b6d3c05eb4091bb8066f7\" UNIQUE (\"userId\"), CONSTRAINT \"FK_986a2b6d3c05eb4091bb8066f78\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_settings\"(\"id\", \"locale\", \"discoverRegion\", \"streamingRegion\", \"originalLanguage\", \"pgpKey\", \"discordId\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"pushoverSound\", \"telegramChatId\", \"telegramSendSilently\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"notificationTypes\", \"userId\") SELECT \"id\", \"locale\", \"discoverRegion\", \"streamingRegion\", \"originalLanguage\", \"pgpKey\", \"discordId\", \"pushbulletAccessToken\", \"pushoverApplicationToken\", \"pushoverUserKey\", \"pushoverSound\", \"telegramChatId\", \"telegramSendSilently\", \"watchlistSyncMovies\", \"watchlistSyncTv\", \"notificationTypes\", \"userId\" FROM \"temporary_user_settings\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_settings\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1734805733535-AddOverrideRules.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddOverrideRules1734805733535 implements MigrationInterface {\n  name = 'AddOverrideRules1734805733535';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"override_rule\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"radarrServiceId\" integer, \"sonarrServiceId\" integer, \"users\" varchar, \"genre\" varchar, \"language\" varchar, \"keywords\" varchar, \"profileId\" integer, \"rootFolder\" varchar, \"tags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')))`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP TABLE \"override_rule\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1737320080282-AddBlacklistTagsColumn.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddBlacklistTagsColumn1737320080282 implements MigrationInterface {\n  name = 'AddBlacklistTagsColumn1737320080282';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blacklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blacklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blacklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blacklist\" RENAME TO \"blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" RENAME TO \"temporary_blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blacklist\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1743023610704-UpdateWebPush.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class UpdateWebPush1743023610704 implements MigrationInterface {\n  name = 'UpdateWebPush1743023610704';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blacklist\" RENAME TO \"blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_5f933c8ed6ad2c31739e6b94886\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_e49b27917899e01d7aca6b0b15c\" UNIQUE (\"mediaId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blacklist\" RENAME TO \"blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime DEFAULT (CURRENT_TIMESTAMP), \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaId\" varchar, \"jellyfinMediaId4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_939f205946256cc0d2a1ac51a8\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"), CONSTRAINT \"FK_ae34e6b153a90672eb9dc4857d7\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_watchlist\"(\"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\") SELECT \"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\" FROM \"watchlist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"watchlist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_watchlist\" RENAME TO \"watchlist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_5f933c8ed6ad2c31739e6b94886\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_e49b27917899e01d7aca6b0b15c\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blacklist\" RENAME TO \"blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" RENAME TO \"temporary_blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_5f933c8ed6ad2c31739e6b94886\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_e49b27917899e01d7aca6b0b15c\" UNIQUE (\"mediaId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blacklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_939f205946256cc0d2a1ac51a8\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" RENAME TO \"temporary_watchlist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"watchlist\"(\"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\") SELECT \"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\" FROM \"temporary_watchlist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_watchlist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\"`);\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime, \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaId\" varchar, \"jellyfinMediaId4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" RENAME TO \"temporary_blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blacklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" RENAME TO \"temporary_blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\", \"userId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blacklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1743107645301-AddUserAvatarCacheFields.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUserAvatarCacheFields1743107645301 implements MigrationInterface {\n  name = 'AddUserAvatarCacheFields1743107645301';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, \"avatarETag\" varchar, \"avatarVersion\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1745492372230-UpdateWebPush.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class UpdateWebPush1745492372230 implements MigrationInterface {\n  name = 'UpdateWebPush1745492372230';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, \"blacklistedTags\" varchar, CONSTRAINT \"UQ_e49b27917899e01d7aca6b0b15c\" UNIQUE (\"mediaId\"), CONSTRAINT \"UQ_5f933c8ed6ad2c31739e6b94886\" UNIQUE (\"tmdbId\"), CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blacklist\" RENAME TO \"blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" RENAME TO \"temporary_blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_e49b27917899e01d7aca6b0b15c\" UNIQUE (\"mediaId\"), CONSTRAINT \"UQ_5f933c8ed6ad2c31739e6b94886\" UNIQUE (\"tmdbId\"), CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blacklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1765233385034-AddUniqueConstraintToPushSubscription.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddUniqueConstraintToPushSubscription1765233385034 implements MigrationInterface {\n  name = 'AddUniqueConstraintToPushSubscription1765233385034';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`\n      DELETE FROM \"user_push_subscription\"\n      WHERE id NOT IN (\n        SELECT MAX(id)\n        FROM \"user_push_subscription\"\n        GROUP BY \"endpoint\", \"userId\"\n      )\n    `);\n\n    await queryRunner.query(\n      `CREATE UNIQUE INDEX \"UQ_6427d07d9a171a3a1ab87480005\" ON \"user_push_subscription\" (\"endpoint\", \"userId\")`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"UQ_6427d07d9a171a3a1ab87480005\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1770627968781-AddPerformanceIndexes.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddPerformanceIndexes1770627968781 implements MigrationInterface {\n  name = 'AddPerformanceIndexes1770627968781';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"UQ_6427d07d9a171a3a1ab87480005\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_939f205946256cc0d2a1ac51a8\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"), CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_ae34e6b153a90672eb9dc4857d7\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_watchlist\"(\"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\") SELECT \"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\" FROM \"watchlist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"watchlist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_watchlist\" RENAME TO \"watchlist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_issue_comment\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"message\" text NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"issueId\" integer, CONSTRAINT \"FK_180710fead1c94ca499c57a7d42\" FOREIGN KEY (\"issueId\") REFERENCES \"issue\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_707b033c2d0653f75213614789d\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_issue_comment\"(\"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\") SELECT \"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\" FROM \"issue_comment\"`\n    );\n    await queryRunner.query(`DROP TABLE \"issue_comment\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_issue_comment\" RENAME TO \"issue_comment\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_issue\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"issueType\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"problemSeason\" integer NOT NULL DEFAULT (0), \"problemEpisode\" integer NOT NULL DEFAULT (0), \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaId\" integer, \"createdById\" integer, \"modifiedById\" integer, CONSTRAINT \"FK_da88a1019c850d1a7b143ca02e5\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_10b17b49d1ee77e7184216001e0\" FOREIGN KEY (\"createdById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_276e20d053f3cff1645803c95d8\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_issue\"(\"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\") SELECT \"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\" FROM \"issue\"`\n    );\n    await queryRunner.query(`DROP TABLE \"issue\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_issue\" RENAME TO \"issue\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_override_rule\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"radarrServiceId\" integer, \"sonarrServiceId\" integer, \"users\" varchar, \"genre\" varchar, \"language\" varchar, \"keywords\" varchar, \"profileId\" integer, \"rootFolder\" varchar, \"tags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_override_rule\"(\"id\", \"radarrServiceId\", \"sonarrServiceId\", \"users\", \"genre\", \"language\", \"keywords\", \"profileId\", \"rootFolder\", \"tags\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"radarrServiceId\", \"sonarrServiceId\", \"users\", \"genre\", \"language\", \"keywords\", \"profileId\", \"rootFolder\", \"tags\", \"createdAt\", \"updatedAt\" FROM \"override_rule\"`\n    );\n    await queryRunner.query(`DROP TABLE \"override_rule\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_override_rule\" RENAME TO \"override_rule\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"requestId\" integer, CONSTRAINT \"FK_6f14737e346d6b27d8e50d2157a\" FOREIGN KEY (\"requestId\") REFERENCES \"media_request\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"season_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_season_request\" RENAME TO \"season_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"status\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"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, \"isAutoRequest\" boolean NOT NULL DEFAULT (0), 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)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\", \"isAutoRequest\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\", \"isAutoRequest\" FROM \"media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_media_request\" RENAME TO \"media_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, \"avatarETag\" varchar, \"avatarVersion\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"avatarETag\", \"avatarVersion\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"avatarETag\", \"avatarVersion\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_6bbafa28411e6046421991ea21\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, \"blacklistedTags\" varchar, CONSTRAINT \"UQ_5f933c8ed6ad2c31739e6b94886\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_e49b27917899e01d7aca6b0b15c\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\", \"blacklistedTags\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\", \"blacklistedTags\" FROM \"blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blacklist\" RENAME TO \"blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_season\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaId\" integer, \"status4k\" integer NOT NULL DEFAULT (1), CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_season\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\", \"status4k\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\", \"status4k\" FROM \"season\"`\n    );\n    await queryRunner.query(`DROP TABLE \"season\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_season\" RENAME TO \"season\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_41a289eb1fa489c1bc6f38d9c3\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_7ff2d11f6a83cb52386eaebe74\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime DEFAULT (CURRENT_TIMESTAMP), \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaId\" varchar, \"jellyfinMediaId4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\" FROM \"media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"media\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_media\" RENAME TO \"media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_discover_slider\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"type\" integer NOT NULL, \"order\" integer NOT NULL, \"isBuiltIn\" boolean NOT NULL DEFAULT (0), \"enabled\" boolean NOT NULL DEFAULT (1), \"title\" varchar, \"data\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_discover_slider\"(\"id\", \"type\", \"order\", \"isBuiltIn\", \"enabled\", \"title\", \"data\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"type\", \"order\", \"isBuiltIn\", \"enabled\", \"title\", \"data\", \"createdAt\", \"updatedAt\" FROM \"discover_slider\"`\n    );\n    await queryRunner.query(`DROP TABLE \"discover_slider\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_discover_slider\" RENAME TO \"discover_slider\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_4c696e8ed36ae34fe18abe59d2\" ON \"media_request\" (\"status\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_c730c2d67f271a372c39a07b7e\" ON \"media\" (\"status\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_5d6218de4f547909391a5c1347\" ON \"media\" (\"status4k\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_f8233358694d1677a67899b90a\" ON \"media\" (\"tmdbId\", \"mediaType\") `\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_f8233358694d1677a67899b90a\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_5d6218de4f547909391a5c1347\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_c730c2d67f271a372c39a07b7e\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_4c696e8ed36ae34fe18abe59d2\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"discover_slider\" RENAME TO \"temporary_discover_slider\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"discover_slider\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"type\" integer NOT NULL, \"order\" integer NOT NULL, \"isBuiltIn\" boolean NOT NULL DEFAULT (0), \"enabled\" boolean NOT NULL DEFAULT (1), \"title\" varchar, \"data\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"discover_slider\"(\"id\", \"type\", \"order\", \"isBuiltIn\", \"enabled\", \"title\", \"data\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"type\", \"order\", \"isBuiltIn\", \"enabled\", \"title\", \"data\", \"createdAt\", \"updatedAt\" FROM \"temporary_discover_slider\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_discover_slider\"`);\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_7ff2d11f6a83cb52386eaebe74\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_41a289eb1fa489c1bc6f38d9c3\"`\n    );\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_7157aad07c73f6a6ae3bbd5ef5\"`\n    );\n    await queryRunner.query(`ALTER TABLE \"media\" RENAME TO \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"media\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"tvdbId\" integer, \"imdbId\" varchar, \"status\" integer NOT NULL DEFAULT (1), \"status4k\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"lastSeasonChange\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"mediaAddedAt\" datetime DEFAULT (CURRENT_TIMESTAMP), \"serviceId\" integer, \"serviceId4k\" integer, \"externalServiceId\" integer, \"externalServiceId4k\" integer, \"externalServiceSlug\" varchar, \"externalServiceSlug4k\" varchar, \"ratingKey\" varchar, \"ratingKey4k\" varchar, \"jellyfinMediaId\" varchar, \"jellyfinMediaId4k\" varchar, CONSTRAINT \"UQ_41a289eb1fa489c1bc6f38d9c3c\" UNIQUE (\"tvdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media\"(\"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\") SELECT \"id\", \"mediaType\", \"tmdbId\", \"tvdbId\", \"imdbId\", \"status\", \"status4k\", \"createdAt\", \"updatedAt\", \"lastSeasonChange\", \"mediaAddedAt\", \"serviceId\", \"serviceId4k\", \"externalServiceId\", \"externalServiceId4k\", \"externalServiceSlug\", \"externalServiceSlug4k\", \"ratingKey\", \"ratingKey4k\", \"jellyfinMediaId\", \"jellyfinMediaId4k\" FROM \"temporary_media\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7ff2d11f6a83cb52386eaebe74\" ON \"media\" (\"imdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_41a289eb1fa489c1bc6f38d9c3\" ON \"media\" (\"tvdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_7157aad07c73f6a6ae3bbd5ef5\" ON \"media\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"season\" RENAME TO \"temporary_season\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, \"status4k\" integer NOT NULL DEFAULT (1), CONSTRAINT \"FK_087099b39600be695591da9a49c\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"season\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\", \"status4k\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"mediaId\", \"status4k\" FROM \"temporary_season\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_season\"`);\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_6bbafa28411e6046421991ea21\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"blacklist\" RENAME TO \"temporary_blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blacklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, \"blacklistedTags\" varchar, CONSTRAINT \"UQ_5f933c8ed6ad2c31739e6b94886\" UNIQUE (\"tmdbId\"), CONSTRAINT \"UQ_e49b27917899e01d7aca6b0b15c\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blacklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\", \"blacklistedTags\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"userId\", \"mediaId\", \"blacklistedTags\" FROM \"temporary_blacklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blacklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, \"avatarETag\" varchar, \"avatarVersion\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"avatarETag\", \"avatarVersion\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"avatarETag\", \"avatarVersion\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"media_request\" RENAME TO \"temporary_media_request\"`\n    );\n    await queryRunner.query(\n      `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, \"tags\" text, \"isAutoRequest\" boolean NOT NULL DEFAULT (0), 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)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"media_request\"(\"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\", \"isAutoRequest\") SELECT \"id\", \"status\", \"createdAt\", \"updatedAt\", \"type\", \"mediaId\", \"requestedById\", \"modifiedById\", \"is4k\", \"serverId\", \"profileId\", \"rootFolder\", \"languageProfileId\", \"tags\", \"isAutoRequest\" FROM \"temporary_media_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_media_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"season_request\" RENAME TO \"temporary_season_request\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"season_request\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"seasonNumber\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestId\" integer, CONSTRAINT \"FK_6f14737e346d6b27d8e50d2157a\" FOREIGN KEY (\"requestId\") REFERENCES \"media_request\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"season_request\"(\"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\") SELECT \"id\", \"seasonNumber\", \"status\", \"createdAt\", \"updatedAt\", \"requestId\" FROM \"temporary_season_request\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_season_request\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"override_rule\" RENAME TO \"temporary_override_rule\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"override_rule\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"radarrServiceId\" integer, \"sonarrServiceId\" integer, \"users\" varchar, \"genre\" varchar, \"language\" varchar, \"keywords\" varchar, \"profileId\" integer, \"rootFolder\" varchar, \"tags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"override_rule\"(\"id\", \"radarrServiceId\", \"sonarrServiceId\", \"users\", \"genre\", \"language\", \"keywords\", \"profileId\", \"rootFolder\", \"tags\", \"createdAt\", \"updatedAt\") SELECT \"id\", \"radarrServiceId\", \"sonarrServiceId\", \"users\", \"genre\", \"language\", \"keywords\", \"profileId\", \"rootFolder\", \"tags\", \"createdAt\", \"updatedAt\" FROM \"temporary_override_rule\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_override_rule\"`);\n    await queryRunner.query(`ALTER TABLE \"issue\" RENAME TO \"temporary_issue\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"issue\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"issueType\" integer NOT NULL, \"status\" integer NOT NULL DEFAULT (1), \"problemSeason\" integer NOT NULL DEFAULT (0), \"problemEpisode\" integer NOT NULL DEFAULT (0), \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"mediaId\" integer, \"createdById\" integer, \"modifiedById\" integer, CONSTRAINT \"FK_da88a1019c850d1a7b143ca02e5\" FOREIGN KEY (\"modifiedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_10b17b49d1ee77e7184216001e0\" FOREIGN KEY (\"createdById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_276e20d053f3cff1645803c95d8\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"issue\"(\"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\") SELECT \"id\", \"issueType\", \"status\", \"problemSeason\", \"problemEpisode\", \"createdAt\", \"updatedAt\", \"mediaId\", \"createdById\", \"modifiedById\" FROM \"temporary_issue\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_issue\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"issue_comment\" RENAME TO \"temporary_issue_comment\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"issue_comment\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"message\" text NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"issueId\" integer, CONSTRAINT \"FK_180710fead1c94ca499c57a7d42\" FOREIGN KEY (\"issueId\") REFERENCES \"issue\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_707b033c2d0653f75213614789d\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"issue_comment\"(\"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\") SELECT \"id\", \"message\", \"createdAt\", \"updatedAt\", \"userId\", \"issueId\" FROM \"temporary_issue_comment\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_issue_comment\"`);\n    await queryRunner.query(\n      `DROP INDEX IF EXISTS \"IDX_939f205946256cc0d2a1ac51a8\"`\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"watchlist\" RENAME TO \"temporary_watchlist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"updatedAt\" datetime NOT NULL DEFAULT (datetime('now')), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"), CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_ae34e6b153a90672eb9dc4857d7\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"watchlist\"(\"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\") SELECT \"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\" FROM \"temporary_watchlist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_watchlist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (datetime('now')), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(\n      `CREATE UNIQUE INDEX \"UQ_6427d07d9a171a3a1ab87480005\" ON \"user_push_subscription\" (\"endpoint\", \"userId\") `\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1771080196816-RenameBlacklistToBlocklist.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class RenameBlacklistToBlocklist1771080196816 implements MigrationInterface {\n  name = 'RenameBlacklistToBlocklist1771080196816';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`\n      CREATE TABLE \"temporary_blocklist\" (\n        \"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL,\n        \"mediaType\" varchar NOT NULL,\n        \"title\" varchar,\n        \"tmdbId\" integer NOT NULL,\n        \"blocklistedTags\" varchar,\n        \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')),\n        \"userId\" integer,\n        \"mediaId\" integer,\n        CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"),\n        CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"),\n        CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION,\n        CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION\n      )\n    `);\n    await queryRunner.query(`\n      INSERT INTO \"temporary_blocklist\" (\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\")\n      SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blacklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blacklist\"\n    `);\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blocklist\" RENAME TO \"blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blocklist\" (\"tmdbId\")`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`ALTER TABLE \"blocklist\" RENAME TO \"blacklist\"`);\n    await queryRunner.query(`\n      CREATE TABLE \"temporary_blacklist\" (\n        \"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL,\n        \"mediaType\" varchar NOT NULL,\n        \"title\" varchar,\n        \"tmdbId\" integer NOT NULL,\n        \"blacklistedTags\" varchar,\n        \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')),\n        \"userId\" integer,\n        \"mediaId\" integer,\n        CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"),\n        CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"),\n        CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION,\n        CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION\n      )\n    `);\n    await queryRunner.query(`\n      INSERT INTO \"temporary_blacklist\" (\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blacklistedTags\", \"createdAt\", \"userId\", \"mediaId\")\n      SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blacklist\"\n    `);\n    await queryRunner.query(`DROP TABLE \"blacklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blacklist\" RENAME TO \"blacklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blacklist\" (\"tmdbId\")`\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1771259394105-AddForeignKeyIndexes.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddForeignKeyIndexes1771259394105 implements MigrationInterface {\n  name = 'AddForeignKeyIndexes1771259394105';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blocklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blocklist\" RENAME TO \"blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\"), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\"), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blocklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blocklist\" RENAME TO \"blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_ae34e6b153a90672eb9dc4857d\" ON \"watchlist\" (\"requestedById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6641da8d831b93dfcb429f8b8b\" ON \"watchlist\" (\"mediaId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_707b033c2d0653f75213614789\" ON \"issue_comment\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_180710fead1c94ca499c57a7d4\" ON \"issue_comment\" (\"issueId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_53d04c07c3f4f54eae372ed665\" ON \"issue\" (\"issueType\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_276e20d053f3cff1645803c95d\" ON \"issue\" (\"mediaId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_10b17b49d1ee77e7184216001e\" ON \"issue\" (\"createdById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_da88a1019c850d1a7b143ca02e\" ON \"issue\" (\"modifiedById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6f14737e346d6b27d8e50d2157\" ON \"season_request\" (\"requestId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_a1aa713f41c99e9d10c48da75a\" ON \"media_request\" (\"mediaId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6997bee94720f1ecb7f3113709\" ON \"media_request\" (\"requestedById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_f4fc4efa14c3ba2b29c4525fa1\" ON \"media_request\" (\"modifiedById\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_03f7958328e311761b0de675fb\" ON \"user_push_subscription\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_087099b39600be695591da9a49\" ON \"season\" (\"mediaId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_09b94c932e84635c5461f3c0a9\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_356721a49f145aa439c16e6b99\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"FK_356721a49f145aa439c16e6b999\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT \"FK_5c8af2d0e83b3be6d250eccc19d\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blocklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blocklist\" RENAME TO \"blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_356721a49f145aa439c16e6b99\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_09b94c932e84635c5461f3c0a9\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" RENAME TO \"temporary_blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blocklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_087099b39600be695591da9a49\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_356721a49f145aa439c16e6b99\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_09b94c932e84635c5461f3c0a9\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_03f7958328e311761b0de675fb\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_f4fc4efa14c3ba2b29c4525fa1\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_6997bee94720f1ecb7f3113709\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_a1aa713f41c99e9d10c48da75a\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_6f14737e346d6b27d8e50d2157\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_da88a1019c850d1a7b143ca02e\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_10b17b49d1ee77e7184216001e\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_276e20d053f3cff1645803c95d\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_53d04c07c3f4f54eae372ed665\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_180710fead1c94ca499c57a7d4\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_707b033c2d0653f75213614789\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_6641da8d831b93dfcb429f8b8b\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_ae34e6b153a90672eb9dc4857d\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" RENAME TO \"temporary_blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blocklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\"), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\"), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_6bbafa28411e6046421991ea21\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" RENAME TO \"temporary_blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (datetime('now')), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"FK_62b7ade94540f9f8d8bede54b99\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_53c1ab62c3e5875bc3ac474823e\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blocklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6bbafa28411e6046421991ea21\" ON \"blocklist\" (\"tmdbId\") `\n    );\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1771337037917-RecoveryLinkExpirationDateTime.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class RecoveryLinkExpirationDateTime1771337037917 implements MigrationInterface {\n  name = 'RecoveryLinkExpirationDateTime1771337037917';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" datetime, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, \"avatarETag\" varchar, \"avatarVersion\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"avatarETag\", \"avatarVersion\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"avatarETag\", \"avatarVersion\" FROM \"user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user\"`);\n    await queryRunner.query(`ALTER TABLE \"temporary_user\" RENAME TO \"user\"`);\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`ALTER TABLE \"user\" RENAME TO \"temporary_user\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"user\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"email\" varchar NOT NULL, \"username\" varchar, \"plexId\" integer, \"plexToken\" varchar, \"permissions\" integer NOT NULL DEFAULT (0), \"avatar\" varchar NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"password\" varchar, \"userType\" integer NOT NULL DEFAULT (1), \"plexUsername\" varchar, \"resetPasswordGuid\" varchar, \"recoveryLinkExpirationDate\" date, \"movieQuotaLimit\" integer, \"movieQuotaDays\" integer, \"tvQuotaLimit\" integer, \"tvQuotaDays\" integer, \"jellyfinUsername\" varchar, \"jellyfinAuthToken\" varchar, \"jellyfinUserId\" varchar, \"jellyfinDeviceId\" varchar, \"avatarETag\" varchar, \"avatarVersion\" varchar, CONSTRAINT \"UQ_e12875dfb3b1d92d7d7c5377e22\" UNIQUE (\"email\"))`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user\"(\"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"avatarETag\", \"avatarVersion\") SELECT \"id\", \"email\", \"username\", \"plexId\", \"plexToken\", \"permissions\", \"avatar\", \"createdAt\", \"updatedAt\", \"password\", \"userType\", \"plexUsername\", \"resetPasswordGuid\", \"recoveryLinkExpirationDate\", \"movieQuotaLimit\", \"movieQuotaDays\", \"tvQuotaLimit\", \"tvQuotaDays\", \"jellyfinUsername\", \"jellyfinAuthToken\", \"jellyfinUserId\", \"jellyfinDeviceId\", \"avatarETag\", \"avatarVersion\" FROM \"temporary_user\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user\"`);\n  }\n}\n"
  },
  {
    "path": "server/migration/sqlite/1772047972752-AddMediaTypeToUniqueConstraints.ts",
    "content": "import type { MigrationInterface, QueryRunner } from 'typeorm';\n\nexport class AddMediaTypeToUniqueConstraints1772047972752 implements MigrationInterface {\n  name = 'AddMediaTypeToUniqueConstraints1772047972752';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP INDEX \"IDX_03f7958328e311761b0de675fb\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_03f7958328e311761b0de675fb\" ON \"user_push_subscription\" (\"userId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_356721a49f145aa439c16e6b99\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_09b94c932e84635c5461f3c0a9\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_5c8af2d0e83b3be6d250eccc19d\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_356721a49f145aa439c16e6b999\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blocklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blocklist\" RENAME TO \"blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_03f7958328e311761b0de675fb\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"user_push_subscription\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_user_push_subscription\" RENAME TO \"user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_03f7958328e311761b0de675fb\" ON \"user_push_subscription\" (\"userId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_356721a49f145aa439c16e6b99\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_09b94c932e84635c5461f3c0a9\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_5c8af2d0e83b3be6d250eccc19d\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_356721a49f145aa439c16e6b999\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blocklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blocklist\" RENAME TO \"blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_356721a49f145aa439c16e6b99\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_09b94c932e84635c5461f3c0a9\"`);\n\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"UQ_81504e02db89b4c1e3152729fa6\" UNIQUE (\"tmdbId\", \"mediaType\"), CONSTRAINT \"FK_5c8af2d0e83b3be6d250eccc19d\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_356721a49f145aa439c16e6b999\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"blocklist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_blocklist\" RENAME TO \"blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n\n    // Manually added as TypeORM migration:generate does not detect changes to named unique constraints.\n    await queryRunner.query(`DROP INDEX \"IDX_939f205946256cc0d2a1ac51a8\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_ae34e6b153a90672eb9dc4857d\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_6641da8d831b93dfcb429f8b8b\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"mediaType\", \"requestedById\"), CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_ae34e6b153a90672eb9dc4857d7\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_watchlist\"(\"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\") SELECT \"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\" FROM \"watchlist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"watchlist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_watchlist\" RENAME TO \"watchlist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\")`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_ae34e6b153a90672eb9dc4857d\" ON \"watchlist\" (\"requestedById\")`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6641da8d831b93dfcb429f8b8b\" ON \"watchlist\" (\"mediaId\")`\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    // Manually added as TypeORM migration:generate does not detect changes to named unique constraints.\n    await queryRunner.query(`DROP INDEX \"IDX_939f205946256cc0d2a1ac51a8\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_ae34e6b153a90672eb9dc4857d\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_6641da8d831b93dfcb429f8b8b\"`);\n    await queryRunner.query(\n      `CREATE TABLE \"temporary_watchlist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"ratingKey\" varchar NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar NOT NULL, \"tmdbId\" integer NOT NULL, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updatedAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"requestedById\" integer, \"mediaId\" integer, CONSTRAINT \"UNIQUE_USER_DB\" UNIQUE (\"tmdbId\", \"requestedById\"), CONSTRAINT \"FK_6641da8d831b93dfcb429f8b8bc\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_ae34e6b153a90672eb9dc4857d7\" FOREIGN KEY (\"requestedById\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"temporary_watchlist\"(\"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\") SELECT \"id\", \"ratingKey\", \"mediaType\", \"title\", \"tmdbId\", \"createdAt\", \"updatedAt\", \"requestedById\", \"mediaId\" FROM \"watchlist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"watchlist\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"temporary_watchlist\" RENAME TO \"watchlist\"`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_939f205946256cc0d2a1ac51a8\" ON \"watchlist\" (\"tmdbId\")`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_ae34e6b153a90672eb9dc4857d\" ON \"watchlist\" (\"requestedById\")`\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_6641da8d831b93dfcb429f8b8b\" ON \"watchlist\" (\"mediaId\")`\n    );\n\n    // Blocklist: revert to original\n    await queryRunner.query(`DROP INDEX \"IDX_09b94c932e84635c5461f3c0a9\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_356721a49f145aa439c16e6b99\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" RENAME TO \"temporary_blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_5c8af2d0e83b3be6d250eccc19d\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_356721a49f145aa439c16e6b999\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blocklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_09b94c932e84635c5461f3c0a9\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_356721a49f145aa439c16e6b99\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" RENAME TO \"temporary_blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_5c8af2d0e83b3be6d250eccc19d\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_356721a49f145aa439c16e6b999\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blocklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_03f7958328e311761b0de675fb\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_03f7958328e311761b0de675fb\" ON \"user_push_subscription\" (\"userId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_09b94c932e84635c5461f3c0a9\"`);\n    await queryRunner.query(`DROP INDEX \"IDX_356721a49f145aa439c16e6b99\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"blocklist\" RENAME TO \"temporary_blocklist\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"blocklist\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"mediaType\" varchar NOT NULL, \"title\" varchar, \"tmdbId\" integer NOT NULL, \"blocklistedTags\" varchar, \"createdAt\" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"userId\" integer, \"mediaId\" integer, CONSTRAINT \"UQ_6bbafa28411e6046421991ea21c\" UNIQUE (\"tmdbId\"), CONSTRAINT \"REL_62b7ade94540f9f8d8bede54b9\" UNIQUE (\"mediaId\"), CONSTRAINT \"FK_5c8af2d0e83b3be6d250eccc19d\" FOREIGN KEY (\"mediaId\") REFERENCES \"media\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT \"FK_356721a49f145aa439c16e6b999\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"blocklist\"(\"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\") SELECT \"id\", \"mediaType\", \"title\", \"tmdbId\", \"blocklistedTags\", \"createdAt\", \"userId\", \"mediaId\" FROM \"temporary_blocklist\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_blocklist\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_09b94c932e84635c5461f3c0a9\" ON \"blocklist\" (\"tmdbId\") `\n    );\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_356721a49f145aa439c16e6b99\" ON \"blocklist\" (\"userId\") `\n    );\n    await queryRunner.query(`DROP INDEX \"IDX_03f7958328e311761b0de675fb\"`);\n    await queryRunner.query(\n      `ALTER TABLE \"user_push_subscription\" RENAME TO \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(\n      `CREATE TABLE \"user_push_subscription\" (\"id\" integer PRIMARY KEY AUTOINCREMENT NOT NULL, \"endpoint\" varchar NOT NULL, \"p256dh\" varchar NOT NULL, \"auth\" varchar NOT NULL, \"userId\" integer, \"userAgent\" varchar, \"createdAt\" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT \"UQ_f90ab5a4ed54905a4bb51a7148b\" UNIQUE (\"auth\"), CONSTRAINT \"UQ_6427d07d9a171a3a1ab87480005\" UNIQUE (\"endpoint\", \"userId\"), CONSTRAINT \"FK_03f7958328e311761b0de675fbe\" FOREIGN KEY (\"userId\") REFERENCES \"user\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION)`\n    );\n    await queryRunner.query(\n      `INSERT INTO \"user_push_subscription\"(\"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\") SELECT \"id\", \"endpoint\", \"p256dh\", \"auth\", \"userId\", \"userAgent\", \"createdAt\" FROM \"temporary_user_push_subscription\"`\n    );\n    await queryRunner.query(`DROP TABLE \"temporary_user_push_subscription\"`);\n    await queryRunner.query(\n      `CREATE INDEX \"IDX_03f7958328e311761b0de675fb\" ON \"user_push_subscription\" (\"userId\") `\n    );\n  }\n}\n"
  },
  {
    "path": "server/models/Collection.ts",
    "content": "import type { TmdbCollection } from '@server/api/themoviedb/interfaces';\nimport { MediaType } from '@server/constants/media';\nimport type Media from '@server/entity/Media';\nimport { sortBy } from 'lodash';\nimport type { MovieResult } from './Search';\nimport { mapMovieResult } from './Search';\n\nexport interface Collection {\n  id: number;\n  name: string;\n  overview?: string;\n  posterPath?: string;\n  backdropPath?: string;\n  parts: MovieResult[];\n}\n\nexport const mapCollection = (\n  collection: TmdbCollection,\n  media: Media[]\n): Collection => ({\n  id: collection.id,\n  name: collection.name,\n  overview: collection.overview,\n  posterPath: collection.poster_path,\n  backdropPath: collection.backdrop_path,\n  parts: sortBy(collection.parts, 'release_date').map((part) =>\n    mapMovieResult(\n      part,\n      media?.find(\n        (req) => req.tmdbId === part.id && req.mediaType === MediaType.MOVIE\n      )\n    )\n  ),\n});\n"
  },
  {
    "path": "server/models/Movie.ts",
    "content": "import type {\n  TmdbMovieDetails,\n  TmdbMovieReleaseResult,\n  TmdbProductionCompany,\n} from '@server/api/themoviedb/interfaces';\nimport type Media from '@server/entity/Media';\nimport type {\n  Cast,\n  Crew,\n  ExternalIds,\n  Genre,\n  Keyword,\n  ProductionCompany,\n  WatchProviders,\n} from './common';\nimport {\n  mapCast,\n  mapCrew,\n  mapExternalIds,\n  mapVideos,\n  mapWatchProviders,\n} from './common';\n\nexport interface Video {\n  url?: string;\n  site: 'YouTube';\n  key: string;\n  name: string;\n  size: number;\n  type:\n    | 'Clip'\n    | 'Teaser'\n    | 'Trailer'\n    | 'Featurette'\n    | 'Opening Credits'\n    | 'Behind the Scenes'\n    | 'Bloopers';\n}\n\nexport interface MovieDetails {\n  id: number;\n  imdbId?: string;\n  adult: boolean;\n  backdropPath?: string;\n  budget: number;\n  genres: Genre[];\n  homepage?: string;\n  originalLanguage: string;\n  originalTitle: string;\n  overview?: string;\n  popularity: number;\n  relatedVideos?: Video[];\n  posterPath?: string;\n  productionCompanies: ProductionCompany[];\n  productionCountries: {\n    iso_3166_1: string;\n    name: string;\n  }[];\n  releaseDate: string;\n  releases: TmdbMovieReleaseResult;\n  revenue: number;\n  runtime?: number;\n  spokenLanguages: {\n    iso_639_1: string;\n    name: string;\n  }[];\n  status: string;\n  tagline?: string;\n  title: string;\n  video: boolean;\n  voteAverage: number;\n  voteCount: number;\n  credits: {\n    cast: Cast[];\n    crew: Crew[];\n  };\n  collection?: {\n    id: number;\n    name: string;\n    posterPath?: string;\n    backdropPath?: string;\n  };\n  mediaInfo?: Media;\n  externalIds: ExternalIds;\n  mediaUrl?: string;\n  watchProviders?: WatchProviders[];\n  keywords: Keyword[];\n  onUserWatchlist?: boolean;\n}\n\nexport const mapProductionCompany = (\n  company: TmdbProductionCompany\n): ProductionCompany => ({\n  id: company.id,\n  name: company.name,\n  originCountry: company.origin_country,\n  description: company.description,\n  headquarters: company.headquarters,\n  homepage: company.homepage,\n  logoPath: company.logo_path,\n});\n\nexport const mapMovieDetails = (\n  movie: TmdbMovieDetails,\n  media?: Media,\n  userWatchlist?: boolean\n): MovieDetails => ({\n  id: movie.id,\n  adult: movie.adult,\n  budget: movie.budget,\n  genres: movie.genres,\n  relatedVideos: mapVideos(movie.videos),\n  originalLanguage: movie.original_language,\n  originalTitle: movie.original_title,\n  popularity: movie.popularity,\n  productionCompanies: movie.production_companies.map(mapProductionCompany),\n  productionCountries: movie.production_countries,\n  releaseDate: movie.release_date,\n  releases: movie.release_dates,\n  revenue: movie.revenue,\n  spokenLanguages: movie.spoken_languages,\n  status: movie.status,\n  title: movie.title,\n  video: movie.video,\n  voteAverage: movie.vote_average,\n  voteCount: movie.vote_count,\n  backdropPath: movie.backdrop_path,\n  homepage: movie.homepage,\n  imdbId: movie.imdb_id,\n  overview: movie.overview,\n  posterPath: movie.poster_path,\n  runtime: movie.runtime,\n  tagline: movie.tagline,\n  credits: {\n    cast: movie.credits.cast.map(mapCast),\n    crew: movie.credits.crew.map(mapCrew),\n  },\n  collection: movie.belongs_to_collection\n    ? {\n        id: movie.belongs_to_collection.id,\n        name: movie.belongs_to_collection.name,\n        posterPath: movie.belongs_to_collection.poster_path,\n        backdropPath: movie.belongs_to_collection.backdrop_path,\n      }\n    : undefined,\n  externalIds: mapExternalIds(movie.external_ids),\n  mediaInfo: media,\n  watchProviders: mapWatchProviders(movie['watch/providers']?.results ?? {}),\n  keywords: movie.keywords.keywords.map((keyword) => ({\n    id: keyword.id,\n    name: keyword.name,\n  })),\n  onUserWatchlist: userWatchlist,\n});\n"
  },
  {
    "path": "server/models/Person.ts",
    "content": "import type {\n  TmdbPersonCreditCast,\n  TmdbPersonCreditCrew,\n  TmdbPersonDetails,\n} from '@server/api/themoviedb/interfaces';\nimport type Media from '@server/entity/Media';\n\nexport interface PersonDetails {\n  id: number;\n  name: string;\n  birthday: string;\n  deathday: string;\n  knownForDepartment: string;\n  alsoKnownAs?: string[];\n  gender: number;\n  biography: string;\n  popularity: number;\n  placeOfBirth?: string;\n  profilePath?: string;\n  adult: boolean;\n  imdbId?: string;\n  homepage?: string;\n}\n\nexport interface PersonCredit {\n  id: number;\n  originalLanguage: string;\n  episodeCount: number;\n  overview: string;\n  originCountry: string[];\n  originalName: string;\n  voteCount: number;\n  name: string;\n  mediaType?: string;\n  popularity: number;\n  creditId: string;\n  backdropPath?: string;\n  firstAirDate: string;\n  voteAverage: number;\n  genreIds?: number[];\n  posterPath?: string;\n  originalTitle: string;\n  video?: boolean;\n  title: string;\n  adult: boolean;\n  releaseDate: string;\n  mediaInfo?: Media;\n}\n\nexport interface PersonCreditCast extends PersonCredit {\n  character: string;\n}\n\nexport interface PersonCreditCrew extends PersonCredit {\n  department: string;\n  job: string;\n}\n\nexport interface CombinedCredit {\n  id: number;\n  cast: PersonCreditCast[];\n  crew: PersonCreditCrew[];\n}\n\nexport const mapPersonDetails = (person: TmdbPersonDetails): PersonDetails => ({\n  id: person.id,\n  name: person.name,\n  birthday: person.birthday,\n  deathday: person.deathday,\n  knownForDepartment: person.known_for_department,\n  alsoKnownAs: person.also_known_as,\n  gender: person.gender,\n  biography: person.biography,\n  popularity: person.popularity,\n  placeOfBirth: person.place_of_birth,\n  profilePath: person.profile_path,\n  adult: person.adult,\n  imdbId: person.imdb_id,\n  homepage: person.homepage,\n});\n\nexport const mapCastCredits = (\n  cast: TmdbPersonCreditCast,\n  media?: Media\n): PersonCreditCast => ({\n  id: cast.id,\n  originalLanguage: cast.original_language,\n  episodeCount: cast.episode_count,\n  overview: cast.overview,\n  originCountry: cast.origin_country,\n  originalName: cast.original_name,\n  voteCount: cast.vote_count,\n  name: cast.name,\n  mediaType: cast.media_type,\n  popularity: cast.popularity,\n  creditId: cast.credit_id,\n  backdropPath: cast.backdrop_path,\n  firstAirDate: cast.first_air_date,\n  voteAverage: cast.vote_average,\n  genreIds: cast.genre_ids,\n  posterPath: cast.poster_path,\n  originalTitle: cast.original_title,\n  video: cast.video,\n  title: cast.title,\n  adult: cast.adult,\n  releaseDate: cast.release_date,\n  character: cast.character,\n  mediaInfo: media,\n});\n\nexport const mapCrewCredits = (\n  crew: TmdbPersonCreditCrew,\n  media?: Media\n): PersonCreditCrew => ({\n  id: crew.id,\n  originalLanguage: crew.original_language,\n  episodeCount: crew.episode_count,\n  overview: crew.overview,\n  originCountry: crew.origin_country,\n  originalName: crew.original_name,\n  voteCount: crew.vote_count,\n  name: crew.name,\n  mediaType: crew.media_type,\n  popularity: crew.popularity,\n  creditId: crew.credit_id,\n  backdropPath: crew.backdrop_path,\n  firstAirDate: crew.first_air_date,\n  voteAverage: crew.vote_average,\n  genreIds: crew.genre_ids,\n  posterPath: crew.poster_path,\n  originalTitle: crew.original_title,\n  video: crew.video,\n  title: crew.title,\n  adult: crew.adult,\n  releaseDate: crew.release_date,\n  department: crew.department,\n  job: crew.job,\n  mediaInfo: media,\n});\n"
  },
  {
    "path": "server/models/Search.ts",
    "content": "import type {\n  TmdbCollectionResult,\n  TmdbMovieDetails,\n  TmdbMovieResult,\n  TmdbPersonDetails,\n  TmdbPersonResult,\n  TmdbTvDetails,\n  TmdbTvResult,\n} from '@server/api/themoviedb/interfaces';\nimport { MediaType as MainMediaType } from '@server/constants/media';\nimport type Media from '@server/entity/Media';\n\nexport type MediaType = 'tv' | 'movie' | 'person' | 'collection';\n\ninterface SearchResult {\n  id: number;\n  mediaType: MediaType;\n  popularity: number;\n  posterPath?: string;\n  backdropPath?: string;\n  voteCount: number;\n  voteAverage: number;\n  genreIds: number[];\n  overview: string;\n  originalLanguage: string;\n  mediaInfo?: Media;\n}\n\nexport interface MovieResult extends SearchResult {\n  mediaType: 'movie';\n  title: string;\n  originalTitle: string;\n  releaseDate: string;\n  adult: boolean;\n  video: boolean;\n  mediaInfo?: Media;\n}\n\nexport interface TvResult extends SearchResult {\n  mediaType: 'tv';\n  name: string;\n  originalName: string;\n  originCountry: string[];\n  firstAirDate: string;\n}\n\nexport interface CollectionResult {\n  id: number;\n  mediaType: 'collection';\n  title: string;\n  originalTitle: string;\n  adult: boolean;\n  posterPath?: string;\n  backdropPath?: string;\n  overview: string;\n  originalLanguage: string;\n}\n\nexport interface PersonResult {\n  id: number;\n  name: string;\n  popularity: number;\n  profilePath?: string;\n  adult: boolean;\n  mediaType: 'person';\n  knownFor: (MovieResult | TvResult)[];\n}\n\nexport type Results = MovieResult | TvResult | PersonResult | CollectionResult;\n\nexport const mapMovieResult = (\n  movieResult: TmdbMovieResult,\n  media?: Media\n): MovieResult => ({\n  id: movieResult.id,\n  mediaType: 'movie',\n  adult: movieResult.adult,\n  genreIds: movieResult.genre_ids,\n  originalLanguage: movieResult.original_language,\n  originalTitle: movieResult.original_title,\n  overview: movieResult.overview,\n  popularity: movieResult.popularity,\n  releaseDate: movieResult.release_date,\n  title: movieResult.title,\n  video: movieResult.video,\n  voteAverage: movieResult.vote_average,\n  voteCount: movieResult.vote_count,\n  backdropPath: movieResult.backdrop_path,\n  posterPath: movieResult.poster_path,\n  mediaInfo: media,\n});\n\nexport const mapTvResult = (\n  tvResult: TmdbTvResult,\n  media?: Media\n): TvResult => ({\n  id: tvResult.id,\n  firstAirDate: tvResult.first_air_date,\n  genreIds: tvResult.genre_ids,\n  // Some results from tmdb dont return the mediaType so we force it here!\n  mediaType: tvResult.media_type || 'tv',\n  name: tvResult.name,\n  originCountry: tvResult.origin_country,\n  originalLanguage: tvResult.original_language,\n  originalName: tvResult.original_name,\n  overview: tvResult.overview,\n  popularity: tvResult.popularity,\n  voteAverage: tvResult.vote_average,\n  voteCount: tvResult.vote_count,\n  backdropPath: tvResult.backdrop_path,\n  posterPath: tvResult.poster_path,\n  mediaInfo: media,\n});\n\nexport const mapCollectionResult = (\n  collectionResult: TmdbCollectionResult\n): CollectionResult => ({\n  id: collectionResult.id,\n  mediaType: collectionResult.media_type || 'collection',\n  adult: collectionResult.adult,\n  originalLanguage: collectionResult.original_language,\n  originalTitle: collectionResult.original_title,\n  title: collectionResult.title,\n  overview: collectionResult.overview,\n  backdropPath: collectionResult.backdrop_path,\n  posterPath: collectionResult.poster_path,\n});\n\nexport const mapPersonResult = (\n  personResult: TmdbPersonResult\n): PersonResult => ({\n  id: personResult.id,\n  name: personResult.name,\n  popularity: personResult.popularity,\n  adult: personResult.adult,\n  mediaType: personResult.media_type,\n  profilePath: personResult.profile_path,\n  knownFor: personResult.known_for.map((result) => {\n    if (result.media_type === 'movie') {\n      return mapMovieResult(result);\n    }\n\n    return mapTvResult(result);\n  }),\n});\n\nexport const mapSearchResults = (\n  results: (\n    | TmdbMovieResult\n    | TmdbTvResult\n    | TmdbPersonResult\n    | TmdbCollectionResult\n  )[],\n  media?: Media[]\n): Results[] =>\n  results.map((result) => {\n    switch (result.media_type) {\n      case 'movie':\n        return mapMovieResult(\n          result,\n          media?.find(\n            (req) =>\n              req.tmdbId === result.id && req.mediaType === MainMediaType.MOVIE\n          )\n        );\n      case 'tv':\n        return mapTvResult(\n          result,\n          media?.find(\n            (req) =>\n              req.tmdbId === result.id && req.mediaType === MainMediaType.TV\n          )\n        );\n      case 'collection':\n        return mapCollectionResult(result);\n      default:\n        return mapPersonResult(result);\n    }\n  });\n\nexport const mapMovieDetailsToResult = (\n  movieDetails: TmdbMovieDetails\n): TmdbMovieResult => ({\n  id: movieDetails.id,\n  media_type: 'movie',\n  adult: movieDetails.adult,\n  genre_ids: movieDetails.genres.map((genre) => genre.id),\n  original_language: movieDetails.original_language,\n  original_title: movieDetails.original_title,\n  overview: movieDetails.overview ?? '',\n  popularity: movieDetails.popularity,\n  release_date: movieDetails.release_date,\n  title: movieDetails.title,\n  video: movieDetails.video,\n  vote_average: movieDetails.vote_average,\n  vote_count: movieDetails.vote_count,\n  backdrop_path: movieDetails.backdrop_path,\n  poster_path: movieDetails.poster_path,\n});\n\nexport const mapTvDetailsToResult = (\n  tvDetails: TmdbTvDetails\n): TmdbTvResult => ({\n  id: tvDetails.id,\n  media_type: 'tv',\n  first_air_date: tvDetails.first_air_date,\n  genre_ids: tvDetails.genres.map((genre) => genre.id),\n  name: tvDetails.name,\n  origin_country: tvDetails.origin_country,\n  original_language: tvDetails.original_language,\n  original_name: tvDetails.original_name,\n  overview: tvDetails.overview,\n  popularity: tvDetails.popularity,\n  vote_average: tvDetails.vote_average,\n  vote_count: tvDetails.vote_count,\n  backdrop_path: tvDetails.backdrop_path,\n  poster_path: tvDetails.poster_path,\n});\n\nexport const mapPersonDetailsToResult = (\n  personDetails: TmdbPersonDetails\n): TmdbPersonResult => ({\n  id: personDetails.id,\n  media_type: 'person',\n  name: personDetails.name,\n  popularity: personDetails.popularity,\n  adult: personDetails.adult,\n  profile_path: personDetails.profile_path,\n  known_for: [],\n});\n"
  },
  {
    "path": "server/models/Tv.ts",
    "content": "import type {\n  TmdbNetwork,\n  TmdbSeasonWithEpisodes,\n  TmdbTvDetails,\n  TmdbTvEpisodeResult,\n  TmdbTvRatingResult,\n  TmdbTvSeasonResult,\n} from '@server/api/themoviedb/interfaces';\nimport type Media from '@server/entity/Media';\nimport type { Video } from './Movie';\nimport type {\n  Cast,\n  Crew,\n  ExternalIds,\n  Genre,\n  Keyword,\n  ProductionCompany,\n  TvNetwork,\n  WatchProviders,\n} from './common';\nimport {\n  mapAggregateCast,\n  mapCrew,\n  mapExternalIds,\n  mapVideos,\n  mapWatchProviders,\n} from './common';\n\ninterface Episode {\n  id: number;\n  name: string;\n  airDate: string | null;\n  episodeNumber: number;\n  overview: string;\n  productionCode: string;\n  seasonNumber: number;\n  showId: number;\n  stillPath?: string;\n  voteAverage: number;\n  voteCount: number;\n}\n\ninterface Season {\n  airDate: string;\n  id: number;\n  episodeCount: number;\n  name: string;\n  overview: string;\n  posterPath?: string;\n  seasonNumber: number;\n}\n\nexport interface SeasonWithEpisodes extends Omit<Season, 'episodeCount'> {\n  episodes: Episode[];\n  externalIds: ExternalIds;\n}\n\ninterface SpokenLanguage {\n  englishName: string;\n  iso_639_1: string;\n  name: string;\n}\n\nexport interface TvDetails {\n  id: number;\n  backdropPath?: string;\n  posterPath?: string;\n  contentRatings: TmdbTvRatingResult;\n  createdBy: {\n    id: number;\n    name: string;\n    gender: number;\n    profilePath?: string;\n  }[];\n  episodeRunTime: number[];\n  firstAirDate?: string;\n  genres: Genre[];\n  homepage: string;\n  inProduction: boolean;\n  relatedVideos?: Video[];\n  languages: string[];\n  lastAirDate: string;\n  lastEpisodeToAir?: Episode;\n  name: string;\n  nextEpisodeToAir?: Episode;\n  networks: TvNetwork[];\n  numberOfEpisodes: number;\n  numberOfSeasons: number;\n  originCountry: string[];\n  originalLanguage: string;\n  originalName: string;\n  overview: string;\n  popularity: number;\n  productionCompanies: ProductionCompany[];\n  productionCountries: {\n    iso_3166_1: string;\n    name: string;\n  }[];\n  spokenLanguages: SpokenLanguage[];\n  seasons: Season[];\n  status: string;\n  tagline?: string;\n  type: string;\n  voteAverage: number;\n  voteCount: number;\n  credits: {\n    cast: Cast[];\n    crew: Crew[];\n  };\n  externalIds: ExternalIds;\n  keywords: Keyword[];\n  mediaInfo?: Media;\n  watchProviders?: WatchProviders[];\n  onUserWatchlist?: boolean;\n}\n\nconst mapEpisodeResult = (episode: TmdbTvEpisodeResult): Episode => ({\n  id: episode.id,\n  airDate: episode.air_date,\n  episodeNumber: episode.episode_number,\n  name: episode.name,\n  overview: episode.overview,\n  productionCode: episode.production_code,\n  seasonNumber: episode.season_number,\n  showId: episode.show_id,\n  voteAverage: episode.vote_average,\n  voteCount: episode.vote_count,\n  stillPath: episode.still_path,\n});\n\nconst mapSeasonResult = (season: TmdbTvSeasonResult): Season => ({\n  airDate: season.air_date,\n  episodeCount: season.episode_count,\n  id: season.id,\n  name: season.name,\n  overview: season.overview,\n  seasonNumber: season.season_number,\n  posterPath: season.poster_path,\n});\n\nexport const mapSeasonWithEpisodes = (\n  season: TmdbSeasonWithEpisodes\n): SeasonWithEpisodes => ({\n  airDate: season.air_date,\n  episodes: season.episodes.map(mapEpisodeResult),\n  externalIds: mapExternalIds(season.external_ids),\n  id: season.id,\n  name: season.name,\n  overview: season.overview,\n  seasonNumber: season.season_number,\n  posterPath: season.poster_path,\n});\n\nexport const mapNetwork = (network: TmdbNetwork): TvNetwork => ({\n  id: network.id,\n  name: network.name,\n  originCountry: network.origin_country,\n  headquarters: network.headquarters,\n  homepage: network.homepage,\n  logoPath: network.logo_path,\n});\n\nexport const mapTvDetails = (\n  show: TmdbTvDetails,\n  media?: Media,\n  userWatchlist?: boolean\n): TvDetails => ({\n  createdBy: show.created_by,\n  episodeRunTime: show.episode_run_time,\n  firstAirDate: show.first_air_date,\n  genres: show.genres.map((genre) => ({\n    id: genre.id,\n    name: genre.name,\n  })),\n  relatedVideos: mapVideos(show.videos),\n  homepage: show.homepage,\n  id: show.id,\n  inProduction: show.in_production,\n  languages: show.languages,\n  lastAirDate: show.last_air_date,\n  name: show.name,\n  networks: show.networks.map(mapNetwork),\n  numberOfEpisodes: show.number_of_episodes,\n  numberOfSeasons: show.number_of_seasons,\n  originCountry: show.origin_country,\n  originalLanguage: show.original_language,\n  originalName: show.original_name,\n  tagline: show.tagline,\n  overview: show.overview,\n  popularity: show.popularity,\n  productionCompanies: show.production_companies.map((company) => ({\n    id: company.id,\n    name: company.name,\n    originCountry: company.origin_country,\n    logoPath: company.logo_path,\n  })),\n  productionCountries: show.production_countries,\n  contentRatings: show.content_ratings,\n  spokenLanguages: show.spoken_languages.map((language) => ({\n    englishName: language.english_name,\n    iso_639_1: language.iso_639_1,\n    name: language.name,\n  })),\n  seasons: show.seasons.map(mapSeasonResult),\n  status: show.status,\n  type: show.type,\n  voteAverage: show.vote_average,\n  voteCount: show.vote_count,\n  backdropPath: show.backdrop_path,\n  lastEpisodeToAir: show.last_episode_to_air\n    ? mapEpisodeResult(show.last_episode_to_air)\n    : undefined,\n  nextEpisodeToAir: show.next_episode_to_air\n    ? mapEpisodeResult(show.next_episode_to_air)\n    : undefined,\n  posterPath: show.poster_path,\n  credits: {\n    cast: show.aggregate_credits.cast.map(mapAggregateCast),\n    crew: show.credits.crew.map(mapCrew),\n  },\n  externalIds: mapExternalIds(show.external_ids),\n  keywords: show.keywords.results.map((keyword) => ({\n    id: keyword.id,\n    name: keyword.name,\n  })),\n  mediaInfo: media,\n  watchProviders: mapWatchProviders(show['watch/providers']?.results ?? {}),\n  onUserWatchlist: userWatchlist,\n});\n"
  },
  {
    "path": "server/models/common.ts",
    "content": "import type {\n  TmdbAggregateCreditCast,\n  TmdbCreditCast,\n  TmdbCreditCrew,\n  TmdbExternalIds,\n  TmdbVideo,\n  TmdbVideoResult,\n  TmdbWatchProviderDetails,\n  TmdbWatchProviders,\n} from '@server/api/themoviedb/interfaces';\nimport type { Video } from '@server/models/Movie';\n\nexport interface ProductionCompany {\n  id: number;\n  logoPath?: string;\n  originCountry: string;\n  name: string;\n  description?: string;\n  headquarters?: string;\n  homepage?: string;\n}\n\nexport interface TvNetwork {\n  id: number;\n  logoPath?: string;\n  originCountry?: string;\n  name: string;\n  headquarters?: string;\n  homepage?: string;\n}\n\nexport interface Keyword {\n  id: number;\n  name: string;\n}\n\nexport interface Genre {\n  id: number;\n  name: string;\n}\n\nexport interface Cast {\n  id: number;\n  castId: number;\n  character: string;\n  creditId: string;\n  gender?: number;\n  name: string;\n  order: number;\n  profilePath?: string;\n}\n\nexport interface Crew {\n  id: number;\n  creditId: string;\n  department: string;\n  gender?: number;\n  job: string;\n  name: string;\n  profilePath?: string;\n}\n\nexport interface ExternalIds {\n  imdbId?: string;\n  freebaseMid?: string;\n  freebaseId?: string;\n  tvdbId?: number;\n  tvrageId?: string;\n  facebookId?: string;\n  instagramId?: string;\n  twitterId?: string;\n}\n\nexport interface WatchProviders {\n  iso_3166_1: string;\n  link?: string;\n  buy?: WatchProviderDetails[];\n  flatrate?: WatchProviderDetails[];\n}\n\nexport interface WatchProviderDetails {\n  displayPriority?: number;\n  logoPath?: string;\n  id: number;\n  name: string;\n}\n\nexport const mapCast = (person: TmdbCreditCast): Cast => ({\n  castId: person.cast_id,\n  character: person.character,\n  creditId: person.credit_id,\n  id: person.id,\n  name: person.name,\n  order: person.order,\n  gender: person.gender,\n  profilePath: person.profile_path,\n});\n\nexport const mapAggregateCast = (person: TmdbAggregateCreditCast): Cast => ({\n  castId: person.cast_id,\n  // the first role is the one for which the actor appears the most as\n  character: person.roles[0].character,\n  creditId: person.roles[0].credit_id,\n  id: person.id,\n  name: person.name,\n  order: person.order,\n  gender: person.gender,\n  profilePath: person.profile_path,\n});\n\nexport const mapCrew = (person: TmdbCreditCrew): Crew => ({\n  creditId: person.credit_id,\n  department: person.department,\n  id: person.id,\n  job: person.job,\n  name: person.name,\n  gender: person.gender,\n  profilePath: person.profile_path,\n});\n\nexport const mapExternalIds = (eids: TmdbExternalIds): ExternalIds => ({\n  facebookId: eids.facebook_id,\n  freebaseId: eids.freebase_id,\n  freebaseMid: eids.freebase_mid,\n  imdbId: eids.imdb_id,\n  instagramId: eids.instagram_id,\n  tvdbId: eids.tvdb_id,\n  tvrageId: eids.tvrage_id,\n  twitterId: eids.twitter_id,\n});\n\nexport const mapVideos = (videoResult: TmdbVideoResult): Video[] =>\n  videoResult?.results.map(({ key, name, size, type, site }: TmdbVideo) => ({\n    site,\n    key,\n    name,\n    size,\n    type,\n    url: siteUrlCreator(site, key),\n  }));\n\nexport const mapWatchProviders = (watchProvidersResult: {\n  [iso_3166_1: string]: TmdbWatchProviders;\n}): WatchProviders[] =>\n  Object.entries(watchProvidersResult).map(\n    ([iso_3166_1, provider]) =>\n      ({\n        iso_3166_1,\n        link: provider.link,\n        buy: mapWatchProviderDetails(provider.buy ?? []),\n        flatrate: mapWatchProviderDetails(provider.flatrate ?? []),\n      }) as WatchProviders\n  );\n\nexport const mapWatchProviderDetails = (\n  watchProviderDetails: TmdbWatchProviderDetails[]\n): WatchProviderDetails[] =>\n  watchProviderDetails.map(\n    (provider) =>\n      ({\n        displayPriority: provider.display_priority,\n        logoPath: provider.logo_path,\n        id: provider.provider_id,\n        name: provider.provider_name,\n      }) as WatchProviderDetails\n  );\n\nconst siteUrlCreator = (site: Video['site'], key: string): string =>\n  ({\n    YouTube: `https://www.youtube.com/watch?v=${key}`,\n  })[site];\n"
  },
  {
    "path": "server/repositories/watchlist.repository.ts",
    "content": "import { getRepository } from '@server/datasource';\nimport { Watchlist } from '@server/entity/Watchlist';\n\nexport const UserRepository = getRepository(Watchlist).extend({\n  // findByName(firstName: string, lastName: string) {\n  //   return this.createQueryBuilder(\"user\")\n  //     .where(\"user.firstName = :firstName\", { firstName })\n  //     .andWhere(\"user.lastName = :lastName\", { lastName })\n  //     .getMany()\n  // },\n});\n"
  },
  {
    "path": "server/routes/auth.test.ts",
    "content": "import assert from 'node:assert/strict';\nimport { before, beforeEach, describe, it, mock } from 'node:test';\n\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport PreparedEmail from '@server/lib/email';\nimport { getSettings } from '@server/lib/settings';\nimport { checkUser } from '@server/middleware/auth';\nimport { setupTestDb } from '@server/test/db';\nimport type { Express } from 'express';\nimport express from 'express';\nimport session from 'express-session';\nimport request from 'supertest';\nimport authRoutes from './auth';\n\nconst emailMock = mock.method(PreparedEmail.prototype, 'send', async () => {\n  return undefined;\n}).mock;\n\nlet app: Express;\n\nfunction createApp() {\n  const app = express();\n  app.use(express.json());\n  app.use(\n    session({\n      secret: 'test-secret',\n      resave: false,\n      saveUninitialized: false,\n    })\n  );\n  app.use(checkUser);\n  app.use('/auth', authRoutes);\n  // Error handler matching how next({ status, message }) calls are handled\n  app.use(\n    (\n      err: { status?: number; message?: string },\n      _req: express.Request,\n      res: express.Response,\n      // We must provide a next function for the function signature here even though its not used\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      _next: express.NextFunction\n    ) => {\n      res\n        .status(err.status ?? 500)\n        .json({ status: err.status ?? 500, message: err.message });\n    }\n  );\n  return app;\n}\n\nbefore(async () => {\n  app = createApp();\n});\n\nsetupTestDb();\n\n/** Create a supertest agent that is logged in as the given user. */\nasync function authenticatedAgent(email: string, password: string) {\n  const agent = request.agent(app);\n  const settings = getSettings();\n  settings.main.localLogin = true;\n\n  const res = await agent.post('/auth/local').send({ email, password });\n\n  assert.strictEqual(res.status, 200);\n  return agent;\n}\n\ndescribe('GET /auth/me', () => {\n  it('returns 403 when not authenticated', async () => {\n    const res = await request(app).get('/auth/me');\n    assert.strictEqual(res.status, 403);\n  });\n\n  it('returns the authenticated user', async () => {\n    const agent = await authenticatedAgent('admin@seerr.dev', 'test1234');\n\n    const res = await agent.get('/auth/me');\n\n    assert.strictEqual(res.status, 200);\n    assert.ok('id' in res.body);\n    assert.strictEqual(res.body.displayName, 'admin');\n  });\n\n  it('includes userEmailRequired warning when email is required but invalid', async () => {\n    const settings = getSettings();\n    settings.notifications.agents.email.options.userEmailRequired = true;\n\n    // Change the user's email to something invalid\n    const userRepo = getRepository(User);\n    const user = await userRepo.findOneOrFail({\n      where: { email: 'admin@seerr.dev' },\n    });\n    user.email = 'not-an-email';\n    await userRepo.save(user);\n\n    // Log in with the changed email\n    const agent = request.agent(app);\n    settings.main.localLogin = true;\n    const loginRes = await agent\n      .post('/auth/local')\n      .send({ email: 'not-an-email', password: 'test1234' });\n    assert.strictEqual(loginRes.status, 200);\n\n    const res = await agent.get('/auth/me');\n\n    assert.strictEqual(res.status, 200);\n    assert.ok(res.body.warnings.includes('userEmailRequired'));\n\n    settings.notifications.agents.email.options.userEmailRequired = false;\n  });\n});\n\ndescribe('POST /auth/local', () => {\n  beforeEach(() => {\n    const settings = getSettings();\n    settings.main.localLogin = true;\n  });\n\n  it('returns 200 and user data on valid credentials', async () => {\n    const res = await request(app)\n      .post('/auth/local')\n      .send({ email: 'admin@seerr.dev', password: 'test1234' });\n\n    assert.strictEqual(res.status, 200);\n    assert.ok('id' in res.body);\n    // filter() strips sensitive fields like password\n    assert.ok(!('password' in res.body));\n  });\n\n  it('returns 403 on wrong password', async () => {\n    const res = await request(app)\n      .post('/auth/local')\n      .send({ email: 'admin@seerr.dev', password: 'wrongpassword' });\n\n    assert.strictEqual(res.status, 403);\n    assert.strictEqual(res.body.message, 'Access denied.');\n  });\n\n  it('returns 403 for nonexistent user', async () => {\n    const res = await request(app)\n      .post('/auth/local')\n      .send({ email: 'nobody@seerr.dev', password: 'test1234' });\n\n    assert.strictEqual(res.status, 403);\n    assert.strictEqual(res.body.message, 'Access denied.');\n  });\n\n  it('returns 500 when local login is disabled', async () => {\n    const settings = getSettings();\n    settings.main.localLogin = false;\n\n    const res = await request(app)\n      .post('/auth/local')\n      .send({ email: 'admin@seerr.dev', password: 'test1234' });\n\n    assert.strictEqual(res.status, 500);\n    assert.strictEqual(res.body.error, 'Password sign-in is disabled.');\n  });\n\n  it('returns 500 when email is missing', async () => {\n    const res = await request(app)\n      .post('/auth/local')\n      .send({ password: 'test1234' });\n\n    assert.strictEqual(res.status, 500);\n    assert.match(res.body.error, /email address and a password/);\n  });\n\n  it('returns 500 when password is missing', async () => {\n    const res = await request(app)\n      .post('/auth/local')\n      .send({ email: 'admin@seerr.dev' });\n\n    assert.strictEqual(res.status, 500);\n    assert.match(res.body.error, /email address and a password/);\n  });\n\n  it('is case-insensitive for email', async () => {\n    const res = await request(app)\n      .post('/auth/local')\n      .send({ email: 'Admin@Seerr.Dev', password: 'test1234' });\n\n    assert.strictEqual(res.status, 200);\n    assert.ok('id' in res.body);\n  });\n\n  it('allows the non-admin user to log in', async () => {\n    const res = await request(app)\n      .post('/auth/local')\n      .send({ email: 'friend@seerr.dev', password: 'test1234' });\n\n    assert.strictEqual(res.status, 200);\n    assert.ok('id' in res.body);\n  });\n\n  it('sets a session on successful login', async () => {\n    const agent = request.agent(app);\n\n    await agent\n      .post('/auth/local')\n      .send({ email: 'admin@seerr.dev', password: 'test1234' });\n\n    // Session should persist — /me should succeed\n    const meRes = await agent.get('/auth/me');\n    assert.strictEqual(meRes.status, 200);\n  });\n});\n\ndescribe('POST /auth/logout', () => {\n  it('returns 200 when not logged in', async () => {\n    const res = await request(app).post('/auth/logout');\n\n    assert.strictEqual(res.status, 200);\n    assert.strictEqual(res.body.status, 'ok');\n  });\n\n  it('destroys session and returns 200 when logged in', async () => {\n    const agent = await authenticatedAgent('admin@seerr.dev', 'test1234');\n\n    // Verify session is active\n    const meBeforeRes = await agent.get('/auth/me');\n    assert.strictEqual(meBeforeRes.status, 200);\n\n    const logoutRes = await agent.post('/auth/logout');\n    assert.strictEqual(logoutRes.status, 200);\n    assert.strictEqual(logoutRes.body.status, 'ok');\n\n    // Session should be invalidated — /me should fail\n    const meAfterRes = await agent.get('/auth/me');\n    assert.strictEqual(meAfterRes.status, 403);\n  });\n});\n\ndescribe('POST /auth/reset-password', () => {\n  beforeEach(() => {\n    emailMock.resetCalls();\n  });\n\n  it('returns 200 for a valid email', async () => {\n    const res = await request(app)\n      .post('/auth/reset-password')\n      .send({ email: 'admin@seerr.dev' });\n\n    assert.strictEqual(res.status, 200);\n    assert.strictEqual(res.body.status, 'ok');\n    assert.strictEqual(emailMock.callCount(), 1);\n  });\n\n  it('returns 200 for nonexistent email (does not reveal user existence)', async () => {\n    const res = await request(app)\n      .post('/auth/reset-password')\n      .send({ email: 'nonexistent@seerr.dev' });\n\n    assert.strictEqual(res.status, 200);\n    assert.strictEqual(res.body.status, 'ok');\n    assert.strictEqual(emailMock.callCount(), 0);\n  });\n\n  it('returns 500 when email is missing', async () => {\n    const res = await request(app).post('/auth/reset-password').send({});\n\n    assert.strictEqual(res.status, 500);\n    assert.strictEqual(res.body.message, 'Email address required.');\n    assert.strictEqual(emailMock.callCount(), 0);\n  });\n\n  it('sets a resetPasswordGuid on the user', async () => {\n    await request(app)\n      .post('/auth/reset-password')\n      .send({ email: 'admin@seerr.dev' });\n\n    const userRepo = getRepository(User);\n    const user = await userRepo\n      .createQueryBuilder('user')\n      .addSelect(['user.resetPasswordGuid', 'user.recoveryLinkExpirationDate'])\n      .where('user.email = :email', { email: 'admin@seerr.dev' })\n      .getOneOrFail();\n\n    assert.notStrictEqual(user.resetPasswordGuid, undefined);\n    assert.notStrictEqual(user.resetPasswordGuid, null);\n    assert.notStrictEqual(user.recoveryLinkExpirationDate, undefined);\n    assert.strictEqual(emailMock.callCount(), 1);\n  });\n});\n\ndescribe('POST /auth/reset-password/:guid', () => {\n  /** Trigger a password reset and return the guid. */\n  async function getResetGuid(email: string): Promise<string> {\n    await request(app).post('/auth/reset-password').send({ email });\n\n    const userRepo = getRepository(User);\n    const user = await userRepo\n      .createQueryBuilder('user')\n      .addSelect('user.resetPasswordGuid')\n      .where('user.email = :email', { email })\n      .getOneOrFail();\n\n    return user.resetPasswordGuid!;\n  }\n\n  it('resets password with a valid guid and password', async () => {\n    const guid = await getResetGuid('admin@seerr.dev');\n\n    const res = await request(app)\n      .post(`/auth/reset-password/${guid}`)\n      .send({ password: 'newpassword123' });\n\n    assert.strictEqual(res.status, 200);\n    assert.strictEqual(res.body.status, 'ok');\n\n    // Old password no longer works\n    const oldLogin = await request(app)\n      .post('/auth/local')\n      .send({ email: 'admin@seerr.dev', password: 'test1234' });\n    assert.strictEqual(oldLogin.status, 403);\n\n    // New password works\n    const newLogin = await request(app)\n      .post('/auth/local')\n      .send({ email: 'admin@seerr.dev', password: 'newpassword123' });\n    assert.strictEqual(newLogin.status, 200);\n  });\n\n  it('returns 500 for an invalid guid', async () => {\n    const res = await request(app)\n      .post('/auth/reset-password/invalid-guid-here')\n      .send({ password: 'newpassword123' });\n\n    assert.strictEqual(res.status, 500);\n    assert.strictEqual(res.body.message, 'Invalid password reset link.');\n  });\n\n  it('returns 500 when password is too short', async () => {\n    const guid = await getResetGuid('admin@seerr.dev');\n\n    const res = await request(app)\n      .post(`/auth/reset-password/${guid}`)\n      .send({ password: 'short' });\n\n    assert.strictEqual(res.status, 500);\n    assert.strictEqual(\n      res.body.message,\n      'Password must be at least 8 characters long.'\n    );\n  });\n\n  it('returns 500 when password is missing', async () => {\n    const guid = await getResetGuid('admin@seerr.dev');\n\n    const res = await request(app)\n      .post(`/auth/reset-password/${guid}`)\n      .send({});\n\n    assert.strictEqual(res.status, 500);\n    assert.strictEqual(\n      res.body.message,\n      'Password must be at least 8 characters long.'\n    );\n  });\n\n  it('returns 500 for an expired recovery link', async () => {\n    const guid = await getResetGuid('admin@seerr.dev');\n\n    // Expire the link\n    const userRepo = getRepository(User);\n    const user = await userRepo.findOneOrFail({\n      where: { email: 'admin@seerr.dev' },\n    });\n    user.recoveryLinkExpirationDate = new Date('2020-01-01');\n    await userRepo.save(user);\n\n    const res = await request(app)\n      .post(`/auth/reset-password/${guid}`)\n      .send({ password: 'newpassword123' });\n\n    assert.strictEqual(res.status, 500);\n    assert.strictEqual(res.body.message, 'Invalid password reset link.');\n  });\n\n  it('cannot reuse a guid after successful reset', async () => {\n    const guid = await getResetGuid('admin@seerr.dev');\n\n    // First reset succeeds\n    const first = await request(app)\n      .post(`/auth/reset-password/${guid}`)\n      .send({ password: 'newpassword123' });\n    assert.strictEqual(first.status, 200);\n\n    // Second reset with same guid fails (recoveryLinkExpirationDate was cleared)\n    const second = await request(app)\n      .post(`/auth/reset-password/${guid}`)\n      .send({ password: 'anotherpassword' });\n    assert.strictEqual(second.status, 500);\n  });\n});\n"
  },
  {
    "path": "server/routes/auth.ts",
    "content": "import JellyfinAPI from '@server/api/jellyfin';\nimport PlexTvAPI from '@server/api/plextv';\nimport { ApiErrorCode } from '@server/constants/error';\nimport { MediaServerType, ServerType } from '@server/constants/server';\nimport { UserType } from '@server/constants/user';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport { startJobs } from '@server/job/schedule';\nimport { Permission } from '@server/lib/permissions';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport { checkAvatarChanged } from '@server/routes/avatarproxy';\nimport { ApiError } from '@server/types/error';\nimport { getAppVersion } from '@server/utils/appVersion';\nimport { getHostname } from '@server/utils/getHostname';\nimport axios from 'axios';\nimport { Router } from 'express';\nimport net from 'net';\nimport validator from 'validator';\n\nconst authRoutes = Router();\n\nauthRoutes.get('/me', isAuthenticated(), async (req, res) => {\n  const userRepository = getRepository(User);\n  if (!req.user) {\n    return res.status(500).json({\n      status: 500,\n      error: 'Please sign in.',\n    });\n  }\n  const user = await userRepository.findOneOrFail({\n    where: { id: req.user.id },\n  });\n\n  // check if email is required in settings and if user has an valid email\n  const settings = await getSettings();\n  if (\n    settings.notifications.agents.email.options.userEmailRequired &&\n    !validator.isEmail(user.email, { require_tld: false })\n  ) {\n    user.warnings.push('userEmailRequired');\n    logger.warn(`User ${user.username} has no valid email address`);\n  }\n\n  return res.status(200).json(user);\n});\n\nauthRoutes.post('/plex', async (req, res, next) => {\n  const settings = getSettings();\n  const userRepository = getRepository(User);\n  const body = req.body as { authToken?: string };\n\n  if (!body.authToken) {\n    return next({\n      status: 500,\n      message: 'Authentication token required.',\n    });\n  }\n\n  if (\n    settings.main.mediaServerType != MediaServerType.NOT_CONFIGURED &&\n    (settings.main.mediaServerLogin === false ||\n      settings.main.mediaServerType != MediaServerType.PLEX)\n  ) {\n    return res.status(500).json({ error: 'Plex login is disabled' });\n  }\n  try {\n    // First we need to use this auth token to get the user's email from plex.tv\n    const plextv = new PlexTvAPI(body.authToken);\n    const account = await plextv.getUser();\n\n    // Next let's see if the user already exists\n    let user = await userRepository\n      .createQueryBuilder('user')\n      .where('user.plexId = :id', { id: account.id })\n      .orWhere('user.email = :email', {\n        email: account.email.toLowerCase(),\n      })\n      .getOne();\n\n    if (!user && !(await userRepository.count())) {\n      user = new User({\n        email: account.email,\n        plexUsername: account.username,\n        plexId: account.id,\n        plexToken: account.authToken,\n        permissions: Permission.ADMIN,\n        avatar: account.thumb,\n        userType: UserType.PLEX,\n      });\n\n      settings.main.mediaServerType = MediaServerType.PLEX;\n      await settings.save();\n      startJobs();\n\n      await userRepository.save(user);\n    } else {\n      const mainUser = await userRepository.findOneOrFail({\n        select: { id: true, plexToken: true, plexId: true, email: true },\n        where: { id: 1 },\n      });\n      const mainPlexTv = new PlexTvAPI(mainUser.plexToken ?? '');\n\n      if (!account.id) {\n        logger.error('Plex ID was missing from Plex.tv response', {\n          label: 'API',\n          ip: req.ip,\n          email: account.email,\n          plexUsername: account.username,\n        });\n\n        return next({\n          status: 500,\n          message: 'Something went wrong. Try again.',\n        });\n      }\n\n      if (\n        account.id === mainUser.plexId ||\n        (account.email === mainUser.email && !mainUser.plexId) ||\n        (await mainPlexTv.checkUserAccess(account.id))\n      ) {\n        if (user) {\n          if (!user.plexId) {\n            logger.info(\n              'Found matching Plex user; updating user with Plex data',\n              {\n                label: 'API',\n                ip: req.ip,\n                email: user.email,\n                userId: user.id,\n                plexId: account.id,\n                plexUsername: account.username,\n              }\n            );\n          }\n\n          user.plexToken = body.authToken;\n          user.plexId = account.id;\n          user.avatar = account.thumb;\n          user.email = account.email;\n          user.plexUsername = account.username;\n          user.userType = UserType.PLEX;\n\n          await userRepository.save(user);\n        } else if (!settings.main.newPlexLogin) {\n          logger.warn(\n            'Failed sign-in attempt by unimported Plex user with access to the media server',\n            {\n              label: 'API',\n              ip: req.ip,\n              email: account.email,\n              plexId: account.id,\n              plexUsername: account.username,\n            }\n          );\n          return next({\n            status: 403,\n            message: 'Access denied.',\n          });\n        } else {\n          logger.info(\n            'Sign-in attempt from Plex user with access to the media server; creating new Seerr user',\n            {\n              label: 'API',\n              ip: req.ip,\n              email: account.email,\n              plexId: account.id,\n              plexUsername: account.username,\n            }\n          );\n          user = new User({\n            email: account.email,\n            plexUsername: account.username,\n            plexId: account.id,\n            plexToken: account.authToken,\n            permissions: settings.main.defaultPermissions,\n            avatar: account.thumb,\n            userType: UserType.PLEX,\n          });\n\n          await userRepository.save(user);\n        }\n      } else {\n        logger.warn(\n          'Failed sign-in attempt by Plex user without access to the media server',\n          {\n            label: 'API',\n            ip: req.ip,\n            email: account.email,\n            plexId: account.id,\n            plexUsername: account.username,\n          }\n        );\n        return next({\n          status: 403,\n          message: 'Access denied.',\n        });\n      }\n    }\n\n    // Set logged in session\n    if (req.session) {\n      req.session.userId = user.id;\n    }\n\n    return res.status(200).json(user?.filter() ?? {});\n  } catch (e) {\n    logger.error('Something went wrong authenticating with Plex account', {\n      label: 'API',\n      errorMessage: e.message,\n      ip: req.ip,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to authenticate.',\n    });\n  }\n});\n\nfunction getUserAvatarUrl(user: User): string {\n  return `/avatarproxy/${user.jellyfinUserId}?v=${user.avatarVersion}`;\n}\n\nauthRoutes.post('/jellyfin', async (req, res, next) => {\n  const settings = getSettings();\n  const userRepository = getRepository(User);\n  const body = req.body as {\n    username?: string;\n    password?: string;\n    hostname?: string;\n    port?: number;\n    urlBase?: string;\n    useSsl?: boolean;\n    email?: string;\n    serverType?: number;\n  };\n\n  //Make sure jellyfin login is enabled, but only if jellyfin && Emby is not already configured\n  if (\n    // media server not configured, allow login for setup\n    settings.main.mediaServerType != MediaServerType.NOT_CONFIGURED &&\n    (settings.main.mediaServerLogin === false ||\n      // media server is neither jellyfin or emby\n      (settings.main.mediaServerType !== MediaServerType.JELLYFIN &&\n        settings.main.mediaServerType !== MediaServerType.EMBY))\n  ) {\n    return res.status(500).json({ error: 'Jellyfin login is disabled' });\n  }\n\n  if (!body.username) {\n    return res.status(500).json({ error: 'You must provide an username' });\n  } else if (settings.jellyfin.ip !== '' && body.hostname) {\n    return res\n      .status(500)\n      .json({ error: 'Jellyfin hostname already configured' });\n  } else if (settings.jellyfin.ip === '' && !body.hostname) {\n    return res.status(500).json({ error: 'No hostname provided.' });\n  }\n\n  try {\n    const hostname =\n      settings.jellyfin.ip !== ''\n        ? getHostname()\n        : getHostname({\n            useSsl: body.useSsl,\n            ip: body.hostname,\n            port: body.port,\n            urlBase: body.urlBase,\n          });\n\n    // Try to find deviceId that corresponds to jellyfin user, else generate a new one\n    let user = await userRepository.findOne({\n      where: { jellyfinUsername: body.username },\n      select: { id: true, jellyfinDeviceId: true },\n    });\n\n    let deviceId = 'BOT_seerr';\n    if (user && user.id === 1) {\n      // Admin is always BOT_seerr\n      deviceId = 'BOT_seerr';\n    } else if (user && user.jellyfinDeviceId) {\n      deviceId = user.jellyfinDeviceId;\n    } else if (body.username) {\n      deviceId = Buffer.from(`BOT_seerr_${body.username}`).toString('base64');\n    }\n\n    // First we need to attempt to log the user in to jellyfin\n    const jellyfinserver = new JellyfinAPI(hostname ?? '', undefined, deviceId);\n\n    const ip = req.ip;\n    let clientIp;\n\n    if (ip) {\n      if (net.isIPv4(ip)) {\n        clientIp = ip;\n      } else if (net.isIPv6(ip)) {\n        clientIp = ip.startsWith('::ffff:') ? ip.substring(7) : ip;\n      }\n    }\n\n    const account = await jellyfinserver.login(\n      body.username,\n      body.password,\n      clientIp\n    );\n\n    // Next let's see if the user already exists\n    user = await userRepository.findOne({\n      where: { jellyfinUserId: account.User.Id },\n    });\n\n    const missingAdminUser = !user && !(await userRepository.count());\n    if (\n      missingAdminUser ||\n      settings.main.mediaServerType === MediaServerType.NOT_CONFIGURED\n    ) {\n      // Check if user is admin on jellyfin\n      if (account.User.Policy.IsAdministrator === false) {\n        throw new ApiError(403, ApiErrorCode.NotAdmin);\n      }\n\n      if (\n        body.serverType !== MediaServerType.JELLYFIN &&\n        body.serverType !== MediaServerType.EMBY\n      ) {\n        throw new ApiError(500, ApiErrorCode.NoAdminUser);\n      }\n      settings.main.mediaServerType = body.serverType;\n\n      if (missingAdminUser) {\n        logger.info(\n          'Sign-in attempt from Jellyfin user with access to the media server; creating initial admin user for Seerr',\n          {\n            label: 'API',\n            ip: req.ip,\n            jellyfinUsername: account.User.Name,\n          }\n        );\n\n        // User doesn't exist, and there are no users in the database, we'll create the user\n        // with admin permissions\n\n        user = new User({\n          id: 1,\n          email: body.email || account.User.Name,\n          jellyfinUsername: account.User.Name,\n          jellyfinUserId: account.User.Id,\n          jellyfinDeviceId: deviceId,\n          jellyfinAuthToken: account.AccessToken,\n          permissions: Permission.ADMIN,\n          userType:\n            body.serverType === MediaServerType.JELLYFIN\n              ? UserType.JELLYFIN\n              : UserType.EMBY,\n        });\n        user.avatar = getUserAvatarUrl(user);\n\n        await userRepository.save(user);\n      } else {\n        logger.info(\n          'Sign-in attempt from Jellyfin user with access to the media server; editing admin user for Seerr',\n          {\n            label: 'API',\n            ip: req.ip,\n            jellyfinUsername: account.User.Name,\n          }\n        );\n\n        // User alread exist but settings.json is not configured, we'll edit the admin user\n\n        user = await userRepository.findOne({\n          where: { id: 1 },\n        });\n        if (!user) {\n          throw new Error('Unable to find admin user to edit');\n        }\n        user.email = body.email || account.User.Name;\n        user.jellyfinUsername = account.User.Name;\n        user.jellyfinUserId = account.User.Id;\n        user.jellyfinDeviceId = deviceId;\n        user.jellyfinAuthToken = account.AccessToken;\n        user.permissions = Permission.ADMIN;\n        user.avatar = getUserAvatarUrl(user);\n        user.userType =\n          body.serverType === MediaServerType.JELLYFIN\n            ? UserType.JELLYFIN\n            : UserType.EMBY;\n\n        await userRepository.save(user);\n      }\n\n      // Create an API key on Jellyfin from this admin user\n      const jellyfinClient = new JellyfinAPI(\n        hostname,\n        account.AccessToken,\n        deviceId\n      );\n      const apiKey = await jellyfinClient.createApiToken('Seerr');\n\n      const serverName = await jellyfinserver.getServerName();\n\n      settings.jellyfin.name = serverName;\n      settings.jellyfin.serverId = account.User.ServerId;\n      settings.jellyfin.ip = body.hostname ?? '';\n      settings.jellyfin.port = body.port ?? 8096;\n      settings.jellyfin.urlBase = body.urlBase ?? '';\n      settings.jellyfin.useSsl = body.useSsl ?? false;\n      settings.jellyfin.apiKey = apiKey;\n      await settings.save();\n      startJobs();\n    }\n    // User already exists, let's update their information\n    else if (account.User.Id === user?.jellyfinUserId) {\n      logger.info(\n        `Found matching ${\n          settings.main.mediaServerType === MediaServerType.JELLYFIN\n            ? ServerType.JELLYFIN\n            : ServerType.EMBY\n        } user; updating user with ${\n          settings.main.mediaServerType === MediaServerType.JELLYFIN\n            ? ServerType.JELLYFIN\n            : ServerType.EMBY\n        }`,\n        {\n          label: 'API',\n          ip: req.ip,\n          jellyfinUsername: account.User.Name,\n        }\n      );\n      user.avatar = getUserAvatarUrl(user);\n      user.jellyfinUsername = account.User.Name;\n\n      if (user.username === account.User.Name) {\n        user.username = '';\n      }\n\n      await userRepository.save(user);\n    } else if (!settings.main.newPlexLogin) {\n      logger.warn(\n        'Failed sign-in attempt by unimported Jellyfin user with access to the media server',\n        {\n          label: 'API',\n          ip: req.ip,\n          jellyfinUserId: account.User.Id,\n          jellyfinUsername: account.User.Name,\n        }\n      );\n      return next({\n        status: 403,\n        message: 'Access denied.',\n      });\n    } else if (!user) {\n      logger.info(\n        'Sign-in attempt from Jellyfin user with access to the media server; creating new Seerr user',\n        {\n          label: 'API',\n          ip: req.ip,\n          jellyfinUsername: account.User.Name,\n        }\n      );\n\n      user = new User({\n        email: body.email,\n        jellyfinUsername: account.User.Name,\n        jellyfinUserId: account.User.Id,\n        jellyfinDeviceId: deviceId,\n        permissions: settings.main.defaultPermissions,\n        userType:\n          settings.main.mediaServerType === MediaServerType.JELLYFIN\n            ? UserType.JELLYFIN\n            : UserType.EMBY,\n      });\n      user.avatar = getUserAvatarUrl(user);\n\n      //initialize Jellyfin/Emby users with local login\n      const passedExplicitPassword = body.password && body.password.length > 0;\n      if (passedExplicitPassword) {\n        await user.setPassword(body.password ?? '');\n      }\n      await userRepository.save(user);\n    }\n\n    if (user && user.jellyfinUserId) {\n      try {\n        const { changed } = await checkAvatarChanged(user);\n\n        if (changed) {\n          user.avatar = getUserAvatarUrl(user);\n          await userRepository.save(user);\n          logger.debug('Avatar updated during login', {\n            userId: user.id,\n            jellyfinUserId: user.jellyfinUserId,\n          });\n        }\n      } catch (error) {\n        logger.error('Error handling avatar during login', {\n          label: 'Auth',\n          errorMessage: error.message,\n        });\n      }\n    }\n\n    // Set logged in session\n    if (req.session) {\n      req.session.userId = user?.id;\n    }\n\n    return res.status(200).json(user?.filter() ?? {});\n  } catch (e) {\n    switch (e.errorCode) {\n      case ApiErrorCode.InvalidUrl:\n        logger.error(\n          `The provided ${\n            settings.main.mediaServerType === MediaServerType.JELLYFIN\n              ? ServerType.JELLYFIN\n              : ServerType.EMBY\n          } is invalid or the server is not reachable.`,\n          {\n            label: 'Auth',\n            error: e.errorCode,\n            status: e.statusCode,\n            hostname: getHostname({\n              useSsl: body.useSsl,\n              ip: body.hostname,\n              port: body.port,\n              urlBase: body.urlBase,\n            }),\n          }\n        );\n        return next({\n          status: e.statusCode,\n          message: e.errorCode,\n        });\n\n      case ApiErrorCode.InvalidCredentials:\n        logger.warn(\n          'Failed login attempt from user with incorrect Jellyfin credentials',\n          {\n            label: 'Auth',\n            account: {\n              ip: req.ip,\n              email: body.username,\n              password: '__REDACTED__',\n            },\n          }\n        );\n        return next({\n          status: e.statusCode,\n          message: e.errorCode,\n        });\n\n      case ApiErrorCode.NotAdmin:\n        logger.warn(\n          'Failed login attempt from user without admin permissions',\n          {\n            label: 'Auth',\n            account: {\n              ip: req.ip,\n              email: body.username,\n            },\n          }\n        );\n        return next({\n          status: e.statusCode,\n          message: e.errorCode,\n        });\n\n      case ApiErrorCode.NoAdminUser:\n        logger.warn(\n          'Failed login attempt from user without admin permissions and no admin user exists',\n          {\n            label: 'Auth',\n            account: {\n              ip: req.ip,\n              email: body.username,\n            },\n          }\n        );\n        return next({\n          status: e.statusCode,\n          message: e.errorCode,\n        });\n\n      default:\n        logger.error(e.message, { label: 'Auth' });\n        return next({\n          status: 500,\n          message: 'Something went wrong.',\n        });\n    }\n  }\n});\n\nauthRoutes.post('/local', async (req, res, next) => {\n  const settings = getSettings();\n  const userRepository = getRepository(User);\n  const body = req.body as { email?: string; password?: string };\n\n  if (!settings.main.localLogin) {\n    return res.status(500).json({ error: 'Password sign-in is disabled.' });\n  } else if (!body.email || !body.password) {\n    return res.status(500).json({\n      error: 'You must provide both an email address and a password.',\n    });\n  }\n  try {\n    const user = await userRepository\n      .createQueryBuilder('user')\n      .select(['user.id', 'user.email', 'user.password', 'user.plexId'])\n      .where('user.email = :email', { email: body.email.toLowerCase() })\n      .getOne();\n\n    if (!user || !(await user.passwordMatch(body.password))) {\n      logger.warn('Failed sign-in attempt using invalid Seerr password', {\n        label: 'API',\n        ip: req.ip,\n        email: body.email,\n        userId: user?.id,\n      });\n      return next({\n        status: 403,\n        message: 'Access denied.',\n      });\n    }\n\n    // Set logged in session\n    if (user && req.session) {\n      req.session.userId = user.id;\n    }\n\n    return res.status(200).json(user?.filter() ?? {});\n  } catch (e) {\n    logger.error('Something went wrong authenticating with Seerr password', {\n      label: 'API',\n      errorMessage: e.message,\n      ip: req.ip,\n      email: body.email,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to authenticate.',\n    });\n  }\n});\n\nauthRoutes.post('/logout', async (req, res, next) => {\n  try {\n    const userId = req.session?.userId;\n    if (!userId) {\n      return res.status(200).json({ status: 'ok' });\n    }\n\n    const settings = getSettings();\n    const isJellyfinOrEmby =\n      settings.main.mediaServerType === MediaServerType.JELLYFIN ||\n      settings.main.mediaServerType === MediaServerType.EMBY;\n\n    if (isJellyfinOrEmby) {\n      const user = await getRepository(User)\n        .createQueryBuilder('user')\n        .addSelect(['user.jellyfinUserId', 'user.jellyfinDeviceId'])\n        .where('user.id = :id', { id: userId })\n        .getOne();\n\n      if (user?.jellyfinUserId && user.jellyfinDeviceId) {\n        try {\n          const baseUrl = getHostname();\n          try {\n            await axios.delete(`${baseUrl}/Devices`, {\n              params: { Id: user.jellyfinDeviceId },\n              headers: {\n                'X-Emby-Authorization': `MediaBrowser Client=\"Seerr\", Device=\"Seerr\", DeviceId=\"seerr\", Version=\"${getAppVersion()}\", Token=\"${\n                  settings.jellyfin.apiKey\n                }\"`,\n              },\n            });\n          } catch (error) {\n            logger.error('Failed to delete Jellyfin device', {\n              label: 'Auth',\n              error: error instanceof Error ? error.message : 'Unknown error',\n              userId: user.id,\n              jellyfinUserId: user.jellyfinUserId,\n            });\n          }\n        } catch (error) {\n          logger.error('Failed to delete Jellyfin device', {\n            label: 'Auth',\n            error: error instanceof Error ? error.message : 'Unknown error',\n            userId: user.id,\n            jellyfinUserId: user.jellyfinUserId,\n          });\n        }\n      }\n    }\n\n    req.session?.destroy((err: Error | null) => {\n      if (err) {\n        logger.error('Failed to destroy session', {\n          label: 'Auth',\n          error: err.message,\n          userId,\n        });\n        return next({ status: 500, message: 'Failed to destroy session.' });\n      }\n      logger.debug('Successfully logged out user', {\n        label: 'Auth',\n        userId,\n      });\n      res.status(200).json({ status: 'ok' });\n    });\n  } catch (error) {\n    logger.error('Error during logout process', {\n      label: 'Auth',\n      error: error instanceof Error ? error.message : 'Unknown error',\n      userId: req.session?.userId,\n    });\n    next({ status: 500, message: 'Error during logout process.' });\n  }\n});\n\nauthRoutes.post('/reset-password', async (req, res, next) => {\n  const userRepository = getRepository(User);\n  const body = req.body as { email?: string };\n\n  if (!body.email) {\n    return next({\n      status: 500,\n      message: 'Email address required.',\n    });\n  }\n\n  const user = await userRepository\n    .createQueryBuilder('user')\n    .where('user.email = :email', { email: body.email.toLowerCase() })\n    .getOne();\n\n  if (user) {\n    await user.resetPassword();\n    await userRepository.save(user);\n    logger.info('Successfully sent password reset link', {\n      label: 'API',\n      ip: req.ip,\n      email: body.email,\n    });\n  } else {\n    logger.error('Something went wrong sending password reset link', {\n      label: 'API',\n      ip: req.ip,\n      email: body.email,\n    });\n  }\n\n  return res.status(200).json({ status: 'ok' });\n});\n\nauthRoutes.post('/reset-password/:guid', async (req, res, next) => {\n  const userRepository = getRepository(User);\n\n  if (!req.body.password || req.body.password?.length < 8) {\n    logger.warn('Failed password reset attempt using invalid new password', {\n      label: 'API',\n      ip: req.ip,\n      guid: req.params.guid,\n    });\n    return next({\n      status: 500,\n      message: 'Password must be at least 8 characters long.',\n    });\n  }\n\n  const user = await userRepository.findOne({\n    where: { resetPasswordGuid: req.params.guid },\n  });\n\n  if (!user) {\n    logger.warn('Failed password reset attempt using invalid recovery link', {\n      label: 'API',\n      ip: req.ip,\n      guid: req.params.guid,\n    });\n    return next({\n      status: 500,\n      message: 'Invalid password reset link.',\n    });\n  }\n\n  if (\n    !user.recoveryLinkExpirationDate ||\n    user.recoveryLinkExpirationDate <= new Date()\n  ) {\n    logger.warn('Failed password reset attempt using expired recovery link', {\n      label: 'API',\n      ip: req.ip,\n      guid: req.params.guid,\n      email: user.email,\n    });\n    return next({\n      status: 500,\n      message: 'Invalid password reset link.',\n    });\n  }\n  user.recoveryLinkExpirationDate = null;\n  await user.setPassword(req.body.password);\n  await userRepository.save(user);\n  logger.info('Successfully reset password', {\n    label: 'API',\n    ip: req.ip,\n    guid: req.params.guid,\n    email: user.email,\n  });\n\n  return res.status(200).json({ status: 'ok' });\n});\n\nexport default authRoutes;\n"
  },
  {
    "path": "server/routes/avatarproxy.ts",
    "content": "import { MediaServerType } from '@server/constants/server';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport ImageProxy from '@server/lib/imageproxy';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { getAppVersion } from '@server/utils/appVersion';\nimport { getHostname } from '@server/utils/getHostname';\nimport axios from 'axios';\nimport { Router } from 'express';\nimport gravatarUrl from 'gravatar-url';\nimport { createHash } from 'node:crypto';\n\nconst router = Router();\n\nlet _avatarImageProxy: ImageProxy | null = null;\n\nasync function initAvatarImageProxy() {\n  if (!_avatarImageProxy) {\n    const userRepository = getRepository(User);\n    const admin = await userRepository.findOne({\n      where: { id: 1 },\n      select: ['id', 'jellyfinUserId', 'jellyfinDeviceId'],\n      order: { id: 'ASC' },\n    });\n    const deviceId = admin?.jellyfinDeviceId || 'BOT_seerr';\n    const authToken = getSettings().jellyfin.apiKey;\n    _avatarImageProxy = new ImageProxy('avatar', '', {\n      headers: {\n        'X-Emby-Authorization': `MediaBrowser Client=\"Seerr\", Device=\"Seerr\", DeviceId=\"${deviceId}\", Version=\"${getAppVersion()}\", Token=\"${authToken}\"`,\n      },\n    });\n  }\n  return _avatarImageProxy;\n}\n\nfunction getJellyfinAvatarUrl(userId: string) {\n  const settings = getSettings();\n  return settings.main.mediaServerType === MediaServerType.JELLYFIN\n    ? `${getHostname()}/UserImage?UserId=${userId}`\n    : `${getHostname()}/Users/${userId}/Images/Primary?quality=90`;\n}\n\nfunction computeImageHash(buffer: Buffer): string {\n  return createHash('sha256').update(buffer).digest('hex');\n}\n\nexport async function checkAvatarChanged(\n  user: User\n): Promise<{ changed: boolean; etag?: string }> {\n  try {\n    if (!user || !user.jellyfinUserId) {\n      return { changed: false };\n    }\n\n    const jellyfinAvatarUrl = getJellyfinAvatarUrl(user.jellyfinUserId);\n\n    let headResponse;\n    try {\n      headResponse = await axios.head(jellyfinAvatarUrl);\n      if (headResponse.status !== 200) {\n        return { changed: false };\n      }\n    } catch {\n      return { changed: false };\n    }\n\n    const settings = getSettings();\n    let remoteVersion: string;\n    if (settings.main.mediaServerType === MediaServerType.JELLYFIN) {\n      const remoteLastModifiedStr = headResponse.headers['last-modified'] || '';\n      remoteVersion = (\n        Date.parse(remoteLastModifiedStr) || Date.now()\n      ).toString();\n    } else if (settings.main.mediaServerType === MediaServerType.EMBY) {\n      remoteVersion =\n        headResponse.headers['etag']?.replace(/\"/g, '') ||\n        Date.now().toString();\n    } else {\n      remoteVersion = Date.now().toString();\n    }\n\n    if (user.avatarVersion && user.avatarVersion === remoteVersion) {\n      return { changed: false, etag: user.avatarETag ?? undefined };\n    }\n\n    const avatarImageCache = await initAvatarImageProxy();\n    await avatarImageCache.clearCachedImage(jellyfinAvatarUrl);\n    const imageData = await avatarImageCache.getImage(\n      jellyfinAvatarUrl,\n      gravatarUrl(user.email || 'none', { default: 'mm', size: 200 })\n    );\n\n    const newHash = computeImageHash(imageData.imageBuffer);\n\n    const hasChanged = user.avatarETag !== newHash;\n\n    user.avatarVersion = remoteVersion;\n    if (hasChanged) {\n      user.avatarETag = newHash;\n    }\n\n    await getRepository(User).save(user);\n\n    return { changed: hasChanged, etag: newHash };\n  } catch (error) {\n    logger.error('Error checking avatar changes', {\n      errorMessage: error.message,\n    });\n    return { changed: false };\n  }\n}\n\nrouter.get('/:jellyfinUserId', async (req, res) => {\n  try {\n    if (!req.params.jellyfinUserId.match(/^[a-f0-9]{32}$/)) {\n      const mediaServerType = getSettings().main.mediaServerType;\n      throw new Error(\n        `Provided URL is not ${\n          mediaServerType === MediaServerType.JELLYFIN\n            ? 'a Jellyfin'\n            : 'an Emby'\n        } avatar.`\n      );\n    }\n\n    const avatarImageCache = await initAvatarImageProxy();\n\n    const userEtag = req.headers['if-none-match'];\n\n    const versionParam = req.query.v;\n\n    const user = await getRepository(User).findOne({\n      where: { jellyfinUserId: req.params.jellyfinUserId },\n    });\n\n    const fallbackUrl = gravatarUrl(user?.email || 'none', {\n      default: 'mm',\n      size: 200,\n    });\n\n    const jellyfinAvatarUrl = getJellyfinAvatarUrl(req.params.jellyfinUserId);\n\n    let imageData = await avatarImageCache.getImage(\n      jellyfinAvatarUrl,\n      fallbackUrl\n    );\n\n    if (imageData.meta.extension === 'json') {\n      // this is a 404\n      imageData = await avatarImageCache.getImage(fallbackUrl);\n    }\n\n    if (userEtag && userEtag === `\"${imageData.meta.etag}\"` && !versionParam) {\n      return res.status(304).end();\n    }\n\n    res.writeHead(200, {\n      'Content-Type': `image/${imageData.meta.extension}`,\n      'Content-Length': imageData.imageBuffer.length,\n      'Cache-Control': `public, max-age=${imageData.meta.curRevalidate}`,\n      ETag: `\"${imageData.meta.etag}\"`,\n      'OS-Cache-Key': imageData.meta.cacheKey,\n      'OS-Cache-Status': imageData.meta.cacheMiss ? 'MISS' : 'HIT',\n    });\n\n    res.end(imageData.imageBuffer);\n  } catch (e) {\n    logger.error('Failed to proxy avatar image', {\n      errorMessage: e.message,\n    });\n  }\n});\n\nexport default router;\n"
  },
  {
    "path": "server/routes/blocklist.ts",
    "content": "import { MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport { Blocklist } from '@server/entity/Blocklist';\nimport Media from '@server/entity/Media';\nimport type { BlocklistResultsResponse } from '@server/interfaces/api/blocklistInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport logger from '@server/logger';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport { Router } from 'express';\nimport { EntityNotFoundError, QueryFailedError } from 'typeorm';\nimport { z } from 'zod';\n\nconst blocklistRoutes = Router();\n\nexport const blocklistAdd = z.object({\n  tmdbId: z.coerce.number(),\n  mediaType: z.nativeEnum(MediaType),\n  title: z.coerce.string().optional(),\n  user: z.coerce.number(),\n});\n\nconst blocklistGet = z.object({\n  take: z.coerce.number().int().positive().default(25),\n  skip: z.coerce.number().int().nonnegative().default(0),\n  search: z.string().optional(),\n  filter: z.enum(['all', 'manual', 'blocklistedTags']).optional(),\n});\n\nblocklistRoutes.get(\n  '/',\n  isAuthenticated([Permission.MANAGE_BLOCKLIST, Permission.VIEW_BLOCKLIST], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    const { take, skip, search, filter } = blocklistGet.parse(req.query);\n\n    try {\n      let query = getRepository(Blocklist)\n        .createQueryBuilder('blocklist')\n        .leftJoinAndSelect('blocklist.user', 'user')\n        .where('1 = 1'); // Allow use of andWhere later\n\n      switch (filter) {\n        case 'manual':\n          query = query.andWhere('blocklist.blocklistedTags IS NULL');\n          break;\n        case 'blocklistedTags':\n          query = query.andWhere('blocklist.blocklistedTags IS NOT NULL');\n          break;\n      }\n\n      if (search) {\n        query = query.andWhere('blocklist.title like :title', {\n          title: `%${search}%`,\n        });\n      }\n\n      const [blocklistedItems, itemsCount] = await query\n        .orderBy('blocklist.createdAt', 'DESC')\n        .take(take)\n        .skip(skip)\n        .getManyAndCount();\n\n      return res.status(200).json({\n        pageInfo: {\n          pages: Math.ceil(itemsCount / take),\n          pageSize: take,\n          results: itemsCount,\n          page: Math.ceil(skip / take) + 1,\n        },\n        results: blocklistedItems,\n      } as BlocklistResultsResponse);\n    } catch (error) {\n      logger.error('Something went wrong while retrieving blocklisted items', {\n        label: 'Blocklist',\n        errorMessage: error.message,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve blocklisted items.',\n      });\n    }\n  }\n);\n\nblocklistRoutes.get(\n  '/:id',\n  isAuthenticated([Permission.MANAGE_BLOCKLIST], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    const mediaType = req.query.mediaType;\n    if (mediaType !== MediaType.MOVIE && mediaType !== MediaType.TV) {\n      return next({\n        status: 400,\n        message: 'Invalid or missing mediaType query parameter.',\n      });\n    }\n\n    try {\n      const blocklisteRepository = getRepository(Blocklist);\n\n      const blocklistItem = await blocklisteRepository.findOneOrFail({\n        where: {\n          tmdbId: Number(req.params.id),\n          mediaType,\n        },\n      });\n\n      return res.status(200).send(blocklistItem);\n    } catch (e) {\n      if (e instanceof EntityNotFoundError) {\n        return next({\n          status: 404,\n          message: e.message,\n        });\n      }\n      return next({ status: 500, message: e.message });\n    }\n  }\n);\n\nblocklistRoutes.post(\n  '/',\n  isAuthenticated([Permission.MANAGE_BLOCKLIST], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    try {\n      const values = blocklistAdd.parse(req.body);\n\n      await Blocklist.addToBlocklist({\n        blocklistRequest: values,\n      });\n\n      return res.status(201).send();\n    } catch (error) {\n      if (!(error instanceof Error)) {\n        return;\n      }\n\n      if (error instanceof QueryFailedError) {\n        switch (error.driverError.errno) {\n          case 19:\n            return next({ status: 412, message: 'Item already blocklisted' });\n          default:\n            logger.warn('Something wrong with data blocklist', {\n              tmdbId: req.body.tmdbId,\n              mediaType: req.body.mediaType,\n              label: 'Blocklist',\n            });\n            return next({ status: 409, message: 'Something wrong' });\n        }\n      }\n\n      return next({ status: 500, message: error.message });\n    }\n  }\n);\n\nblocklistRoutes.delete(\n  '/:id',\n  isAuthenticated([Permission.MANAGE_BLOCKLIST], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    const mediaType = req.query.mediaType;\n    if (mediaType !== MediaType.MOVIE && mediaType !== MediaType.TV) {\n      return next({\n        status: 400,\n        message: 'Invalid or missing mediaType query parameter.',\n      });\n    }\n\n    try {\n      const blocklisteRepository = getRepository(Blocklist);\n\n      const blocklistItem = await blocklisteRepository.findOneOrFail({\n        where: {\n          tmdbId: Number(req.params.id),\n          mediaType,\n        },\n      });\n\n      await blocklisteRepository.remove(blocklistItem);\n\n      const mediaRepository = getRepository(Media);\n\n      const mediaItem = await mediaRepository.findOneOrFail({\n        where: {\n          tmdbId: Number(req.params.id),\n          mediaType: req.query.mediaType as MediaType,\n        },\n      });\n\n      await mediaRepository.remove(mediaItem);\n\n      return res.status(204).send();\n    } catch (e) {\n      if (e instanceof EntityNotFoundError) {\n        return next({\n          status: 404,\n          message: e.message,\n        });\n      }\n      return next({ status: 500, message: e.message });\n    }\n  }\n);\n\nexport default blocklistRoutes;\n"
  },
  {
    "path": "server/routes/collection.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport { MediaType } from '@server/constants/media';\nimport Media from '@server/entity/Media';\nimport logger from '@server/logger';\nimport { mapCollection } from '@server/models/Collection';\nimport { Router } from 'express';\n\nconst collectionRoutes = Router();\n\ncollectionRoutes.get<{ id: string }>('/:id', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const collection = await tmdb.getCollection({\n      collectionId: Number(req.params.id),\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      collection.parts.map((part) => ({\n        tmdbId: part.id,\n        mediaType: MediaType.MOVIE,\n      }))\n    );\n\n    return res.status(200).json(mapCollection(collection, media));\n  } catch (e) {\n    logger.debug('Something went wrong retrieving collection', {\n      label: 'API',\n      errorMessage: e.message,\n      collectionId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve collection.',\n    });\n  }\n});\n\nexport default collectionRoutes;\n"
  },
  {
    "path": "server/routes/discover.ts",
    "content": "import PlexTvAPI from '@server/api/plextv';\nimport type { SortOptions } from '@server/api/themoviedb';\nimport TheMovieDb from '@server/api/themoviedb';\nimport type { TmdbKeyword } from '@server/api/themoviedb/interfaces';\nimport { MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport { User } from '@server/entity/User';\nimport { Watchlist } from '@server/entity/Watchlist';\nimport type {\n  GenreSliderItem,\n  WatchlistResponse,\n} from '@server/interfaces/api/discoverInterfaces';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { mapProductionCompany } from '@server/models/Movie';\nimport {\n  mapCollectionResult,\n  mapMovieResult,\n  mapPersonResult,\n  mapTvResult,\n} from '@server/models/Search';\nimport { mapNetwork } from '@server/models/Tv';\nimport { isCollection, isMovie, isPerson } from '@server/utils/typeHelpers';\nimport { Router } from 'express';\nimport { sortBy } from 'lodash';\nimport { z } from 'zod';\n\nexport const createTmdbWithRegionLanguage = (user?: User): TheMovieDb => {\n  const settings = getSettings();\n\n  const discoverRegion =\n    user?.settings?.streamingRegion === 'all'\n      ? ''\n      : user?.settings?.streamingRegion\n        ? user?.settings?.streamingRegion\n        : settings.main.discoverRegion;\n\n  const originalLanguage =\n    user?.settings?.originalLanguage === 'all'\n      ? ''\n      : user?.settings?.originalLanguage\n        ? user?.settings?.originalLanguage\n        : settings.main.originalLanguage;\n\n  return new TheMovieDb({\n    discoverRegion,\n    originalLanguage,\n  });\n};\n\nconst discoverRoutes = Router();\n\nconst QueryFilterOptions = z.object({\n  page: z.coerce.string().optional(),\n  sortBy: z.coerce.string().optional(),\n  primaryReleaseDateGte: z.coerce.string().optional(),\n  primaryReleaseDateLte: z.coerce.string().optional(),\n  firstAirDateGte: z.coerce.string().optional(),\n  firstAirDateLte: z.coerce.string().optional(),\n  studio: z.coerce.string().optional(),\n  genre: z.coerce.string().optional(),\n  keywords: z.coerce.string().optional(),\n  excludeKeywords: z.coerce.string().optional(),\n  language: z.coerce.string().optional(),\n  withRuntimeGte: z.coerce.string().optional(),\n  withRuntimeLte: z.coerce.string().optional(),\n  voteAverageGte: z.coerce.string().optional(),\n  voteAverageLte: z.coerce.string().optional(),\n  voteCountGte: z.coerce.string().optional(),\n  voteCountLte: z.coerce.string().optional(),\n  network: z.coerce.string().optional(),\n  watchProviders: z.coerce.string().optional(),\n  watchRegion: z.coerce.string().optional(),\n  status: z.coerce.string().optional(),\n  certification: z.coerce.string().optional(),\n  certificationGte: z.coerce.string().optional(),\n  certificationLte: z.coerce.string().optional(),\n  certificationCountry: z.coerce.string().optional(),\n  certificationMode: z.enum(['exact', 'range']).optional(),\n});\n\nexport type FilterOptions = z.infer<typeof QueryFilterOptions>;\nconst ApiQuerySchema = QueryFilterOptions.omit({\n  certificationMode: true,\n});\n\ndiscoverRoutes.get('/movies', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage(req.user);\n\n  try {\n    const query = ApiQuerySchema.parse(req.query);\n    const keywords = query.keywords;\n    const excludeKeywords = query.excludeKeywords;\n\n    const data = await tmdb.getDiscoverMovies({\n      page: Number(query.page),\n      sortBy: query.sortBy as SortOptions,\n      language: req.locale ?? query.language,\n      originalLanguage: query.language,\n      genre: query.genre,\n      studio: query.studio,\n      primaryReleaseDateLte: query.primaryReleaseDateLte\n        ? new Date(query.primaryReleaseDateLte).toISOString().split('T')[0]\n        : undefined,\n      primaryReleaseDateGte: query.primaryReleaseDateGte\n        ? new Date(query.primaryReleaseDateGte).toISOString().split('T')[0]\n        : undefined,\n      keywords,\n      excludeKeywords,\n      withRuntimeGte: query.withRuntimeGte,\n      withRuntimeLte: query.withRuntimeLte,\n      voteAverageGte: query.voteAverageGte,\n      voteAverageLte: query.voteAverageLte,\n      voteCountGte: query.voteCountGte,\n      voteCountLte: query.voteCountLte,\n      watchProviders: query.watchProviders,\n      watchRegion: query.watchRegion,\n      certification: query.certification,\n      certificationGte: query.certificationGte,\n      certificationLte: query.certificationLte,\n      certificationCountry: query.certificationCountry,\n    });\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      data.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: MediaType.MOVIE,\n      }))\n    );\n\n    let keywordData: TmdbKeyword[] = [];\n    if (keywords) {\n      const splitKeywords = keywords.split(',');\n\n      const keywordResults = await Promise.all(\n        splitKeywords.map(async (keywordId) => {\n          return await tmdb.getKeywordDetails({ keywordId: Number(keywordId) });\n        })\n      );\n\n      keywordData = keywordResults.filter(\n        (keyword): keyword is TmdbKeyword => keyword !== null\n      );\n    }\n\n    return res.status(200).json({\n      page: data.page,\n      totalPages: data.total_pages,\n      totalResults: data.total_results,\n      keywords: keywordData,\n      results: data.results.map((result) =>\n        mapMovieResult(\n          result,\n          media.find(\n            (req) =>\n              req.tmdbId === result.id && req.mediaType === MediaType.MOVIE\n          )\n        )\n      ),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving popular movies', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve popular movies.',\n    });\n  }\n});\n\ndiscoverRoutes.get<{ language: string }>(\n  '/movies/language/:language',\n  async (req, res, next) => {\n    const tmdb = createTmdbWithRegionLanguage(req.user);\n\n    try {\n      const languages = await tmdb.getLanguages();\n\n      const language = languages.find(\n        (lang) => lang.iso_639_1 === req.params.language\n      );\n\n      if (!language) {\n        return next({ status: 404, message: 'Language not found.' });\n      }\n\n      const data = await tmdb.getDiscoverMovies({\n        page: Number(req.query.page),\n        language: (req.query.language as string) ?? req.locale,\n        originalLanguage: req.params.language,\n      });\n\n      const media = await Media.getRelatedMedia(\n        req.user,\n        data.results.map((result) => ({\n          tmdbId: result.id,\n          mediaType: MediaType.MOVIE,\n        }))\n      );\n\n      return res.status(200).json({\n        page: data.page,\n        totalPages: data.total_pages,\n        totalResults: data.total_results,\n        language,\n        results: data.results.map((result) =>\n          mapMovieResult(\n            result,\n            media.find(\n              (req) =>\n                req.tmdbId === result.id && req.mediaType === MediaType.MOVIE\n            )\n          )\n        ),\n      });\n    } catch (e) {\n      logger.debug('Something went wrong retrieving movies by language', {\n        label: 'API',\n        errorMessage: e.message,\n        language: req.params.language,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve movies by language.',\n      });\n    }\n  }\n);\n\ndiscoverRoutes.get<{ genreId: string }>(\n  '/movies/genre/:genreId',\n  async (req, res, next) => {\n    const tmdb = createTmdbWithRegionLanguage(req.user);\n\n    try {\n      const genres = await tmdb.getMovieGenres({\n        language: (req.query.language as string) ?? req.locale,\n      });\n\n      const genre = genres.find(\n        (genre) => genre.id === Number(req.params.genreId)\n      );\n\n      if (!genre) {\n        return next({ status: 404, message: 'Genre not found.' });\n      }\n\n      const data = await tmdb.getDiscoverMovies({\n        page: Number(req.query.page),\n        language: (req.query.language as string) ?? req.locale,\n        genre: req.params.genreId as string,\n      });\n\n      const media = await Media.getRelatedMedia(\n        req.user,\n        data.results.map((result) => ({\n          tmdbId: result.id,\n          mediaType: MediaType.MOVIE,\n        }))\n      );\n\n      return res.status(200).json({\n        page: data.page,\n        totalPages: data.total_pages,\n        totalResults: data.total_results,\n        genre,\n        results: data.results.map((result) =>\n          mapMovieResult(\n            result,\n            media.find(\n              (req) =>\n                req.tmdbId === result.id && req.mediaType === MediaType.MOVIE\n            )\n          )\n        ),\n      });\n    } catch (e) {\n      logger.debug('Something went wrong retrieving movies by genre', {\n        label: 'API',\n        errorMessage: e.message,\n        genreId: req.params.genreId,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve movies by genre.',\n      });\n    }\n  }\n);\n\ndiscoverRoutes.get<{ studioId: string }>(\n  '/movies/studio/:studioId',\n  async (req, res, next) => {\n    const tmdb = new TheMovieDb();\n\n    try {\n      const studio = await tmdb.getStudio(Number(req.params.studioId));\n\n      const data = await tmdb.getDiscoverMovies({\n        page: Number(req.query.page),\n        language: (req.query.language as string) ?? req.locale,\n        studio: req.params.studioId as string,\n      });\n\n      const media = await Media.getRelatedMedia(\n        req.user,\n        data.results.map((result) => ({\n          tmdbId: result.id,\n          mediaType: MediaType.MOVIE,\n        }))\n      );\n\n      return res.status(200).json({\n        page: data.page,\n        totalPages: data.total_pages,\n        totalResults: data.total_results,\n        studio: mapProductionCompany(studio),\n        results: data.results.map((result) =>\n          mapMovieResult(\n            result,\n            media.find(\n              (med) =>\n                med.tmdbId === result.id && med.mediaType === MediaType.MOVIE\n            )\n          )\n        ),\n      });\n    } catch (e) {\n      logger.debug('Something went wrong retrieving movies by studio', {\n        label: 'API',\n        errorMessage: e.message,\n        studioId: req.params.studioId,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve movies by studio.',\n      });\n    }\n  }\n);\n\ndiscoverRoutes.get('/movies/upcoming', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage(req.user);\n\n  const now = new Date();\n  const offset = now.getTimezoneOffset();\n  const date = new Date(now.getTime() - offset * 60 * 1000)\n    .toISOString()\n    .split('T')[0];\n\n  try {\n    const data = await tmdb.getDiscoverMovies({\n      page: Number(req.query.page),\n      language: (req.query.language as string) ?? req.locale,\n      primaryReleaseDateGte: date,\n    });\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      data.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: MediaType.MOVIE,\n      }))\n    );\n\n    return res.status(200).json({\n      page: data.page,\n      totalPages: data.total_pages,\n      totalResults: data.total_results,\n      results: data.results.map((result) =>\n        mapMovieResult(\n          result,\n          media.find(\n            (med) =>\n              med.tmdbId === result.id && med.mediaType === MediaType.MOVIE\n          )\n        )\n      ),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving upcoming movies', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve upcoming movies.',\n    });\n  }\n});\n\ndiscoverRoutes.get('/tv', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage(req.user);\n\n  try {\n    const query = ApiQuerySchema.parse(req.query);\n    const keywords = query.keywords;\n    const excludeKeywords = query.excludeKeywords;\n    const data = await tmdb.getDiscoverTv({\n      page: Number(query.page),\n      sortBy: query.sortBy as SortOptions,\n      language: req.locale ?? query.language,\n      genre: query.genre,\n      network: query.network ? Number(query.network) : undefined,\n      firstAirDateLte: query.firstAirDateLte\n        ? new Date(query.firstAirDateLte).toISOString().split('T')[0]\n        : undefined,\n      firstAirDateGte: query.firstAirDateGte\n        ? new Date(query.firstAirDateGte).toISOString().split('T')[0]\n        : undefined,\n      originalLanguage: query.language,\n      keywords,\n      excludeKeywords,\n      withRuntimeGte: query.withRuntimeGte,\n      withRuntimeLte: query.withRuntimeLte,\n      voteAverageGte: query.voteAverageGte,\n      voteAverageLte: query.voteAverageLte,\n      voteCountGte: query.voteCountGte,\n      voteCountLte: query.voteCountLte,\n      watchProviders: query.watchProviders,\n      watchRegion: query.watchRegion,\n      withStatus: query.status,\n      certification: query.certification,\n      certificationGte: query.certificationGte,\n      certificationLte: query.certificationLte,\n      certificationCountry: query.certificationCountry,\n    });\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      data.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: MediaType.TV,\n      }))\n    );\n\n    let keywordData: TmdbKeyword[] = [];\n    if (keywords) {\n      const splitKeywords = keywords.split(',');\n\n      const keywordResults = await Promise.all(\n        splitKeywords.map(async (keywordId) => {\n          return await tmdb.getKeywordDetails({ keywordId: Number(keywordId) });\n        })\n      );\n\n      keywordData = keywordResults.filter(\n        (keyword): keyword is TmdbKeyword => keyword !== null\n      );\n    }\n\n    return res.status(200).json({\n      page: data.page,\n      totalPages: data.total_pages,\n      totalResults: data.total_results,\n      keywords: keywordData,\n      results: data.results.map((result) =>\n        mapTvResult(\n          result,\n          media.find(\n            (med) => med.tmdbId === result.id && med.mediaType === MediaType.TV\n          )\n        )\n      ),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving popular series', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve popular series.',\n    });\n  }\n});\n\ndiscoverRoutes.get<{ language: string }>(\n  '/tv/language/:language',\n  async (req, res, next) => {\n    const tmdb = createTmdbWithRegionLanguage(req.user);\n\n    try {\n      const languages = await tmdb.getLanguages();\n\n      const language = languages.find(\n        (lang) => lang.iso_639_1 === req.params.language\n      );\n\n      if (!language) {\n        return next({ status: 404, message: 'Language not found.' });\n      }\n\n      const data = await tmdb.getDiscoverTv({\n        page: Number(req.query.page),\n        language: (req.query.language as string) ?? req.locale,\n        originalLanguage: req.params.language,\n      });\n\n      const media = await Media.getRelatedMedia(\n        req.user,\n        data.results.map((result) => ({\n          tmdbId: result.id,\n          mediaType: MediaType.TV,\n        }))\n      );\n\n      return res.status(200).json({\n        page: data.page,\n        totalPages: data.total_pages,\n        totalResults: data.total_results,\n        language,\n        results: data.results.map((result) =>\n          mapTvResult(\n            result,\n            media.find(\n              (med) =>\n                med.tmdbId === result.id && med.mediaType === MediaType.TV\n            )\n          )\n        ),\n      });\n    } catch (e) {\n      logger.debug('Something went wrong retrieving series by language', {\n        label: 'API',\n        errorMessage: e.message,\n        language: req.params.language,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve series by language.',\n      });\n    }\n  }\n);\n\ndiscoverRoutes.get<{ genreId: string }>(\n  '/tv/genre/:genreId',\n  async (req, res, next) => {\n    const tmdb = createTmdbWithRegionLanguage(req.user);\n\n    try {\n      const genres = await tmdb.getTvGenres({\n        language: (req.query.language as string) ?? req.locale,\n      });\n\n      const genre = genres.find(\n        (genre) => genre.id === Number(req.params.genreId)\n      );\n\n      if (!genre) {\n        return next({ status: 404, message: 'Genre not found.' });\n      }\n\n      const data = await tmdb.getDiscoverTv({\n        page: Number(req.query.page),\n        language: (req.query.language as string) ?? req.locale,\n        genre: req.params.genreId,\n      });\n\n      const media = await Media.getRelatedMedia(\n        req.user,\n        data.results.map((result) => ({\n          tmdbId: result.id,\n          mediaType: MediaType.TV,\n        }))\n      );\n\n      return res.status(200).json({\n        page: data.page,\n        totalPages: data.total_pages,\n        totalResults: data.total_results,\n        genre,\n        results: data.results.map((result) =>\n          mapTvResult(\n            result,\n            media.find(\n              (med) =>\n                med.tmdbId === result.id && med.mediaType === MediaType.TV\n            )\n          )\n        ),\n      });\n    } catch (e) {\n      logger.debug('Something went wrong retrieving series by genre', {\n        label: 'API',\n        errorMessage: e.message,\n        genreId: req.params.genreId,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve series by genre.',\n      });\n    }\n  }\n);\n\ndiscoverRoutes.get<{ networkId: string }>(\n  '/tv/network/:networkId',\n  async (req, res, next) => {\n    const tmdb = new TheMovieDb();\n\n    try {\n      const network = await tmdb.getNetwork(Number(req.params.networkId));\n\n      const data = await tmdb.getDiscoverTv({\n        page: Number(req.query.page),\n        language: (req.query.language as string) ?? req.locale,\n        network: Number(req.params.networkId),\n      });\n\n      const media = await Media.getRelatedMedia(\n        req.user,\n        data.results.map((result) => ({\n          tmdbId: result.id,\n          mediaType: MediaType.TV,\n        }))\n      );\n\n      return res.status(200).json({\n        page: data.page,\n        totalPages: data.total_pages,\n        totalResults: data.total_results,\n        network: mapNetwork(network),\n        results: data.results.map((result) =>\n          mapTvResult(\n            result,\n            media.find(\n              (med) =>\n                med.tmdbId === result.id && med.mediaType === MediaType.TV\n            )\n          )\n        ),\n      });\n    } catch (e) {\n      logger.debug('Something went wrong retrieving series by network', {\n        label: 'API',\n        errorMessage: e.message,\n        networkId: req.params.networkId,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve series by network.',\n      });\n    }\n  }\n);\n\ndiscoverRoutes.get('/tv/upcoming', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage(req.user);\n\n  const now = new Date();\n  const offset = now.getTimezoneOffset();\n  const date = new Date(now.getTime() - offset * 60 * 1000)\n    .toISOString()\n    .split('T')[0];\n\n  try {\n    const data = await tmdb.getDiscoverTv({\n      page: Number(req.query.page),\n      language: (req.query.language as string) ?? req.locale,\n      firstAirDateGte: date,\n    });\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      data.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: MediaType.TV,\n      }))\n    );\n\n    return res.status(200).json({\n      page: data.page,\n      totalPages: data.total_pages,\n      totalResults: data.total_results,\n      results: data.results.map((result) =>\n        mapTvResult(\n          result,\n          media.find(\n            (med) => med.tmdbId === result.id && med.mediaType === MediaType.TV\n          )\n        )\n      ),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving upcoming series', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve upcoming series.',\n    });\n  }\n});\n\ndiscoverRoutes.get('/trending', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage(req.user);\n\n  try {\n    const mediaType = (req.query.mediaType as 'all' | 'movie' | 'tv') ?? 'all';\n    const timeWindow =\n      (req.query.timeWindow as 'day' | 'week') === 'week' ? 'week' : 'day';\n    const language = (req.query.language as string) ?? req.locale;\n    const page = Number(req.query.page);\n\n    const trendingFetchers = {\n      movie: async () => ({\n        data: await tmdb.getMovieTrending({ page, language, timeWindow }),\n        mapper: mapMovieResult,\n        type: MediaType.MOVIE,\n      }),\n      tv: async () => ({\n        data: await tmdb.getTvTrending({ page, language, timeWindow }),\n        mapper: mapTvResult,\n        type: MediaType.TV,\n      }),\n      all: async () => ({\n        data: await tmdb.getAllTrending({ page, language, timeWindow }),\n        mapper: (result: any, media?: Media) => {\n          if (isMovie(result)) {\n            return mapMovieResult(result, media);\n          } else if (isPerson(result)) {\n            return mapPersonResult(result);\n          } else if (isCollection(result)) {\n            return mapCollectionResult(result);\n          } else {\n            return mapTvResult(result, media);\n          }\n        },\n        type: null,\n      }),\n    } as const;\n\n    const { data, mapper, type } = await trendingFetchers[mediaType]();\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      data.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: isMovie(result) ? MediaType.MOVIE : MediaType.TV,\n      }))\n    );\n\n    return res.status(200).json({\n      page: data.page,\n      totalPages: data.total_pages,\n      totalResults: data.total_results,\n      results: data.results.map((result) => {\n        // - If \"type\" is set (case: \"movie\" or \"tv\"), the mediaType must also match.\n        // - If \"type\" is not set (case: \"all\"), only filter by tmdbId.\n        const selectedMedia = media.find(\n          (med) =>\n            med.tmdbId === result.id && (type ? med.mediaType === type : true)\n        );\n\n        return mapper(result, selectedMedia);\n      }),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving trending items', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve trending items.',\n    });\n  }\n});\n\ndiscoverRoutes.get<{ keywordId: string }>(\n  '/keyword/:keywordId/movies',\n  async (req, res, next) => {\n    const tmdb = new TheMovieDb();\n\n    try {\n      const data = await tmdb.getMoviesByKeyword({\n        keywordId: Number(req.params.keywordId),\n        page: Number(req.query.page),\n        language: (req.query.language as string) ?? req.locale,\n      });\n\n      const media = await Media.getRelatedMedia(\n        req.user,\n        data.results.map((result) => ({\n          tmdbId: result.id,\n          mediaType: MediaType.MOVIE,\n        }))\n      );\n\n      return res.status(200).json({\n        page: data.page,\n        totalPages: data.total_pages,\n        totalResults: data.total_results,\n        results: data.results.map((result) =>\n          mapMovieResult(\n            result,\n            media.find(\n              (med) =>\n                med.tmdbId === result.id && med.mediaType === MediaType.MOVIE\n            )\n          )\n        ),\n      });\n    } catch (e) {\n      logger.debug('Something went wrong retrieving movies by keyword', {\n        label: 'API',\n        errorMessage: e.message,\n        keywordId: req.params.keywordId,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve movies by keyword.',\n      });\n    }\n  }\n);\n\ndiscoverRoutes.get<{ language: string }, GenreSliderItem[]>(\n  '/genreslider/movie',\n  async (req, res, next) => {\n    const tmdb = new TheMovieDb();\n\n    try {\n      const mappedGenres: GenreSliderItem[] = [];\n\n      const genres = await tmdb.getMovieGenres({\n        language: (req.query.language as string) ?? req.locale,\n      });\n\n      await Promise.all(\n        genres.map(async (genre) => {\n          const genreData = await tmdb.getDiscoverMovies({\n            genre: genre.id.toString(),\n          });\n\n          mappedGenres.push({\n            id: genre.id,\n            name: genre.name,\n            backdrops: genreData.results\n              .filter((title) => !!title.backdrop_path)\n              .map((title) => title.backdrop_path) as string[],\n          });\n        })\n      );\n\n      const sortedData = sortBy(mappedGenres, 'name');\n\n      return res.status(200).json(sortedData);\n    } catch (e) {\n      logger.debug('Something went wrong retrieving the movie genre slider', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve movie genre slider.',\n      });\n    }\n  }\n);\n\ndiscoverRoutes.get<{ language: string }, GenreSliderItem[]>(\n  '/genreslider/tv',\n  async (req, res, next) => {\n    const tmdb = new TheMovieDb();\n\n    try {\n      const mappedGenres: GenreSliderItem[] = [];\n\n      const genres = await tmdb.getTvGenres({\n        language: (req.query.language as string) ?? req.locale,\n      });\n\n      await Promise.all(\n        genres.map(async (genre) => {\n          const genreData = await tmdb.getDiscoverTv({\n            genre: genre.id.toString(),\n          });\n\n          mappedGenres.push({\n            id: genre.id,\n            name: genre.name,\n            backdrops: genreData.results\n              .filter((title) => !!title.backdrop_path)\n              .map((title) => title.backdrop_path) as string[],\n          });\n        })\n      );\n\n      const sortedData = sortBy(mappedGenres, 'name');\n\n      return res.status(200).json(sortedData);\n    } catch (e) {\n      logger.debug('Something went wrong retrieving the series genre slider', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve series genre slider.',\n      });\n    }\n  }\n);\n\ndiscoverRoutes.get<Record<string, unknown>, WatchlistResponse>(\n  '/watchlist',\n  async (req, res) => {\n    const userRepository = getRepository(User);\n    const itemsPerPage = 20;\n    const page = req.query.page ? Number(req.query.page) : 1;\n    const offset = (page - 1) * itemsPerPage;\n\n    const activeUser = await userRepository.findOne({\n      where: { id: req.user?.id },\n      select: ['id', 'plexToken'],\n    });\n\n    if (activeUser && !activeUser?.plexToken) {\n      // Non-Plex users can only see their own watchlist\n      const [result, total] = await getRepository(Watchlist).findAndCount({\n        where: { requestedBy: { id: activeUser?.id } },\n        relations: {\n          /*requestedBy: true,media:true*/\n        },\n        // loadRelationIds: true,\n        take: itemsPerPage,\n        skip: offset,\n      });\n      if (total) {\n        return res.json({\n          page: page,\n          totalPages: Math.ceil(total / itemsPerPage),\n          totalResults: total,\n          results: result,\n        });\n      }\n    }\n    if (!activeUser?.plexToken) {\n      // We will just return an empty array if the user has no Plex token\n      return res.json({\n        page: 1,\n        totalPages: 1,\n        totalResults: 0,\n        results: [],\n      });\n    }\n\n    // List watchlist from Plex\n    const plexTV = new PlexTvAPI(activeUser.plexToken);\n\n    const watchlist = await plexTV.getWatchlist({ offset });\n\n    return res.json({\n      page,\n      totalPages: Math.ceil(watchlist.totalSize / itemsPerPage),\n      totalResults: watchlist.totalSize,\n      results: watchlist.items.map((item) => ({\n        id: item.tmdbId,\n        ratingKey: item.ratingKey,\n        title: item.title,\n        mediaType: item.type === 'show' ? 'tv' : 'movie',\n        tmdbId: item.tmdbId,\n      })),\n    });\n  }\n);\n\nexport default discoverRoutes;\n"
  },
  {
    "path": "server/routes/imageproxy.ts",
    "content": "import ImageProxy from '@server/lib/imageproxy';\nimport logger from '@server/logger';\nimport { Router } from 'express';\n\nconst router = Router();\n\n// Delay the initialization of ImageProxy instances until the proxy (if any) is properly configured\nlet _tmdbImageProxy: ImageProxy;\nfunction initTmdbImageProxy() {\n  if (!_tmdbImageProxy) {\n    _tmdbImageProxy = new ImageProxy('tmdb', 'https://image.tmdb.org', {\n      rateLimitOptions: {\n        maxRequests: 20,\n        maxRPS: 50,\n      },\n    });\n  }\n  return _tmdbImageProxy;\n}\nlet _tvdbImageProxy: ImageProxy;\nfunction initTvdbImageProxy() {\n  if (!_tvdbImageProxy) {\n    _tvdbImageProxy = new ImageProxy('tvdb', 'https://artworks.thetvdb.com', {\n      rateLimitOptions: {\n        maxRequests: 20,\n        maxRPS: 50,\n      },\n    });\n  }\n  return _tvdbImageProxy;\n}\n\nrouter.get('/:type/*', async (req, res) => {\n  const imagePath = req.path.replace(/^\\/\\w+/, '');\n\n  if (imagePath.startsWith('//') || imagePath.includes('://')) {\n    logger.error('Invalid URL for image proxy', { imagePath });\n    return res.status(403).send('Invalid URL for image proxy');\n  }\n\n  try {\n    let imageData;\n    if (req.params.type === 'tmdb') {\n      imageData = await initTmdbImageProxy().getImage(imagePath);\n    } else if (req.params.type === 'tvdb') {\n      imageData = await initTvdbImageProxy().getImage(imagePath);\n    } else {\n      logger.error('Unsupported image type', {\n        imagePath,\n        type: req.params.type,\n      });\n      res.status(400).send('Unsupported image type');\n      return;\n    }\n\n    res.writeHead(200, {\n      'Content-Type': `image/${imageData.meta.extension}`,\n      'Content-Length': imageData.imageBuffer.length,\n      'Cache-Control': `public, max-age=${imageData.meta.curRevalidate}`,\n      'OS-Cache-Key': imageData.meta.cacheKey,\n      'OS-Cache-Status': imageData.meta.cacheMiss ? 'MISS' : 'HIT',\n    });\n\n    res.end(imageData.imageBuffer);\n  } catch (e) {\n    logger.error('Failed to proxy image', {\n      imagePath,\n      errorMessage: e.message,\n    });\n    res.status(500).send();\n  }\n});\n\nexport default router;\n"
  },
  {
    "path": "server/routes/index.ts",
    "content": "import GithubAPI from '@server/api/github';\nimport PushoverAPI from '@server/api/pushover';\nimport TheMovieDb from '@server/api/themoviedb';\nimport type {\n  TmdbMovieResult,\n  TmdbTvResult,\n} from '@server/api/themoviedb/interfaces';\nimport { getRepository } from '@server/datasource';\nimport DiscoverSlider from '@server/entity/DiscoverSlider';\nimport type { StatusResponse } from '@server/interfaces/api/settingsInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { checkUser, isAuthenticated } from '@server/middleware/auth';\nimport deprecatedRoute from '@server/middleware/deprecation';\nimport { mapProductionCompany } from '@server/models/Movie';\nimport { mapNetwork } from '@server/models/Tv';\nimport { mapWatchProviderDetails } from '@server/models/common';\nimport overrideRuleRoutes from '@server/routes/overrideRule';\nimport settingsRoutes from '@server/routes/settings';\nimport watchlistRoutes from '@server/routes/watchlist';\nimport {\n  appDataPath,\n  appDataPermissions,\n  appDataStatus,\n} from '@server/utils/appDataVolume';\nimport { getAppVersion, getCommitTag } from '@server/utils/appVersion';\nimport restartFlag from '@server/utils/restartFlag';\nimport { isPerson } from '@server/utils/typeHelpers';\nimport { Router } from 'express';\nimport authRoutes from './auth';\nimport blocklistRoutes from './blocklist';\nimport collectionRoutes from './collection';\nimport discoverRoutes, { createTmdbWithRegionLanguage } from './discover';\nimport issueRoutes from './issue';\nimport issueCommentRoutes from './issueComment';\nimport mediaRoutes from './media';\nimport movieRoutes from './movie';\nimport personRoutes from './person';\nimport requestRoutes from './request';\nimport searchRoutes from './search';\nimport serviceRoutes from './service';\nimport tvRoutes from './tv';\nimport user from './user';\n\nconst router = Router();\n\nrouter.use(checkUser);\n\nrouter.get<unknown, StatusResponse>('/status', async (req, res) => {\n  const githubApi = new GithubAPI();\n\n  const currentVersion = getAppVersion();\n  const commitTag = getCommitTag();\n  let updateAvailable = false;\n  let commitsBehind = 0;\n\n  if (currentVersion.startsWith('develop-') && commitTag !== 'local') {\n    const commits = await githubApi.getSeerrCommits();\n\n    if (commits.length) {\n      const filteredCommits = commits.filter(\n        (commit) => !commit.commit.message.includes('[skip ci]')\n      );\n      if (filteredCommits[0].sha !== commitTag) {\n        updateAvailable = true;\n      }\n\n      const commitIndex = filteredCommits.findIndex(\n        (commit) => commit.sha === commitTag\n      );\n\n      if (updateAvailable) {\n        commitsBehind = commitIndex;\n      }\n    }\n  } else if (commitTag !== 'local') {\n    const releases = await githubApi.getSeerrReleases();\n\n    if (releases.length) {\n      const latestVersion = releases[0];\n\n      if (!latestVersion.name.includes(currentVersion)) {\n        updateAvailable = true;\n      }\n    }\n  }\n\n  return res.status(200).json({\n    version: getAppVersion(),\n    commitTag: getCommitTag(),\n    updateAvailable,\n    commitsBehind,\n    restartRequired: restartFlag.isSet(),\n  });\n});\n\nrouter.get('/status/appdata', (_req, res) => {\n  return res.status(200).json({\n    appData: appDataStatus(),\n    appDataPath: appDataPath(),\n    appDataPermissions: appDataPermissions(),\n  });\n});\n\nrouter.use('/user', isAuthenticated(), user);\nrouter.get('/settings/public', async (req, res) => {\n  const settings = getSettings();\n\n  if (!(req.user?.settings?.notificationTypes.webpush ?? true)) {\n    return res\n      .status(200)\n      .json({ ...settings.fullPublicSettings, enablePushRegistration: false });\n  } else {\n    return res.status(200).json(settings.fullPublicSettings);\n  }\n});\nrouter.get('/settings/discover', isAuthenticated(), async (_req, res) => {\n  const sliderRepository = getRepository(DiscoverSlider);\n\n  const sliders = await sliderRepository.find({ order: { order: 'ASC' } });\n\n  return res.json(sliders);\n});\nrouter.get(\n  '/settings/notifications/pushover/sounds',\n  isAuthenticated(),\n  async (req, res, next) => {\n    const pushoverApi = new PushoverAPI();\n\n    try {\n      if (!req.query.token) {\n        throw new Error('Pushover application token missing from request');\n      }\n\n      const sounds = await pushoverApi.getSounds(req.query.token as string);\n      res.status(200).json(sounds);\n    } catch (e) {\n      logger.debug('Something went wrong retrieving Pushover sounds', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve Pushover sounds.',\n      });\n    }\n  }\n);\nrouter.use('/settings', isAuthenticated(Permission.ADMIN), settingsRoutes);\nrouter.use('/search', isAuthenticated(), searchRoutes);\nrouter.use('/discover', isAuthenticated(), discoverRoutes);\nrouter.use('/request', isAuthenticated(), requestRoutes);\nrouter.use('/watchlist', isAuthenticated(), watchlistRoutes);\nrouter.use('/blocklist', isAuthenticated(), blocklistRoutes);\nrouter.use(\n  '/blacklist',\n  isAuthenticated(),\n  deprecatedRoute({\n    oldPath: '/api/v1/blacklist',\n    newPath: '/api/v1/blocklist',\n    sunsetDate: '2026-06-01',\n  }),\n  blocklistRoutes\n);\nrouter.use('/movie', isAuthenticated(), movieRoutes);\nrouter.use('/tv', isAuthenticated(), tvRoutes);\nrouter.use('/media', isAuthenticated(), mediaRoutes);\nrouter.use('/person', isAuthenticated(), personRoutes);\nrouter.use('/collection', isAuthenticated(), collectionRoutes);\nrouter.use('/service', isAuthenticated(), serviceRoutes);\nrouter.use('/issue', isAuthenticated(), issueRoutes);\nrouter.use('/issueComment', isAuthenticated(), issueCommentRoutes);\nrouter.use('/auth', authRoutes);\nrouter.use(\n  '/overrideRule',\n  isAuthenticated(Permission.ADMIN),\n  overrideRuleRoutes\n);\n\nrouter.get('/regions', isAuthenticated(), async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const regions = await tmdb.getRegions();\n\n    return res.status(200).json(regions);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving regions', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve regions.',\n    });\n  }\n});\n\nrouter.get('/languages', isAuthenticated(), async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const languages = await tmdb.getLanguages();\n\n    return res.status(200).json(languages);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving languages', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve languages.',\n    });\n  }\n});\n\nrouter.get<{ id: string }>('/studio/:id', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const studio = await tmdb.getStudio(Number(req.params.id));\n\n    return res.status(200).json(mapProductionCompany(studio));\n  } catch (e) {\n    logger.debug('Something went wrong retrieving studio', {\n      label: 'API',\n      errorMessage: e.message,\n      studioId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve studio.',\n    });\n  }\n});\n\nrouter.get<{ id: string }>('/network/:id', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const network = await tmdb.getNetwork(Number(req.params.id));\n\n    return res.status(200).json(mapNetwork(network));\n  } catch (e) {\n    logger.debug('Something went wrong retrieving network', {\n      label: 'API',\n      errorMessage: e.message,\n      networkId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve network.',\n    });\n  }\n});\n\nrouter.get('/genres/movie', isAuthenticated(), async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const genres = await tmdb.getMovieGenres({\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    return res.status(200).json(genres);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving movie genres', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve movie genres.',\n    });\n  }\n});\n\nrouter.get('/genres/tv', isAuthenticated(), async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const genres = await tmdb.getTvGenres({\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    return res.status(200).json(genres);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving series genres', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve series genres.',\n    });\n  }\n});\n\nrouter.get('/backdrops', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage();\n\n  try {\n    const data = (\n      await tmdb.getAllTrending({\n        page: 1,\n        timeWindow: 'week',\n      })\n    ).results.filter((result) => !isPerson(result)) as (\n      | TmdbMovieResult\n      | TmdbTvResult\n    )[];\n\n    return res\n      .status(200)\n      .json(\n        data\n          .map((result) => result.backdrop_path)\n          .filter((backdropPath) => !!backdropPath)\n      );\n  } catch (e) {\n    logger.debug('Something went wrong retrieving backdrops', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve backdrops.',\n    });\n  }\n});\n\nrouter.get('/keyword/:keywordId', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage();\n\n  try {\n    const result = await tmdb.getKeywordDetails({\n      keywordId: Number(req.params.keywordId),\n    });\n\n    return res.status(200).json(result);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving keyword data', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve keyword data.',\n    });\n  }\n});\n\nrouter.get('/watchproviders/regions', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage();\n\n  try {\n    const result = await tmdb.getAvailableWatchProviderRegions({});\n    return res.status(200).json(result);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving watch provider regions', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve watch provider regions.',\n    });\n  }\n});\n\nrouter.get('/watchproviders/movies', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage();\n\n  try {\n    const result = await tmdb.getMovieWatchProviders({\n      watchRegion: req.query.watchRegion as string,\n    });\n\n    return res.status(200).json(mapWatchProviderDetails(result));\n  } catch (e) {\n    logger.debug('Something went wrong retrieving movie watch providers', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve movie watch providers.',\n    });\n  }\n});\n\nrouter.get('/watchproviders/tv', async (req, res, next) => {\n  const tmdb = createTmdbWithRegionLanguage();\n\n  try {\n    const result = await tmdb.getTvWatchProviders({\n      watchRegion: req.query.watchRegion as string,\n    });\n\n    return res.status(200).json(mapWatchProviderDetails(result));\n  } catch (e) {\n    logger.debug('Something went wrong retrieving tv watch providers', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve tv watch providers.',\n    });\n  }\n});\n\nrouter.get(\n  '/certifications/movie',\n  isAuthenticated(),\n  async (req, res, next) => {\n    const tmdb = new TheMovieDb();\n\n    try {\n      const certifications = await tmdb.getMovieCertifications();\n\n      return res.status(200).json(certifications);\n    } catch (e) {\n      logger.error('Something went wrong retrieving movie certifications', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve movie certifications.',\n      });\n    }\n  }\n);\n\nrouter.get('/certifications/tv', isAuthenticated(), async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const certifications = await tmdb.getTvCertifications();\n\n    return res.status(200).json(certifications);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving TV certifications', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve TV certifications.',\n    });\n  }\n});\n\nrouter.get('/', (_req, res) => {\n  return res.status(200).json({\n    api: 'Seerr API',\n    version: '1.0',\n  });\n});\n\nexport default router;\n"
  },
  {
    "path": "server/routes/issue.ts",
    "content": "import { IssueStatus, IssueType } from '@server/constants/issue';\nimport { getRepository } from '@server/datasource';\nimport Issue from '@server/entity/Issue';\nimport IssueComment from '@server/entity/IssueComment';\nimport Media from '@server/entity/Media';\nimport type { IssueResultsResponse } from '@server/interfaces/api/issueInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport logger from '@server/logger';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport { Router } from 'express';\n\nconst issueRoutes = Router();\n\nissueRoutes.get<Record<string, string>, IssueResultsResponse>(\n  '/',\n  isAuthenticated(\n    [\n      Permission.MANAGE_ISSUES,\n      Permission.VIEW_ISSUES,\n      Permission.CREATE_ISSUES,\n    ],\n    { type: 'or' }\n  ),\n  async (req, res, next) => {\n    const pageSize = req.query.take ? Number(req.query.take) : 10;\n    const skip = req.query.skip ? Number(req.query.skip) : 0;\n    const createdBy = req.query.createdBy ? Number(req.query.createdBy) : null;\n\n    let sortFilter: string;\n\n    switch (req.query.sort) {\n      case 'modified':\n        sortFilter = 'issue.updatedAt';\n        break;\n      default:\n        sortFilter = 'issue.createdAt';\n    }\n\n    let statusFilter: IssueStatus[];\n\n    switch (req.query.filter) {\n      case 'open':\n        statusFilter = [IssueStatus.OPEN];\n        break;\n      case 'resolved':\n        statusFilter = [IssueStatus.RESOLVED];\n        break;\n      default:\n        statusFilter = [IssueStatus.OPEN, IssueStatus.RESOLVED];\n    }\n\n    let query = getRepository(Issue)\n      .createQueryBuilder('issue')\n      .leftJoinAndSelect('issue.createdBy', 'createdBy')\n      .leftJoinAndSelect('issue.media', 'media')\n      .leftJoinAndSelect('issue.modifiedBy', 'modifiedBy')\n      .leftJoinAndSelect('issue.comments', 'comments')\n      .where('issue.status IN (:...issueStatus)', {\n        issueStatus: statusFilter,\n      });\n\n    if (\n      !req.user?.hasPermission(\n        [Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES],\n        { type: 'or' }\n      )\n    ) {\n      if (createdBy && createdBy !== req.user?.id) {\n        return next({\n          status: 403,\n          message:\n            'You do not have permission to view issues reported by other users',\n        });\n      }\n      query = query.andWhere('createdBy.id = :id', { id: req.user?.id });\n    } else if (createdBy) {\n      query = query.andWhere('createdBy.id = :id', { id: createdBy });\n    }\n\n    const [issues, issueCount] = await query\n      .orderBy(sortFilter, 'DESC')\n      .take(pageSize)\n      .skip(skip)\n      .getManyAndCount();\n\n    return res.status(200).json({\n      pageInfo: {\n        pages: Math.ceil(issueCount / pageSize),\n        pageSize,\n        results: issueCount,\n        page: Math.ceil(skip / pageSize) + 1,\n      },\n      results: issues,\n    });\n  }\n);\n\nissueRoutes.post<\n  Record<string, string>,\n  Issue,\n  {\n    message: string;\n    mediaId: number;\n    issueType: number;\n    problemSeason: number;\n    problemEpisode: number;\n  }\n>(\n  '/',\n  isAuthenticated([Permission.MANAGE_ISSUES, Permission.CREATE_ISSUES], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    // Satisfy typescript here. User is set, we assure you!\n    if (!req.user) {\n      return next({ status: 500, message: 'User missing from request.' });\n    }\n\n    const issueRepository = getRepository(Issue);\n    const mediaRepository = getRepository(Media);\n\n    const media = await mediaRepository.findOne({\n      where: { id: req.body.mediaId },\n    });\n\n    if (!media) {\n      return next({ status: 404, message: 'Media does not exist.' });\n    }\n\n    const issue = new Issue({\n      createdBy: req.user,\n      issueType: req.body.issueType,\n      problemSeason: req.body.problemSeason,\n      problemEpisode: req.body.problemEpisode,\n      media,\n      comments: [\n        new IssueComment({\n          user: req.user,\n          message: req.body.message,\n        }),\n      ],\n    });\n\n    const newIssue = await issueRepository.save(issue);\n\n    return res.status(200).json(newIssue);\n  }\n);\n\nissueRoutes.get('/count', async (req, res, next) => {\n  const issueRepository = getRepository(Issue);\n\n  try {\n    const query = issueRepository.createQueryBuilder('issue');\n\n    const totalCount = await query.getCount();\n\n    const videoCount = await query\n      .where('issue.issueType = :issueType', {\n        issueType: IssueType.VIDEO,\n      })\n      .getCount();\n\n    const audioCount = await query\n      .where('issue.issueType = :issueType', {\n        issueType: IssueType.AUDIO,\n      })\n      .getCount();\n\n    const subtitlesCount = await query\n      .where('issue.issueType = :issueType', {\n        issueType: IssueType.SUBTITLES,\n      })\n      .getCount();\n\n    const othersCount = await query\n      .where('issue.issueType = :issueType', {\n        issueType: IssueType.OTHER,\n      })\n      .getCount();\n\n    const openCount = await query\n      .where('issue.status = :issueStatus', {\n        issueStatus: IssueStatus.OPEN,\n      })\n      .getCount();\n\n    const closedCount = await query\n      .where('issue.status = :issueStatus', {\n        issueStatus: IssueStatus.RESOLVED,\n      })\n      .getCount();\n\n    return res.status(200).json({\n      total: totalCount,\n      video: videoCount,\n      audio: audioCount,\n      subtitles: subtitlesCount,\n      others: othersCount,\n      open: openCount,\n      closed: closedCount,\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving issue counts.', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    next({ status: 500, message: 'Unable to retrieve issue counts.' });\n  }\n});\n\nissueRoutes.get<{ issueId: string }>(\n  '/:issueId',\n  isAuthenticated(\n    [\n      Permission.MANAGE_ISSUES,\n      Permission.VIEW_ISSUES,\n      Permission.CREATE_ISSUES,\n    ],\n    { type: 'or' }\n  ),\n  async (req, res, next) => {\n    const issueRepository = getRepository(Issue);\n    // Satisfy typescript here. User is set, we assure you!\n    if (!req.user) {\n      return next({ status: 500, message: 'User missing from request.' });\n    }\n\n    try {\n      const issue = await issueRepository\n        .createQueryBuilder('issue')\n        .leftJoinAndSelect('issue.comments', 'comments')\n        .leftJoinAndSelect('issue.createdBy', 'createdBy')\n        .leftJoinAndSelect('comments.user', 'user')\n        .leftJoinAndSelect('issue.media', 'media')\n        .where('issue.id = :issueId', { issueId: Number(req.params.issueId) })\n        .getOneOrFail();\n\n      if (\n        issue.createdBy.id !== req.user.id &&\n        !req.user.hasPermission(\n          [Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES],\n          { type: 'or' }\n        )\n      ) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to view this issue.',\n        });\n      }\n\n      return res.status(200).json(issue);\n    } catch (e) {\n      logger.debug('Failed to retrieve issue.', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      next({ status: 500, message: 'Issue not found.' });\n    }\n  }\n);\n\nissueRoutes.post<{ issueId: string }, Issue, { message: string }>(\n  '/:issueId/comment',\n  isAuthenticated([Permission.MANAGE_ISSUES, Permission.CREATE_ISSUES], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    const issueRepository = getRepository(Issue);\n    // Satisfy typescript here. User is set, we assure you!\n    if (!req.user) {\n      return next({ status: 500, message: 'User missing from request.' });\n    }\n\n    try {\n      const issue = await issueRepository.findOneOrFail({\n        where: { id: Number(req.params.issueId) },\n      });\n\n      if (\n        issue.createdBy.id !== req.user.id &&\n        !req.user.hasPermission(Permission.MANAGE_ISSUES)\n      ) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to comment on this issue.',\n        });\n      }\n\n      const comment = new IssueComment({\n        message: req.body.message,\n        user: req.user,\n      });\n\n      issue.comments = [...issue.comments, comment];\n      issue.updatedAt = new Date();\n      await issueRepository.save(issue);\n\n      return res.status(200).json(issue);\n    } catch (e) {\n      logger.debug('Something went wrong creating an issue comment.', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      next({ status: 500, message: 'Issue not found.' });\n    }\n  }\n);\n\nissueRoutes.post<{ issueId: string; status: string }, Issue>(\n  '/:issueId/:status',\n  isAuthenticated([Permission.MANAGE_ISSUES, Permission.CREATE_ISSUES], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    const issueRepository = getRepository(Issue);\n    // Satisfy typescript here. User is set, we assure you!\n    if (!req.user) {\n      return next({ status: 500, message: 'User missing from request.' });\n    }\n\n    try {\n      const issue = await issueRepository.findOneOrFail({\n        where: { id: Number(req.params.issueId) },\n      });\n\n      if (\n        !req.user?.hasPermission(Permission.MANAGE_ISSUES) &&\n        issue.createdBy.id !== req.user?.id\n      ) {\n        return next({\n          status: 401,\n          message: 'You do not have permission to modify this issue.',\n        });\n      }\n\n      let newStatus: IssueStatus | undefined;\n\n      switch (req.params.status) {\n        case 'resolved':\n          newStatus = IssueStatus.RESOLVED;\n          break;\n        case 'open':\n          newStatus = IssueStatus.OPEN;\n      }\n\n      if (!newStatus) {\n        return next({\n          status: 400,\n          message: 'You must provide a valid status',\n        });\n      }\n\n      issue.status = newStatus;\n      issue.modifiedBy = req.user;\n\n      await issueRepository.save(issue);\n\n      return res.status(200).json(issue);\n    } catch (e) {\n      logger.debug('Something went wrong creating an issue comment.', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      next({ status: 500, message: 'Issue not found.' });\n    }\n  }\n);\n\nissueRoutes.delete(\n  '/:issueId',\n  isAuthenticated([Permission.MANAGE_ISSUES, Permission.CREATE_ISSUES], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    const issueRepository = getRepository(Issue);\n\n    try {\n      const issue = await issueRepository.findOneOrFail({\n        where: { id: Number(req.params.issueId) },\n        relations: { createdBy: true },\n      });\n\n      if (\n        !req.user?.hasPermission(Permission.MANAGE_ISSUES) &&\n        (issue.createdBy.id !== req.user?.id || issue.comments.length > 1)\n      ) {\n        return next({\n          status: 401,\n          message: 'You do not have permission to delete this issue.',\n        });\n      }\n\n      await issueRepository.remove(issue);\n\n      return res.status(204).send();\n    } catch (e) {\n      logger.error('Something went wrong deleting an issue.', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      next({ status: 404, message: 'Issue not found.' });\n    }\n  }\n);\n\nexport default issueRoutes;\n"
  },
  {
    "path": "server/routes/issueComment.ts",
    "content": "import { getRepository } from '@server/datasource';\nimport IssueComment from '@server/entity/IssueComment';\nimport { Permission } from '@server/lib/permissions';\nimport logger from '@server/logger';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport { Router } from 'express';\n\nconst issueCommentRoutes = Router();\n\nissueCommentRoutes.get<{ commentId: string }, IssueComment>(\n  '/:commentId',\n  isAuthenticated(\n    [\n      Permission.MANAGE_ISSUES,\n      Permission.VIEW_ISSUES,\n      Permission.CREATE_ISSUES,\n    ],\n    {\n      type: 'or',\n    }\n  ),\n  async (req, res, next) => {\n    const issueCommentRepository = getRepository(IssueComment);\n\n    try {\n      const comment = await issueCommentRepository.findOneOrFail({\n        where: { id: Number(req.params.commentId) },\n      });\n\n      if (\n        !req.user?.hasPermission(\n          [Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES],\n          { type: 'or' }\n        ) &&\n        comment.user.id !== req.user?.id\n      ) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to view this comment.',\n        });\n      }\n\n      return res.status(200).json(comment);\n    } catch (e) {\n      logger.debug('Request for unknown issue comment failed', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      next({ status: 404, message: 'Issue comment not found.' });\n    }\n  }\n);\n\nissueCommentRoutes.put<\n  { commentId: string },\n  IssueComment,\n  { message: string }\n>(\n  '/:commentId',\n  isAuthenticated([Permission.MANAGE_ISSUES, Permission.CREATE_ISSUES], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    const issueCommentRepository = getRepository(IssueComment);\n\n    try {\n      const comment = await issueCommentRepository.findOneOrFail({\n        where: { id: Number(req.params.commentId) },\n      });\n\n      if (comment.user.id !== req.user?.id) {\n        return next({\n          status: 403,\n          message: 'You can only edit your own comments.',\n        });\n      }\n\n      comment.message = req.body.message;\n\n      await issueCommentRepository.save(comment);\n\n      return res.status(200).json(comment);\n    } catch (e) {\n      logger.debug('Put request for issue comment failed', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      next({ status: 404, message: 'Issue comment not found.' });\n    }\n  }\n);\n\nissueCommentRoutes.delete<{ commentId: string }, IssueComment>(\n  '/:commentId',\n  isAuthenticated([Permission.MANAGE_ISSUES, Permission.CREATE_ISSUES], {\n    type: 'or',\n  }),\n  async (req, res, next) => {\n    const issueCommentRepository = getRepository(IssueComment);\n\n    try {\n      const comment = await issueCommentRepository.findOneOrFail({\n        where: { id: Number(req.params.commentId) },\n      });\n\n      if (\n        !req.user?.hasPermission([Permission.MANAGE_ISSUES], { type: 'or' }) &&\n        comment.user.id !== req.user?.id\n      ) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to delete this comment.',\n        });\n      }\n\n      await issueCommentRepository.remove(comment);\n\n      return res.status(204).send();\n    } catch (e) {\n      logger.debug('Delete request for issue comment failed', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      next({ status: 404, message: 'Issue comment not found.' });\n    }\n  }\n);\n\nexport default issueCommentRoutes;\n"
  },
  {
    "path": "server/routes/media.ts",
    "content": "import RadarrAPI from '@server/api/servarr/radarr';\nimport SonarrAPI from '@server/api/servarr/sonarr';\nimport TautulliAPI from '@server/api/tautulli';\nimport TheMovieDb from '@server/api/themoviedb';\nimport { MediaStatus, MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport Season from '@server/entity/Season';\nimport { User } from '@server/entity/User';\nimport type {\n  MediaResultsResponse,\n  MediaWatchDataResponse,\n} from '@server/interfaces/api/mediaInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport { Router } from 'express';\nimport type { FindOneOptions } from 'typeorm';\nimport { In, IsNull, Not } from 'typeorm';\n\nconst mediaRoutes = Router();\n\nmediaRoutes.get('/', async (req, res, next) => {\n  const mediaRepository = getRepository(Media);\n\n  const pageSize = req.query.take ? Number(req.query.take) : 20;\n  const skip = req.query.skip ? Number(req.query.skip) : 0;\n\n  let statusFilter = undefined;\n\n  switch (req.query.filter) {\n    case 'available':\n      statusFilter = MediaStatus.AVAILABLE;\n      break;\n    case 'partial':\n      statusFilter = MediaStatus.PARTIALLY_AVAILABLE;\n      break;\n    case 'allavailable':\n      statusFilter = In([\n        MediaStatus.AVAILABLE,\n        MediaStatus.PARTIALLY_AVAILABLE,\n      ]);\n      break;\n    case 'processing':\n      statusFilter = MediaStatus.PROCESSING;\n      break;\n    case 'pending':\n      statusFilter = MediaStatus.PENDING;\n      break;\n  }\n\n  let sortFilter: FindOneOptions<Media>['order'] = {\n    id: 'DESC',\n  };\n\n  switch (req.query.sort) {\n    case 'modified':\n      sortFilter = {\n        updatedAt: 'DESC',\n      };\n      break;\n    case 'mediaAdded':\n      sortFilter = {\n        mediaAddedAt: 'DESC',\n      };\n  }\n\n  let whereClause: FindOneOptions<Media>['where'];\n  if (statusFilter || req.query.sort === 'mediaAdded') {\n    whereClause = {};\n    if (statusFilter) whereClause.status = statusFilter;\n    if (req.query.sort === 'mediaAdded')\n      whereClause.mediaAddedAt = Not(IsNull());\n  }\n\n  try {\n    const [media, mediaCount] = await mediaRepository.findAndCount({\n      order: sortFilter,\n      where: whereClause,\n      take: pageSize,\n      skip,\n    });\n    return res.status(200).json({\n      pageInfo: {\n        pages: Math.ceil(mediaCount / pageSize),\n        pageSize,\n        results: mediaCount,\n        page: Math.ceil(skip / pageSize) + 1,\n      },\n      results: media,\n    } as MediaResultsResponse);\n  } catch (e) {\n    next({ status: 500, message: e.message });\n  }\n});\n\nmediaRoutes.post<\n  {\n    id: string;\n    status: 'available' | 'partial' | 'processing' | 'pending' | 'unknown';\n  },\n  Media\n>(\n  '/:id/:status',\n  isAuthenticated(Permission.MANAGE_REQUESTS),\n  async (req, res, next) => {\n    const mediaRepository = getRepository(Media);\n    const seasonRepository = getRepository(Season);\n\n    const media = await mediaRepository.findOne({\n      where: { id: Number(req.params.id) },\n    });\n\n    if (!media) {\n      return next({ status: 404, message: 'Media does not exist.' });\n    }\n\n    const is4k = String(req.body.is4k) === 'true';\n\n    switch (req.params.status) {\n      case 'available':\n        media[is4k ? 'status4k' : 'status'] = MediaStatus.AVAILABLE;\n\n        if (media.mediaType === MediaType.TV) {\n          const expectedSeasons = req.body.seasons ?? [];\n\n          for (const expectedSeason of expectedSeasons) {\n            let season = media.seasons.find(\n              (s) => s.seasonNumber === expectedSeason?.seasonNumber\n            );\n\n            if (!season) {\n              // Create the season if it doesn't exist\n              season = seasonRepository.create({\n                seasonNumber: expectedSeason?.seasonNumber,\n              });\n              media.seasons.push(season);\n            }\n\n            season[is4k ? 'status4k' : 'status'] = MediaStatus.AVAILABLE;\n          }\n        }\n        break;\n      case 'partial':\n        if (media.mediaType === MediaType.MOVIE) {\n          return next({\n            status: 400,\n            message: 'Only series can be set to be partially available',\n          });\n        }\n        media[is4k ? 'status4k' : 'status'] = MediaStatus.PARTIALLY_AVAILABLE;\n        break;\n      case 'processing':\n        media[is4k ? 'status4k' : 'status'] = MediaStatus.PROCESSING;\n        break;\n      case 'pending':\n        media[is4k ? 'status4k' : 'status'] = MediaStatus.PENDING;\n        break;\n      case 'unknown':\n        media[is4k ? 'status4k' : 'status'] = MediaStatus.UNKNOWN;\n    }\n\n    await mediaRepository.save(media);\n\n    return res.status(200).json(media);\n  }\n);\n\nmediaRoutes.delete(\n  '/:id',\n  isAuthenticated(Permission.MANAGE_REQUESTS),\n  async (req, res, next) => {\n    try {\n      const mediaRepository = getRepository(Media);\n\n      const media = await mediaRepository.findOneOrFail({\n        where: { id: Number(req.params.id) },\n      });\n\n      if (media.status === MediaStatus.BLOCKLISTED) {\n        media.resetServiceData();\n        await mediaRepository.save(media);\n      } else {\n        await mediaRepository.remove(media);\n      }\n\n      return res.status(204).send();\n    } catch (e) {\n      logger.error('Something went wrong fetching media in delete request', {\n        label: 'Media',\n        message: e.message,\n      });\n      next({ status: 404, message: 'Media not found' });\n    }\n  }\n);\n\nmediaRoutes.delete(\n  '/:id/file',\n  isAuthenticated(Permission.MANAGE_REQUESTS),\n  async (req, res, next) => {\n    try {\n      const settings = getSettings();\n      const mediaRepository = getRepository(Media);\n      const media = await mediaRepository.findOneOrFail({\n        where: { id: Number(req.params.id) },\n      });\n\n      const is4k = String(req.query.is4k) === 'true';\n      const isMovie = media.mediaType === MediaType.MOVIE;\n\n      let serviceSettings;\n      if (isMovie) {\n        serviceSettings = settings.radarr.find(\n          (radarr) => radarr.isDefault && radarr.is4k === is4k\n        );\n      } else {\n        serviceSettings = settings.sonarr.find(\n          (sonarr) => sonarr.isDefault && sonarr.is4k === is4k\n        );\n      }\n\n      const specificServiceId = is4k ? media.serviceId4k : media.serviceId;\n      if (\n        specificServiceId &&\n        specificServiceId >= 0 &&\n        serviceSettings?.id !== specificServiceId\n      ) {\n        if (isMovie) {\n          serviceSettings = settings.radarr.find(\n            (radarr) => radarr.id === specificServiceId\n          );\n        } else {\n          serviceSettings = settings.sonarr.find(\n            (sonarr) => sonarr.id === specificServiceId\n          );\n        }\n      }\n\n      if (!serviceSettings) {\n        logger.warn(\n          `There is no default ${\n            is4k ? '4K ' : '' + isMovie ? 'Radarr' : 'Sonarr'\n          }/ server configured. Did you set any of your ${\n            is4k ? '4K ' : '' + isMovie ? 'Radarr' : 'Sonarr'\n          } servers as default?`,\n          {\n            label: 'Media Request',\n            mediaId: media.id,\n          }\n        );\n        return;\n      }\n\n      let service;\n      if (isMovie) {\n        service = new RadarrAPI({\n          apiKey: serviceSettings?.apiKey,\n          url: RadarrAPI.buildUrl(serviceSettings, '/api/v3'),\n        });\n      } else {\n        service = new SonarrAPI({\n          apiKey: serviceSettings?.apiKey,\n          url: SonarrAPI.buildUrl(serviceSettings, '/api/v3'),\n        });\n      }\n\n      if (isMovie) {\n        await (service as RadarrAPI).removeMovie(media.tmdbId);\n      } else {\n        const tmdb = new TheMovieDb();\n        const series = await tmdb.getTvShow({ tvId: media.tmdbId });\n        const tvdbId = series.external_ids.tvdb_id ?? media.tvdbId;\n        if (!tvdbId) {\n          throw new Error('TVDB ID not found');\n        }\n        await (service as SonarrAPI).removeSeries(tvdbId);\n      }\n\n      return res.status(204).send();\n    } catch (e) {\n      logger.error('Something went wrong fetching media in delete request', {\n        label: 'Media',\n        message: e.message,\n      });\n      next({ status: 404, message: 'Media not found' });\n    }\n  }\n);\n\nmediaRoutes.get<{ id: string }, MediaWatchDataResponse>(\n  '/:id/watch_data',\n  isAuthenticated(Permission.ADMIN),\n  async (req, res, next) => {\n    const settings = getSettings().tautulli;\n\n    if (!settings.hostname || !settings.port || !settings.apiKey) {\n      return next({\n        status: 404,\n        message: 'Tautulli API not configured.',\n      });\n    }\n\n    const media = await getRepository(Media).findOne({\n      where: { id: Number(req.params.id) },\n    });\n\n    if (!media) {\n      return next({ status: 404, message: 'Media does not exist.' });\n    }\n\n    try {\n      const tautulli = new TautulliAPI(settings);\n      const userRepository = getRepository(User);\n\n      const response: MediaWatchDataResponse = {};\n\n      if (media.ratingKey) {\n        const watchStats = await tautulli.getMediaWatchStats(media.ratingKey);\n        const watchUsers = await tautulli.getMediaWatchUsers(media.ratingKey);\n        const plexIds = watchUsers.map((u) => u.user_id);\n        if (!plexIds.length) plexIds.push(-1);\n\n        const users = await userRepository\n          .createQueryBuilder('user')\n          .where('user.plexId IN (:...plexIds)', { plexIds })\n          .getMany();\n\n        const playCount =\n          watchStats.find((i) => i.query_days == 0)?.total_plays ?? 0;\n\n        const playCount7Days =\n          watchStats.find((i) => i.query_days == 7)?.total_plays ?? 0;\n\n        const playCount30Days =\n          watchStats.find((i) => i.query_days == 30)?.total_plays ?? 0;\n\n        response.data = {\n          users: users,\n          playCount,\n          playCount7Days,\n          playCount30Days,\n        };\n      }\n\n      if (media.ratingKey4k) {\n        const watchStats4k = await tautulli.getMediaWatchStats(\n          media.ratingKey4k\n        );\n        const watchUsers4k = await tautulli.getMediaWatchUsers(\n          media.ratingKey4k\n        );\n        const plexIds4k = watchUsers4k.map((u) => u.user_id);\n        if (!plexIds4k.length) plexIds4k.push(-1);\n\n        const users = await userRepository\n          .createQueryBuilder('user')\n          .where('user.plexId IN (:...plexIds)', { plexIds: plexIds4k })\n          .getMany();\n\n        const playCount =\n          watchStats4k.find((i) => i.query_days == 0)?.total_plays ?? 0;\n\n        const playCount7Days =\n          watchStats4k.find((i) => i.query_days == 7)?.total_plays ?? 0;\n\n        const playCount30Days =\n          watchStats4k.find((i) => i.query_days == 30)?.total_plays ?? 0;\n\n        response.data4k = {\n          users,\n          playCount,\n          playCount7Days,\n          playCount30Days,\n        };\n      }\n\n      return res.status(200).json(response);\n    } catch (e) {\n      logger.error('Something went wrong fetching media watch data', {\n        label: 'API',\n        errorMessage: e.message,\n        mediaId: req.params.id,\n      });\n      next({ status: 500, message: 'Failed to fetch watch data.' });\n    }\n  }\n);\n\nexport default mediaRoutes;\n"
  },
  {
    "path": "server/routes/movie.ts",
    "content": "import IMDBRadarrProxy from '@server/api/rating/imdbRadarrProxy';\nimport RottenTomatoes from '@server/api/rating/rottentomatoes';\nimport { type RatingResponse } from '@server/api/ratings';\nimport TheMovieDb from '@server/api/themoviedb';\nimport { MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport { Watchlist } from '@server/entity/Watchlist';\nimport logger from '@server/logger';\nimport { mapMovieDetails } from '@server/models/Movie';\nimport { mapMovieResult } from '@server/models/Search';\nimport { Router } from 'express';\n\nconst movieRoutes = Router();\n\nmovieRoutes.get('/:id', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const tmdbMovie = await tmdb.getMovie({\n      movieId: Number(req.params.id),\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    const media = await Media.getMedia(tmdbMovie.id, MediaType.MOVIE);\n\n    const onUserWatchlist = await getRepository(Watchlist).exist({\n      where: {\n        tmdbId: Number(req.params.id),\n        mediaType: MediaType.MOVIE,\n        requestedBy: {\n          id: req.user?.id,\n        },\n      },\n    });\n\n    const data = mapMovieDetails(tmdbMovie, media, onUserWatchlist);\n\n    // TMDB issue where it doesnt fallback to English when no overview is available in requested locale.\n    if (!data.overview) {\n      const tvEnglish = await tmdb.getMovie({ movieId: Number(req.params.id) });\n      data.overview = tvEnglish.overview;\n    }\n\n    return res.status(200).json(data);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving movie', {\n      label: 'API',\n      errorMessage: e.message,\n      movieId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve movie.',\n    });\n  }\n});\n\nmovieRoutes.get('/:id/recommendations', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const results = await tmdb.getMovieRecommendations({\n      movieId: Number(req.params.id),\n      page: Number(req.query.page),\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      results.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: MediaType.MOVIE,\n      }))\n    );\n\n    return res.status(200).json({\n      page: results.page,\n      totalPages: results.total_pages,\n      totalResults: results.total_results,\n      results: results.results.map((result) =>\n        mapMovieResult(\n          result,\n          media.find(\n            (req) =>\n              req.tmdbId === result.id && req.mediaType === MediaType.MOVIE\n          )\n        )\n      ),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving movie recommendations', {\n      label: 'API',\n      errorMessage: e.message,\n      movieId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve movie recommendations.',\n    });\n  }\n});\n\nmovieRoutes.get('/:id/similar', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const results = await tmdb.getMovieSimilar({\n      movieId: Number(req.params.id),\n      page: Number(req.query.page),\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      results.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: MediaType.MOVIE,\n      }))\n    );\n\n    return res.status(200).json({\n      page: results.page,\n      totalPages: results.total_pages,\n      totalResults: results.total_results,\n      results: results.results.map((result) =>\n        mapMovieResult(\n          result,\n          media.find(\n            (req) =>\n              req.tmdbId === result.id && req.mediaType === MediaType.MOVIE\n          )\n        )\n      ),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving similar movies', {\n      label: 'API',\n      errorMessage: e.message,\n      movieId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve similar movies.',\n    });\n  }\n});\n\n/**\n * Endpoint backed by RottenTomatoes\n */\nmovieRoutes.get('/:id/ratings', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n  const rtapi = new RottenTomatoes();\n\n  try {\n    const movie = await tmdb.getMovie({\n      movieId: Number(req.params.id),\n    });\n\n    const rtratings = await rtapi.getMovieRatings(\n      movie.title,\n      Number(movie.release_date.slice(0, 4))\n    );\n\n    if (!rtratings) {\n      return next({\n        status: 404,\n        message: 'Rotten Tomatoes ratings not found.',\n      });\n    }\n\n    return res.status(200).json(rtratings);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving movie ratings', {\n      label: 'API',\n      errorMessage: e.message,\n      movieId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve movie ratings.',\n    });\n  }\n});\n\n/**\n * Endpoint combining RottenTomatoes and IMDB\n */\nmovieRoutes.get('/:id/ratingscombined', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n  const rtapi = new RottenTomatoes();\n  const imdbApi = new IMDBRadarrProxy();\n\n  try {\n    const movie = await tmdb.getMovie({\n      movieId: Number(req.params.id),\n    });\n\n    const rtratings = await rtapi.getMovieRatings(\n      movie.title,\n      Number(movie.release_date.slice(0, 4))\n    );\n\n    let imdbRatings;\n    if (movie.imdb_id) {\n      imdbRatings = await imdbApi.getMovieRatings(movie.imdb_id);\n    }\n\n    if (!rtratings && !imdbRatings) {\n      return next({\n        status: 404,\n        message: 'No ratings found.',\n      });\n    }\n\n    const ratings: RatingResponse = {\n      ...(rtratings ? { rt: rtratings } : {}),\n      ...(imdbRatings ? { imdb: imdbRatings } : {}),\n    };\n\n    return res.status(200).json(ratings);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving movie ratings', {\n      label: 'API',\n      errorMessage: e.message,\n      movieId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve movie ratings.',\n    });\n  }\n});\n\nexport default movieRoutes;\n"
  },
  {
    "path": "server/routes/overrideRule.ts",
    "content": "import { getRepository } from '@server/datasource';\nimport OverrideRule from '@server/entity/OverrideRule';\nimport type { OverrideRuleResultsResponse } from '@server/interfaces/api/overrideRuleInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport { Router } from 'express';\n\nconst overrideRuleRoutes = Router();\n\noverrideRuleRoutes.get(\n  '/',\n  isAuthenticated(Permission.ADMIN),\n  async (req, res, next) => {\n    const overrideRuleRepository = getRepository(OverrideRule);\n\n    try {\n      const rules = await overrideRuleRepository.find({});\n\n      return res.status(200).json(rules as OverrideRuleResultsResponse);\n    } catch (e) {\n      next({ status: 404, message: e.message });\n    }\n  }\n);\n\noverrideRuleRoutes.post<\n  Record<string, string>,\n  OverrideRule,\n  {\n    users?: string;\n    genre?: string;\n    language?: string;\n    keywords?: string;\n    profileId?: number;\n    rootFolder?: string;\n    tags?: string;\n    radarrServiceId?: number;\n    sonarrServiceId?: number;\n  }\n>('/', isAuthenticated(Permission.ADMIN), async (req, res, next) => {\n  const overrideRuleRepository = getRepository(OverrideRule);\n\n  try {\n    const rule = new OverrideRule({\n      users: req.body.users,\n      genre: req.body.genre,\n      language: req.body.language,\n      keywords: req.body.keywords,\n      profileId: req.body.profileId,\n      rootFolder: req.body.rootFolder,\n      tags: req.body.tags,\n      radarrServiceId: req.body.radarrServiceId,\n      sonarrServiceId: req.body.sonarrServiceId,\n    });\n\n    const newRule = await overrideRuleRepository.save(rule);\n\n    return res.status(200).json(newRule);\n  } catch (e) {\n    next({ status: 404, message: e.message });\n  }\n});\n\noverrideRuleRoutes.put<\n  { ruleId: string },\n  OverrideRule,\n  {\n    users?: string;\n    genre?: string;\n    language?: string;\n    keywords?: string;\n    profileId?: number;\n    rootFolder?: string;\n    tags?: string;\n    radarrServiceId?: number;\n    sonarrServiceId?: number;\n  }\n>('/:ruleId', isAuthenticated(Permission.ADMIN), async (req, res, next) => {\n  const overrideRuleRepository = getRepository(OverrideRule);\n\n  try {\n    const rule = await overrideRuleRepository.findOne({\n      where: {\n        id: Number(req.params.ruleId),\n      },\n    });\n\n    if (!rule) {\n      return next({ status: 404, message: 'Override Rule not found.' });\n    }\n\n    rule.users = req.body.users;\n    rule.genre = req.body.genre;\n    rule.language = req.body.language;\n    rule.keywords = req.body.keywords;\n    rule.profileId = req.body.profileId;\n    rule.rootFolder = req.body.rootFolder;\n    rule.tags = req.body.tags;\n    rule.radarrServiceId = req.body.radarrServiceId;\n    rule.sonarrServiceId = req.body.sonarrServiceId;\n\n    const newRule = await overrideRuleRepository.save(rule);\n\n    return res.status(200).json(newRule);\n  } catch (e) {\n    next({ status: 404, message: e.message });\n  }\n});\n\noverrideRuleRoutes.delete<{ ruleId: string }, OverrideRule>(\n  '/:ruleId',\n  isAuthenticated(Permission.ADMIN),\n  async (req, res, next) => {\n    const overrideRuleRepository = getRepository(OverrideRule);\n\n    try {\n      const rule = await overrideRuleRepository.findOne({\n        where: {\n          id: Number(req.params.ruleId),\n        },\n      });\n\n      if (!rule) {\n        return next({ status: 404, message: 'Override Rule not found.' });\n      }\n\n      await overrideRuleRepository.remove(rule);\n\n      return res.status(200).json(rule);\n    } catch (e) {\n      next({ status: 404, message: e.message });\n    }\n  }\n);\n\nexport default overrideRuleRoutes;\n"
  },
  {
    "path": "server/routes/person.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport Media from '@server/entity/Media';\nimport logger from '@server/logger';\nimport {\n  mapCastCredits,\n  mapCrewCredits,\n  mapPersonDetails,\n} from '@server/models/Person';\nimport { Router } from 'express';\n\nconst personRoutes = Router();\n\npersonRoutes.get('/:id', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const person = await tmdb.getPerson({\n      personId: Number(req.params.id),\n      language: (req.query.language as string) ?? req.locale,\n    });\n    return res.status(200).json(mapPersonDetails(person));\n  } catch (e) {\n    logger.debug('Something went wrong retrieving person', {\n      label: 'API',\n      errorMessage: e.message,\n      personId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve person.',\n    });\n  }\n});\n\npersonRoutes.get('/:id/combined_credits', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const combinedCredits = await tmdb.getPersonCombinedCredits({\n      personId: Number(req.params.id),\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    const castMedia = await Media.getRelatedMedia(\n      req.user,\n      combinedCredits.cast\n        .filter((result) => result.media_type)\n        .map((result) => ({\n          tmdbId: result.id,\n          mediaType: result.media_type!,\n        }))\n    );\n\n    const crewMedia = await Media.getRelatedMedia(\n      req.user,\n      combinedCredits.crew\n        .filter((result) => result.media_type)\n        .map((result) => ({\n          tmdbId: result.id,\n          mediaType: result.media_type!,\n        }))\n    );\n\n    return res.status(200).json({\n      cast: combinedCredits.cast\n        .map((result) =>\n          mapCastCredits(\n            result,\n            castMedia.find(\n              (med) =>\n                med.tmdbId === result.id && med.mediaType === result.media_type\n            )\n          )\n        )\n        .filter((item) => !item.adult),\n      crew: combinedCredits.crew\n        .map((result) =>\n          mapCrewCredits(\n            result,\n            crewMedia.find(\n              (med) =>\n                med.tmdbId === result.id && med.mediaType === result.media_type\n            )\n          )\n        )\n        .filter((item) => !item.adult),\n      id: combinedCredits.id,\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving combined credits', {\n      label: 'API',\n      errorMessage: e.message,\n      personId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve combined credits.',\n    });\n  }\n});\n\nexport default personRoutes;\n"
  },
  {
    "path": "server/routes/request.ts",
    "content": "import RadarrAPI from '@server/api/servarr/radarr';\nimport SonarrAPI from '@server/api/servarr/sonarr';\nimport {\n  MediaRequestStatus,\n  MediaStatus,\n  MediaType,\n} from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport {\n  BlocklistedMediaError,\n  DuplicateMediaRequestError,\n  MediaRequest,\n  NoSeasonsAvailableError,\n  QuotaRestrictedError,\n  RequestPermissionError,\n} from '@server/entity/MediaRequest';\nimport SeasonRequest from '@server/entity/SeasonRequest';\nimport { User } from '@server/entity/User';\nimport type {\n  MediaRequestBody,\n  RequestResultsResponse,\n} from '@server/interfaces/api/requestInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport { Router } from 'express';\n\nconst requestRoutes = Router();\n\nrequestRoutes.get<Record<string, unknown>, RequestResultsResponse>(\n  '/',\n  async (req, res, next) => {\n    try {\n      const pageSize = req.query.take ? Number(req.query.take) : 10;\n      const skip = req.query.skip ? Number(req.query.skip) : 0;\n      const requestedBy = req.query.requestedBy\n        ? Number(req.query.requestedBy)\n        : null;\n      const mediaType = (req.query.mediaType as MediaType | 'all') || 'all';\n\n      let statusFilter: MediaRequestStatus[];\n\n      switch (req.query.filter) {\n        case 'approved':\n        case 'processing':\n          statusFilter = [MediaRequestStatus.APPROVED];\n          break;\n        case 'pending':\n          statusFilter = [MediaRequestStatus.PENDING];\n          break;\n        case 'unavailable':\n          statusFilter = [\n            MediaRequestStatus.PENDING,\n            MediaRequestStatus.APPROVED,\n          ];\n          break;\n        case 'failed':\n          statusFilter = [MediaRequestStatus.FAILED];\n          break;\n        case 'completed':\n        case 'available':\n        case 'deleted':\n          statusFilter = [MediaRequestStatus.COMPLETED];\n          break;\n        default:\n          statusFilter = [\n            MediaRequestStatus.PENDING,\n            MediaRequestStatus.APPROVED,\n            MediaRequestStatus.DECLINED,\n            MediaRequestStatus.FAILED,\n            MediaRequestStatus.COMPLETED,\n          ];\n      }\n\n      let mediaStatusFilter: MediaStatus[];\n\n      switch (req.query.filter) {\n        case 'available':\n          mediaStatusFilter = [MediaStatus.AVAILABLE];\n          break;\n        case 'processing':\n        case 'unavailable':\n          mediaStatusFilter = [\n            MediaStatus.UNKNOWN,\n            MediaStatus.PENDING,\n            MediaStatus.PROCESSING,\n            MediaStatus.PARTIALLY_AVAILABLE,\n          ];\n          break;\n        case 'deleted':\n          mediaStatusFilter = [MediaStatus.DELETED];\n          break;\n        default:\n          mediaStatusFilter = [\n            MediaStatus.UNKNOWN,\n            MediaStatus.PENDING,\n            MediaStatus.PROCESSING,\n            MediaStatus.PARTIALLY_AVAILABLE,\n            MediaStatus.AVAILABLE,\n            MediaStatus.DELETED,\n          ];\n      }\n\n      let sortFilter: string;\n      let sortDirection: 'ASC' | 'DESC';\n\n      switch (req.query.sort) {\n        case 'modified':\n          sortFilter = 'request.updatedAt';\n          break;\n        default:\n          sortFilter = 'request.id';\n      }\n\n      switch (req.query.sortDirection) {\n        case 'asc':\n          sortDirection = 'ASC';\n          break;\n        default:\n          sortDirection = 'DESC';\n      }\n\n      let query = getRepository(MediaRequest)\n        .createQueryBuilder('request')\n        .leftJoinAndSelect('request.media', 'media')\n        .leftJoinAndSelect('request.seasons', 'seasons')\n        .leftJoinAndSelect('request.modifiedBy', 'modifiedBy')\n        .leftJoinAndSelect('request.requestedBy', 'requestedBy')\n        .where('request.status IN (:...requestStatus)', {\n          requestStatus: statusFilter,\n        })\n        .andWhere(\n          '((request.is4k = false AND media.status IN (:...mediaStatus)) OR (request.is4k = true AND media.status4k IN (:...mediaStatus)))',\n          {\n            mediaStatus: mediaStatusFilter,\n          }\n        );\n\n      if (\n        !req.user?.hasPermission(\n          [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n          { type: 'or' }\n        )\n      ) {\n        if (requestedBy && requestedBy !== req.user?.id) {\n          return next({\n            status: 403,\n            message: \"You do not have permission to view this user's requests.\",\n          });\n        }\n\n        query = query.andWhere('requestedBy.id = :id', {\n          id: req.user?.id,\n        });\n      } else if (requestedBy) {\n        query = query.andWhere('requestedBy.id = :id', {\n          id: requestedBy,\n        });\n      }\n\n      switch (mediaType) {\n        case 'all':\n          break;\n        case 'movie':\n          query = query.andWhere('request.type = :type', {\n            type: MediaType.MOVIE,\n          });\n          break;\n        case 'tv':\n          query = query.andWhere('request.type = :type', {\n            type: MediaType.TV,\n          });\n          break;\n      }\n\n      const [requests, requestCount] = await query\n        .orderBy(sortFilter, sortDirection)\n        .take(pageSize)\n        .skip(skip)\n        .getManyAndCount();\n\n      const settings = getSettings();\n\n      // get all quality profiles for every configured sonarr server\n      const sonarrServers = await Promise.all(\n        settings.sonarr.map(async (sonarrSetting) => {\n          const sonarr = new SonarrAPI({\n            apiKey: sonarrSetting.apiKey,\n            url: SonarrAPI.buildUrl(sonarrSetting, '/api/v3'),\n          });\n\n          return {\n            id: sonarrSetting.id,\n            profiles: await sonarr.getProfiles().catch(() => undefined),\n          };\n        })\n      );\n\n      // get all quality profiles for every configured radarr server\n      const radarrServers = await Promise.all(\n        settings.radarr.map(async (radarrSetting) => {\n          const radarr = new RadarrAPI({\n            apiKey: radarrSetting.apiKey,\n            url: RadarrAPI.buildUrl(radarrSetting, '/api/v3'),\n          });\n\n          return {\n            id: radarrSetting.id,\n            profiles: await radarr.getProfiles().catch(() => undefined),\n          };\n        })\n      );\n\n      // add profile names to the media requests, with undefined if not found\n      let mappedRequests = requests.map((r) => {\n        switch (r.type) {\n          case MediaType.MOVIE: {\n            const profileName = radarrServers\n              .find((serverr) => serverr.id === r.serverId)\n              ?.profiles?.find((profile) => profile.id === r.profileId)?.name;\n\n            return {\n              ...r,\n              profileName,\n            };\n          }\n          case MediaType.TV: {\n            return {\n              ...r,\n              profileName: sonarrServers\n                .find((serverr) => serverr.id === r.serverId)\n                ?.profiles?.find((profile) => profile.id === r.profileId)?.name,\n            };\n          }\n        }\n      });\n\n      // add canRemove prop if user has permission\n      if (req.user?.hasPermission(Permission.MANAGE_REQUESTS)) {\n        mappedRequests = mappedRequests.map((r) => {\n          switch (r.type) {\n            case MediaType.MOVIE: {\n              return {\n                ...r,\n                // check if the radarr server for this request is configured\n                canRemove: radarrServers.some(\n                  (server) =>\n                    server.id ===\n                    (r.is4k ? r.media.serviceId4k : r.media.serviceId)\n                ),\n              };\n            }\n            case MediaType.TV: {\n              return {\n                ...r,\n                // check if the sonarr server for this request is configured\n                canRemove: sonarrServers.some(\n                  (server) =>\n                    server.id ===\n                    (r.is4k ? r.media.serviceId4k : r.media.serviceId)\n                ),\n              };\n            }\n          }\n        });\n      }\n\n      return res.status(200).json({\n        pageInfo: {\n          pages: Math.ceil(requestCount / pageSize),\n          pageSize,\n          results: requestCount,\n          page: Math.ceil(skip / pageSize) + 1,\n        },\n        results: mappedRequests,\n        serviceErrors: {\n          radarr: radarrServers\n            .filter((s) => !s.profiles)\n            .map((s) => ({\n              id: s.id,\n              name:\n                settings.radarr.find((r) => r.id === s.id)?.name ||\n                `Radarr ${s.id}`,\n            })),\n          sonarr: sonarrServers\n            .filter((s) => !s.profiles)\n            .map((s) => ({\n              id: s.id,\n              name:\n                settings.sonarr.find((r) => r.id === s.id)?.name ||\n                `Sonarr ${s.id}`,\n            })),\n        },\n      });\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nrequestRoutes.post<never, MediaRequest, MediaRequestBody>(\n  '/',\n  async (req, res, next) => {\n    try {\n      if (!req.user) {\n        return next({\n          status: 401,\n          message: 'You must be logged in to request media.',\n        });\n      }\n      const request = await MediaRequest.request(req.body, req.user);\n\n      return res.status(201).json(request);\n    } catch (error) {\n      if (!(error instanceof Error)) {\n        return;\n      }\n\n      switch (error.constructor) {\n        case RequestPermissionError:\n        case QuotaRestrictedError:\n          return next({ status: 403, message: error.message });\n        case DuplicateMediaRequestError:\n          return next({ status: 409, message: error.message });\n        case NoSeasonsAvailableError:\n          return next({ status: 202, message: error.message });\n        case BlocklistedMediaError:\n          return next({ status: 403, message: error.message });\n        default:\n          return next({ status: 500, message: error.message });\n      }\n    }\n  }\n);\n\nrequestRoutes.get('/count', async (_req, res, next) => {\n  const requestRepository = getRepository(MediaRequest);\n\n  try {\n    const query = requestRepository\n      .createQueryBuilder('request')\n      .innerJoinAndSelect('request.media', 'media');\n\n    const totalCount = await query.getCount();\n\n    const movieCount = await query\n      .where('request.type = :requestType', {\n        requestType: MediaType.MOVIE,\n      })\n      .getCount();\n\n    const tvCount = await query\n      .where('request.type = :requestType', {\n        requestType: MediaType.TV,\n      })\n      .getCount();\n\n    const pendingCount = await query\n      .where('request.status = :requestStatus', {\n        requestStatus: MediaRequestStatus.PENDING,\n      })\n      .getCount();\n\n    const approvedCount = await query\n      .where('request.status = :requestStatus', {\n        requestStatus: MediaRequestStatus.APPROVED,\n      })\n      .getCount();\n\n    const declinedCount = await query\n      .where('request.status = :requestStatus', {\n        requestStatus: MediaRequestStatus.DECLINED,\n      })\n      .getCount();\n\n    const processingCount = await query\n      .where('request.status = :requestStatus', {\n        requestStatus: MediaRequestStatus.APPROVED,\n      })\n      .andWhere(\n        '((request.is4k = false AND media.status != :availableStatus) OR (request.is4k = true AND media.status4k != :availableStatus))',\n        {\n          availableStatus: MediaStatus.AVAILABLE,\n        }\n      )\n      .getCount();\n\n    const availableCount = await query\n      .where('request.status = :requestStatus', {\n        requestStatus: MediaRequestStatus.APPROVED,\n      })\n      .andWhere(\n        '((request.is4k = false AND media.status = :availableStatus) OR (request.is4k = true AND media.status4k = :availableStatus))',\n        {\n          availableStatus: MediaStatus.AVAILABLE,\n        }\n      )\n      .getCount();\n\n    const completedCount = await query\n      .where('request.status = :requestStatus', {\n        requestStatus: MediaRequestStatus.COMPLETED,\n      })\n      .getCount();\n\n    return res.status(200).json({\n      total: totalCount,\n      movie: movieCount,\n      tv: tvCount,\n      pending: pendingCount,\n      approved: approvedCount,\n      declined: declinedCount,\n      processing: processingCount,\n      available: availableCount,\n      completed: completedCount,\n    });\n  } catch (e) {\n    logger.error('Something went wrong retrieving request counts', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    next({ status: 500, message: 'Unable to retrieve request counts.' });\n  }\n});\n\nrequestRoutes.get('/:requestId', async (req, res, next) => {\n  const requestRepository = getRepository(MediaRequest);\n\n  try {\n    const request = await requestRepository.findOneOrFail({\n      where: { id: Number(req.params.requestId) },\n      relations: { requestedBy: true, modifiedBy: true },\n    });\n\n    if (\n      request.requestedBy.id !== req.user?.id &&\n      !req.user?.hasPermission(\n        [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n        { type: 'or' }\n      )\n    ) {\n      return next({\n        status: 403,\n        message: 'You do not have permission to view this request.',\n      });\n    }\n\n    return res.status(200).json(request);\n  } catch (e) {\n    logger.debug('Failed to retrieve request.', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    next({ status: 404, message: 'Request not found.' });\n  }\n});\n\nrequestRoutes.put<{ requestId: string }>(\n  '/:requestId',\n  async (req, res, next) => {\n    const requestRepository = getRepository(MediaRequest);\n    const userRepository = getRepository(User);\n    try {\n      const request = await requestRepository.findOne({\n        where: {\n          id: Number(req.params.requestId),\n        },\n      });\n\n      if (!request) {\n        return next({ status: 404, message: 'Request not found.' });\n      }\n\n      if (\n        (request.requestedBy.id !== req.user?.id ||\n          (req.body.mediaType !== 'tv' &&\n            !req.user?.hasPermission(Permission.REQUEST_ADVANCED))) &&\n        !req.user?.hasPermission(Permission.MANAGE_REQUESTS)\n      ) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to modify this request.',\n        });\n      }\n\n      let requestUser = request.requestedBy;\n\n      if (\n        req.body.userId &&\n        req.body.userId !== request.requestedBy.id &&\n        !req.user?.hasPermission([\n          Permission.MANAGE_USERS,\n          Permission.MANAGE_REQUESTS,\n        ])\n      ) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to modify the request user.',\n        });\n      } else if (req.body.userId) {\n        requestUser = await userRepository.findOneOrFail({\n          where: { id: req.body.userId },\n        });\n      }\n\n      if (req.body.mediaType === MediaType.MOVIE) {\n        request.serverId = req.body.serverId;\n        request.profileId = req.body.profileId;\n        request.rootFolder = req.body.rootFolder;\n        request.tags = req.body.tags;\n        request.requestedBy = requestUser as User;\n\n        requestRepository.save(request);\n      } else if (req.body.mediaType === MediaType.TV) {\n        const mediaRepository = getRepository(Media);\n        request.serverId = req.body.serverId;\n        request.profileId = req.body.profileId;\n        request.rootFolder = req.body.rootFolder;\n        request.languageProfileId = req.body.languageProfileId;\n        request.tags = req.body.tags;\n        request.requestedBy = requestUser as User;\n\n        const requestedSeasons = req.body.seasons as number[] | undefined;\n\n        if (!requestedSeasons || requestedSeasons.length === 0) {\n          throw new Error(\n            'Missing seasons. If you want to cancel a series request, use the DELETE method.'\n          );\n        }\n\n        // Get existing media so we can work with all the requests\n        const media = await mediaRepository.findOneOrFail({\n          where: { tmdbId: request.media.tmdbId, mediaType: MediaType.TV },\n          relations: { requests: true },\n        });\n\n        // Get all requested seasons that are not part of this request we are editing\n        const existingSeasons = media.requests\n          .filter(\n            (r) =>\n              r.is4k === request.is4k &&\n              r.id !== request.id &&\n              r.status !== MediaRequestStatus.DECLINED &&\n              r.status !== MediaRequestStatus.COMPLETED\n          )\n          .reduce((seasons, r) => {\n            const combinedSeasons = r.seasons.map(\n              (season) => season.seasonNumber\n            );\n\n            return [...seasons, ...combinedSeasons];\n          }, [] as number[]);\n\n        const filteredSeasons = requestedSeasons.filter(\n          (rs) => !existingSeasons.includes(rs)\n        );\n\n        if (filteredSeasons.length === 0) {\n          return next({\n            status: 202,\n            message: 'No seasons available to request',\n          });\n        }\n\n        const newSeasons = requestedSeasons.filter(\n          (sn) => !request.seasons.map((s) => s.seasonNumber).includes(sn)\n        );\n\n        request.seasons = request.seasons.filter((rs) =>\n          filteredSeasons.includes(rs.seasonNumber)\n        );\n\n        if (newSeasons.length > 0) {\n          logger.debug('Adding new seasons to request', {\n            label: 'Media Request',\n            newSeasons,\n          });\n          request.seasons.push(\n            ...newSeasons.map(\n              (ns) =>\n                new SeasonRequest({\n                  seasonNumber: ns,\n                  status: MediaRequestStatus.PENDING,\n                })\n            )\n          );\n        }\n\n        await requestRepository.save(request);\n      }\n\n      return res.status(200).json(request);\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nrequestRoutes.delete('/:requestId', async (req, res, next) => {\n  const requestRepository = getRepository(MediaRequest);\n\n  try {\n    const request = await requestRepository.findOneOrFail({\n      where: { id: Number(req.params.requestId) },\n      relations: { requestedBy: true, modifiedBy: true },\n    });\n\n    if (\n      !req.user?.hasPermission(Permission.MANAGE_REQUESTS) &&\n      request.requestedBy.id !== req.user?.id &&\n      request.status !== 1\n    ) {\n      return next({\n        status: 401,\n        message: 'You do not have permission to delete this request.',\n      });\n    }\n\n    await requestRepository.remove(request);\n\n    return res.status(204).send();\n  } catch (e) {\n    logger.error('Something went wrong deleting a request.', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    next({ status: 404, message: 'Request not found.' });\n  }\n});\n\nrequestRoutes.post<{\n  requestId: string;\n}>(\n  '/:requestId/retry',\n  isAuthenticated(Permission.MANAGE_REQUESTS),\n  async (req, res, next) => {\n    const requestRepository = getRepository(MediaRequest);\n\n    try {\n      const request = await requestRepository.findOneOrFail({\n        where: { id: Number(req.params.requestId) },\n        relations: { requestedBy: true, modifiedBy: true },\n      });\n\n      // this also triggers updating the parent media's status & sending to *arr\n      request.status = MediaRequestStatus.APPROVED;\n      await requestRepository.save(request);\n\n      return res.status(200).json(request);\n    } catch (e) {\n      logger.error('Error processing request retry', {\n        label: 'Media Request',\n        message: e.message,\n      });\n      next({ status: 404, message: 'Request not found.' });\n    }\n  }\n);\n\nrequestRoutes.post<{\n  requestId: string;\n  status: 'pending' | 'approve' | 'decline';\n}>(\n  '/:requestId/:status',\n  isAuthenticated(Permission.MANAGE_REQUESTS),\n  async (req, res, next) => {\n    const requestRepository = getRepository(MediaRequest);\n\n    try {\n      const request = await requestRepository.findOneOrFail({\n        where: { id: Number(req.params.requestId) },\n        relations: { requestedBy: true, modifiedBy: true },\n      });\n\n      let newStatus: MediaRequestStatus;\n\n      switch (req.params.status) {\n        case 'pending':\n          newStatus = MediaRequestStatus.PENDING;\n          break;\n        case 'approve':\n          newStatus = MediaRequestStatus.APPROVED;\n          break;\n        case 'decline':\n          newStatus = MediaRequestStatus.DECLINED;\n          break;\n      }\n\n      request.status = newStatus;\n      request.modifiedBy = req.user;\n      await requestRepository.save(request);\n\n      return res.status(200).json(request);\n    } catch (e) {\n      logger.error('Error processing request update', {\n        label: 'Media Request',\n        message: e.message,\n      });\n      next({ status: 404, message: 'Request not found.' });\n    }\n  }\n);\n\nexport default requestRoutes;\n"
  },
  {
    "path": "server/routes/search.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport type { TmdbSearchMultiResponse } from '@server/api/themoviedb/interfaces';\nimport Media from '@server/entity/Media';\nimport { findSearchProvider } from '@server/lib/search';\nimport logger from '@server/logger';\nimport { mapSearchResults } from '@server/models/Search';\nimport { Router } from 'express';\n\nconst searchRoutes = Router();\n\nsearchRoutes.get('/', async (req, res, next) => {\n  const queryString = req.query.query as string;\n  const searchProvider = findSearchProvider(queryString.toLowerCase());\n  let results: TmdbSearchMultiResponse;\n\n  try {\n    if (searchProvider) {\n      const [id] = queryString\n        .toLowerCase()\n        .match(searchProvider.pattern) as RegExpMatchArray;\n      results = await searchProvider.search({\n        id,\n        language: (req.query.language as string) ?? req.locale,\n        query: queryString,\n      });\n    } else {\n      const tmdb = new TheMovieDb();\n\n      results = await tmdb.searchMulti({\n        query: queryString,\n        page: Number(req.query.page),\n        language: (req.query.language as string) ?? req.locale,\n      });\n    }\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      results.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: result.media_type,\n      }))\n    );\n\n    return res.status(200).json({\n      page: results.page,\n      totalPages: results.total_pages,\n      totalResults: results.total_results,\n      results: mapSearchResults(results.results, media),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving search results', {\n      label: 'API',\n      errorMessage: e.message,\n      query: req.query.query,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve search results.',\n    });\n  }\n});\n\nsearchRoutes.get('/keyword', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const results = await tmdb.searchKeyword({\n      query: req.query.query as string,\n      page: Number(req.query.page),\n    });\n\n    return res.status(200).json(results);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving keyword search results', {\n      label: 'API',\n      errorMessage: e.message,\n      query: req.query.query,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve keyword search results.',\n    });\n  }\n});\n\nsearchRoutes.get('/company', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const results = await tmdb.searchCompany({\n      query: req.query.query as string,\n      page: Number(req.query.page),\n    });\n\n    return res.status(200).json(results);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving company search results', {\n      label: 'API',\n      errorMessage: e.message,\n      query: req.query.query,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve company search results.',\n    });\n  }\n});\n\nexport default searchRoutes;\n"
  },
  {
    "path": "server/routes/service.ts",
    "content": "import RadarrAPI from '@server/api/servarr/radarr';\nimport SonarrAPI from '@server/api/servarr/sonarr';\nimport TheMovieDb from '@server/api/themoviedb';\nimport type {\n  ServiceCommonServer,\n  ServiceCommonServerWithDetails,\n} from '@server/interfaces/api/serviceInterfaces';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { Router } from 'express';\n\nconst serviceRoutes = Router();\n\nserviceRoutes.get('/radarr', async (req, res) => {\n  const settings = getSettings();\n\n  const filteredRadarrServers: ServiceCommonServer[] = settings.radarr.map(\n    (radarr) => ({\n      id: radarr.id,\n      name: radarr.name,\n      is4k: radarr.is4k,\n      isDefault: radarr.isDefault,\n      activeDirectory: radarr.activeDirectory,\n      activeProfileId: radarr.activeProfileId,\n      activeTags: radarr.tags ?? [],\n    })\n  );\n\n  return res.status(200).json(filteredRadarrServers);\n});\n\nserviceRoutes.get<{ radarrId: string }>(\n  '/radarr/:radarrId',\n  async (req, res, next) => {\n    const settings = getSettings();\n\n    const radarrSettings = settings.radarr.find(\n      (radarr) => radarr.id === Number(req.params.radarrId)\n    );\n\n    if (!radarrSettings) {\n      return next({\n        status: 404,\n        message: 'Radarr server with provided ID  does not exist.',\n      });\n    }\n\n    const radarr = new RadarrAPI({\n      apiKey: radarrSettings.apiKey,\n      url: RadarrAPI.buildUrl(radarrSettings, '/api/v3'),\n    });\n\n    const profiles = await radarr.getProfiles();\n    const rootFolders = await radarr.getRootFolders();\n    const tags = await radarr.getTags();\n\n    return res.status(200).json({\n      server: {\n        id: radarrSettings.id,\n        name: radarrSettings.name,\n        is4k: radarrSettings.is4k,\n        isDefault: radarrSettings.isDefault,\n        activeDirectory: radarrSettings.activeDirectory,\n        activeProfileId: radarrSettings.activeProfileId,\n        activeTags: radarrSettings.tags,\n      },\n      profiles: profiles.map((profile) => ({\n        id: profile.id,\n        name: profile.name,\n      })),\n      rootFolders: rootFolders.map((folder) => ({\n        id: folder.id,\n        freeSpace: folder.freeSpace,\n        path: folder.path,\n        totalSpace: folder.totalSpace,\n      })),\n      tags,\n    } as ServiceCommonServerWithDetails);\n  }\n);\n\nserviceRoutes.get('/sonarr', async (req, res) => {\n  const settings = getSettings();\n\n  const filteredSonarrServers: ServiceCommonServer[] = settings.sonarr.map(\n    (sonarr) => ({\n      id: sonarr.id,\n      name: sonarr.name,\n      is4k: sonarr.is4k,\n      isDefault: sonarr.isDefault,\n      activeDirectory: sonarr.activeDirectory,\n      activeProfileId: sonarr.activeProfileId,\n      activeAnimeProfileId: sonarr.activeAnimeProfileId,\n      activeAnimeDirectory: sonarr.activeAnimeDirectory,\n      activeLanguageProfileId: sonarr.activeLanguageProfileId,\n      activeAnimeLanguageProfileId: sonarr.activeAnimeLanguageProfileId,\n      activeTags: [],\n    })\n  );\n\n  return res.status(200).json(filteredSonarrServers);\n});\n\nserviceRoutes.get<{ sonarrId: string }>(\n  '/sonarr/:sonarrId',\n  async (req, res, next) => {\n    const settings = getSettings();\n\n    const sonarrSettings = settings.sonarr.find(\n      (sonarr) => sonarr.id === Number(req.params.sonarrId)\n    );\n\n    if (!sonarrSettings) {\n      return next({\n        status: 404,\n        message: 'Sonarr server with provided ID does not exist.',\n      });\n    }\n\n    const sonarr = new SonarrAPI({\n      apiKey: sonarrSettings.apiKey,\n      url: SonarrAPI.buildUrl(sonarrSettings, '/api/v3'),\n    });\n\n    try {\n      const systemStatus = await sonarr.getSystemStatus();\n      const sonarrMajorVersion = Number(systemStatus.version.split('.')[0]);\n\n      const profiles = await sonarr.getProfiles();\n      const rootFolders = await sonarr.getRootFolders();\n      const languageProfiles =\n        sonarrMajorVersion <= 3 ? await sonarr.getLanguageProfiles() : null;\n      const tags = await sonarr.getTags();\n\n      return res.status(200).json({\n        server: {\n          id: sonarrSettings.id,\n          name: sonarrSettings.name,\n          is4k: sonarrSettings.is4k,\n          isDefault: sonarrSettings.isDefault,\n          activeDirectory: sonarrSettings.activeDirectory,\n          activeProfileId: sonarrSettings.activeProfileId,\n          activeAnimeProfileId: sonarrSettings.activeAnimeProfileId,\n          activeAnimeDirectory: sonarrSettings.activeAnimeDirectory,\n          activeLanguageProfileId: sonarrSettings.activeLanguageProfileId,\n          activeAnimeLanguageProfileId:\n            sonarrSettings.activeAnimeLanguageProfileId,\n          activeTags: sonarrSettings.tags,\n          activeAnimeTags: sonarrSettings.animeTags,\n        },\n        profiles: profiles.map((profile) => ({\n          id: profile.id,\n          name: profile.name,\n        })),\n        rootFolders: rootFolders.map((folder) => ({\n          id: folder.id,\n          freeSpace: folder.freeSpace,\n          path: folder.path,\n          totalSpace: folder.totalSpace,\n        })),\n        languageProfiles: languageProfiles,\n        tags,\n      } as ServiceCommonServerWithDetails);\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nserviceRoutes.get<{ tmdbId: string }>(\n  '/sonarr/lookup/:tmdbId',\n  async (req, res, next) => {\n    const settings = getSettings();\n    const tmdb = new TheMovieDb();\n\n    const sonarrSettings = settings.sonarr[0];\n\n    if (!sonarrSettings) {\n      logger.error('No sonarr server has been setup', {\n        label: 'Media Request',\n      });\n      return next({\n        status: 404,\n        message: 'No sonarr server has been setup',\n      });\n    }\n\n    const sonarr = new SonarrAPI({\n      apiKey: sonarrSettings.apiKey,\n      url: SonarrAPI.buildUrl(sonarrSettings, '/api/v3'),\n    });\n\n    try {\n      const tv = await tmdb.getTvShow({\n        tvId: Number(req.params.tmdbId),\n        language: 'en',\n      });\n\n      const response = await sonarr.getSeriesByTitle(tv.name);\n\n      return res.status(200).json(response);\n    } catch (e) {\n      logger.error('Failed to fetch tvdb search results', {\n        label: 'Media Request',\n        message: e.message,\n      });\n\n      return next({\n        status: 500,\n        message: 'Something went wrong trying to fetch series information',\n      });\n    }\n  }\n);\n\nexport default serviceRoutes;\n"
  },
  {
    "path": "server/routes/settings/discover.ts",
    "content": "import { getRepository } from '@server/datasource';\nimport DiscoverSlider from '@server/entity/DiscoverSlider';\nimport logger from '@server/logger';\nimport { Router } from 'express';\n\nconst discoverSettingRoutes = Router();\n\ndiscoverSettingRoutes.post('/', async (req, res) => {\n  const sliderRepository = getRepository(DiscoverSlider);\n\n  const sliders = req.body as DiscoverSlider[];\n\n  if (!Array.isArray(sliders)) {\n    return res.status(400).json({ message: 'Invalid request body.' });\n  }\n\n  for (let x = 0; x < sliders.length; x++) {\n    const slider = sliders[x];\n    const existingSlider = await sliderRepository.findOne({\n      where: {\n        id: slider.id,\n      },\n    });\n\n    if (existingSlider && slider.id) {\n      existingSlider.enabled = slider.enabled;\n      existingSlider.order = x;\n\n      // Only allow changes to the following when the slider is not built in\n      if (!existingSlider.isBuiltIn) {\n        existingSlider.title = slider.title;\n        existingSlider.data = slider.data;\n        existingSlider.type = slider.type;\n      }\n\n      await sliderRepository.save(existingSlider);\n    } else {\n      const newSlider = new DiscoverSlider({\n        isBuiltIn: false,\n        data: slider.data,\n        title: slider.title,\n        enabled: slider.enabled,\n        order: x,\n        type: slider.type,\n      });\n      await sliderRepository.save(newSlider);\n    }\n  }\n\n  return res.json(sliders);\n});\n\ndiscoverSettingRoutes.post('/add', async (req, res) => {\n  const sliderRepository = getRepository(DiscoverSlider);\n\n  const slider = req.body as DiscoverSlider;\n\n  const newSlider = new DiscoverSlider({\n    isBuiltIn: false,\n    data: slider.data,\n    title: slider.title,\n    enabled: false,\n    order: -1,\n    type: slider.type,\n  });\n  await sliderRepository.save(newSlider);\n\n  return res.json(newSlider);\n});\n\ndiscoverSettingRoutes.get('/reset', async (_req, res) => {\n  const sliderRepository = getRepository(DiscoverSlider);\n\n  await sliderRepository.clear();\n  await DiscoverSlider.bootstrapSliders();\n\n  return res.status(204).send();\n});\n\ndiscoverSettingRoutes.put('/:sliderId', async (req, res, next) => {\n  const sliderRepository = getRepository(DiscoverSlider);\n\n  const slider = req.body as DiscoverSlider;\n\n  try {\n    const existingSlider = await sliderRepository.findOneOrFail({\n      where: {\n        id: Number(req.params.sliderId),\n      },\n    });\n\n    // Only allow changes to the following when the slider is not built in\n    if (!existingSlider.isBuiltIn) {\n      existingSlider.title = slider.title;\n      existingSlider.data = slider.data;\n      existingSlider.type = slider.type;\n    }\n\n    await sliderRepository.save(existingSlider);\n\n    return res.status(200).json(existingSlider);\n  } catch (e) {\n    logger.error('Something went wrong updating a slider.', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    next({ status: 404, message: 'Slider not found or cannot be updated.' });\n  }\n});\n\ndiscoverSettingRoutes.delete('/:sliderId', async (req, res, next) => {\n  const sliderRepository = getRepository(DiscoverSlider);\n\n  try {\n    const slider = await sliderRepository.findOneOrFail({\n      where: { id: Number(req.params.sliderId), isBuiltIn: false },\n    });\n\n    await sliderRepository.remove(slider);\n\n    return res.status(204).send();\n  } catch (e) {\n    logger.error('Something went wrong deleting a slider.', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    next({ status: 404, message: 'Slider not found or cannot be deleted.' });\n  }\n});\n\nexport default discoverSettingRoutes;\n"
  },
  {
    "path": "server/routes/settings/index.ts",
    "content": "import JellyfinAPI from '@server/api/jellyfin';\nimport PlexAPI from '@server/api/plexapi';\nimport PlexTvAPI from '@server/api/plextv';\nimport TautulliAPI from '@server/api/tautulli';\nimport { ApiErrorCode } from '@server/constants/error';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport { MediaRequest } from '@server/entity/MediaRequest';\nimport { User } from '@server/entity/User';\nimport type { PlexConnection } from '@server/interfaces/api/plexInterfaces';\nimport type {\n  LogMessage,\n  LogsResultsResponse,\n  SettingsAboutResponse,\n} from '@server/interfaces/api/settingsInterfaces';\nimport { scheduledJobs } from '@server/job/schedule';\nimport type { AvailableCacheIds } from '@server/lib/cache';\nimport cacheManager from '@server/lib/cache';\nimport ImageProxy from '@server/lib/imageproxy';\nimport { Permission } from '@server/lib/permissions';\nimport { jellyfinFullScanner } from '@server/lib/scanners/jellyfin';\nimport { plexFullScanner } from '@server/lib/scanners/plex';\nimport type { JobId, Library, MainSettings } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport discoverSettingRoutes from '@server/routes/settings/discover';\nimport { ApiError } from '@server/types/error';\nimport { appDataPath } from '@server/utils/appDataVolume';\nimport { getAppVersion } from '@server/utils/appVersion';\nimport { dnsCache } from '@server/utils/dnsCache';\nimport { getHostname } from '@server/utils/getHostname';\nimport type { DnsEntries, DnsStats } from 'dns-caching';\nimport { Router } from 'express';\nimport rateLimit from 'express-rate-limit';\nimport fs from 'fs';\nimport { escapeRegExp, merge, omit, set, sortBy } from 'lodash';\nimport { rescheduleJob } from 'node-schedule';\nimport path from 'path';\nimport semver from 'semver';\nimport { URL } from 'url';\nimport metadataRoutes from './metadata';\nimport notificationRoutes from './notifications';\nimport radarrRoutes from './radarr';\nimport sonarrRoutes from './sonarr';\n\nconst settingsRoutes = Router();\n\nsettingsRoutes.use('/notifications', notificationRoutes);\nsettingsRoutes.use('/radarr', radarrRoutes);\nsettingsRoutes.use('/sonarr', sonarrRoutes);\nsettingsRoutes.use('/discover', discoverSettingRoutes);\nsettingsRoutes.use('/metadatas', metadataRoutes);\n\nconst filteredMainSettings = (\n  user: User,\n  main: MainSettings\n): Partial<MainSettings> => {\n  if (!user?.hasPermission(Permission.ADMIN)) {\n    return omit(main, 'apiKey');\n  }\n\n  return main;\n};\n\nsettingsRoutes.get('/main', (req, res, next) => {\n  const settings = getSettings();\n\n  if (!req.user) {\n    return next({ status: 400, message: 'User missing from request.' });\n  }\n\n  res.status(200).json(filteredMainSettings(req.user, settings.main));\n});\n\nsettingsRoutes.post('/main', async (req, res) => {\n  const settings = getSettings();\n\n  settings.main = merge(settings.main, req.body);\n  await settings.save();\n\n  return res.status(200).json(settings.main);\n});\n\nsettingsRoutes.get('/network', (req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.network);\n});\n\nsettingsRoutes.post('/network', async (req, res) => {\n  const settings = getSettings();\n\n  settings.network = merge(settings.network, req.body);\n  await settings.save();\n\n  return res.status(200).json(settings.network);\n});\n\nsettingsRoutes.post('/main/regenerate', async (req, res, next) => {\n  const settings = getSettings();\n\n  const main = await settings.regenerateApiKey();\n\n  if (!req.user) {\n    return next({ status: 500, message: 'User missing from request.' });\n  }\n\n  return res.status(200).json(filteredMainSettings(req.user, main));\n});\n\nsettingsRoutes.get('/plex', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.plex);\n});\n\nsettingsRoutes.post('/plex', async (req, res, next) => {\n  const userRepository = getRepository(User);\n  const settings = getSettings();\n  try {\n    const admin = await userRepository.findOneOrFail({\n      select: { id: true, plexToken: true },\n      where: { id: 1 },\n    });\n\n    Object.assign(settings.plex, req.body);\n\n    const plexClient = new PlexAPI({ plexToken: admin.plexToken });\n\n    const result = await plexClient.getStatus();\n\n    if (!result?.MediaContainer?.machineIdentifier) {\n      throw new Error('Server not found');\n    }\n\n    settings.plex.machineId = result.MediaContainer.machineIdentifier;\n    settings.plex.name = result.MediaContainer.friendlyName;\n\n    await settings.save();\n  } catch (e) {\n    logger.error('Something went wrong testing Plex connection', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to connect to Plex.',\n    });\n  }\n\n  return res.status(200).json(settings.plex);\n});\n\nsettingsRoutes.get('/plex/devices/servers', async (req, res, next) => {\n  const userRepository = getRepository(User);\n  try {\n    const admin = await userRepository.findOneOrFail({\n      select: { id: true, plexToken: true },\n      where: { id: 1 },\n    });\n    const plexTvClient = admin.plexToken\n      ? new PlexTvAPI(admin.plexToken)\n      : null;\n    const devices = (await plexTvClient?.getDevices())?.filter((device) => {\n      return device.provides.includes('server') && device.owned;\n    });\n    const settings = getSettings();\n\n    if (devices) {\n      await Promise.all(\n        devices.map(async (device) => {\n          const plexDirectConnections: PlexConnection[] = [];\n\n          device.connection.forEach((connection) => {\n            const url = new URL(connection.uri);\n\n            if (url.hostname !== connection.address) {\n              const plexDirectConnection = { ...connection };\n              plexDirectConnection.address = url.hostname;\n              plexDirectConnections.push(plexDirectConnection);\n\n              // Connect to IP addresses over HTTP\n              connection.protocol = 'http';\n            }\n          });\n\n          plexDirectConnections.forEach((plexDirectConnection) => {\n            device.connection.push(plexDirectConnection);\n          });\n\n          await Promise.all(\n            device.connection.map(async (connection) => {\n              const plexDeviceSettings = {\n                ...settings.plex,\n                ip: connection.address,\n                port: connection.port,\n                useSsl: connection.protocol === 'https',\n              };\n              const plexClient = new PlexAPI({\n                plexToken: admin.plexToken,\n                plexSettings: plexDeviceSettings,\n                timeout: 5000,\n              });\n\n              try {\n                await plexClient.getStatus();\n                connection.status = 200;\n                connection.message = 'OK';\n              } catch (e) {\n                connection.status = 500;\n                connection.message = e.message.split(':')[0];\n              }\n            })\n          );\n        })\n      );\n    }\n    return res.status(200).json(devices);\n  } catch (e) {\n    logger.error('Something went wrong retrieving Plex server list', {\n      label: 'API',\n      errorMessage: e.message,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve Plex server list.',\n    });\n  }\n});\n\nsettingsRoutes.get('/plex/library', async (req, res) => {\n  const settings = getSettings();\n\n  if (req.query.sync) {\n    const userRepository = getRepository(User);\n    const admin = await userRepository.findOneOrFail({\n      select: { id: true, plexToken: true },\n      where: { id: 1 },\n    });\n    const plexapi = new PlexAPI({ plexToken: admin.plexToken });\n\n    await plexapi.syncLibraries();\n  }\n\n  const enabledLibraries = req.query.enable\n    ? (req.query.enable as string).split(',')\n    : [];\n  settings.plex.libraries = settings.plex.libraries.map((library) => ({\n    ...library,\n    enabled: enabledLibraries.includes(library.id),\n  }));\n  await settings.save();\n  return res.status(200).json(settings.plex.libraries);\n});\n\nsettingsRoutes.get('/plex/sync', (_req, res) => {\n  return res.status(200).json(plexFullScanner.status());\n});\n\nsettingsRoutes.post('/plex/sync', (req, res) => {\n  if (req.body.cancel) {\n    plexFullScanner.cancel();\n  } else if (req.body.start) {\n    plexFullScanner.run();\n  }\n  return res.status(200).json(plexFullScanner.status());\n});\n\nsettingsRoutes.get('/jellyfin', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.jellyfin);\n});\n\nsettingsRoutes.post('/jellyfin', async (req, res, next) => {\n  const userRepository = getRepository(User);\n  const settings = getSettings();\n\n  try {\n    const admin = await userRepository.findOneOrFail({\n      where: { id: 1 },\n      select: ['id', 'jellyfinUserId', 'jellyfinDeviceId'],\n      order: { id: 'ASC' },\n    });\n\n    const tempJellyfinSettings = { ...settings.jellyfin, ...req.body };\n\n    const jellyfinClient = new JellyfinAPI(\n      getHostname(tempJellyfinSettings),\n      tempJellyfinSettings.apiKey,\n      admin.jellyfinDeviceId ?? ''\n    );\n\n    const result = await jellyfinClient.getSystemInfo();\n\n    if (!result?.Id) {\n      throw new ApiError(result?.status, ApiErrorCode.InvalidUrl);\n    }\n\n    Object.assign(settings.jellyfin, req.body);\n    settings.jellyfin.serverId = result.Id;\n    settings.jellyfin.name = result.ServerName;\n    await settings.save();\n  } catch (e) {\n    if (e instanceof ApiError) {\n      logger.error('Something went wrong testing Jellyfin connection', {\n        label: 'API',\n        status: e.statusCode,\n        errorMessage: ApiErrorCode.InvalidUrl,\n      });\n\n      return next({\n        status: e.statusCode,\n        message: ApiErrorCode.InvalidUrl,\n      });\n    } else {\n      logger.error('Something went wrong', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n\n      return next({\n        status: e.statusCode ?? 500,\n        message: ApiErrorCode.Unknown,\n      });\n    }\n  }\n\n  return res.status(200).json(settings.jellyfin);\n});\n\nsettingsRoutes.get('/jellyfin/library', async (req, res, next) => {\n  const settings = getSettings();\n\n  if (req.query.sync) {\n    const userRepository = getRepository(User);\n    const admin = await userRepository.findOneOrFail({\n      select: ['id', 'jellyfinDeviceId', 'jellyfinUserId'],\n      where: { id: 1 },\n      order: { id: 'ASC' },\n    });\n    const jellyfinClient = new JellyfinAPI(\n      getHostname(),\n      settings.jellyfin.apiKey,\n      admin.jellyfinDeviceId ?? ''\n    );\n\n    jellyfinClient.setUserId(admin.jellyfinUserId ?? '');\n\n    const libraries = await jellyfinClient.getLibraries();\n\n    if (libraries.length === 0) {\n      // Check if no libraries are found due to the fallback to user views\n      // This only affects LDAP users\n      const account = await jellyfinClient.getUser();\n\n      // Automatic Library grouping is not supported when user views are used to get library\n      if (account.Configuration.GroupedFolders?.length > 0) {\n        return next({\n          status: 501,\n          message: ApiErrorCode.SyncErrorGroupedFolders,\n        });\n      }\n\n      return next({ status: 404, message: ApiErrorCode.SyncErrorNoLibraries });\n    }\n\n    const newLibraries: Library[] = libraries.map((library) => {\n      const existing = settings.jellyfin.libraries.find(\n        (l) => l.id === library.key && l.name === library.title\n      );\n\n      return {\n        id: library.key,\n        name: library.title,\n        enabled: existing?.enabled ?? false,\n        type: library.type,\n      };\n    });\n\n    settings.jellyfin.libraries = newLibraries;\n  }\n\n  const enabledLibraries = req.query.enable\n    ? (req.query.enable as string).split(',')\n    : [];\n  settings.jellyfin.libraries = settings.jellyfin.libraries.map((library) => ({\n    ...library,\n    enabled: enabledLibraries.includes(library.id),\n  }));\n  await settings.save();\n  return res.status(200).json(settings.jellyfin.libraries);\n});\n\nsettingsRoutes.get('/jellyfin/users', async (req, res) => {\n  const settings = getSettings();\n\n  const userRepository = getRepository(User);\n  const admin = await userRepository.findOneOrFail({\n    select: ['id', 'jellyfinDeviceId', 'jellyfinUserId'],\n    where: { id: 1 },\n    order: { id: 'ASC' },\n  });\n  const jellyfinClient = new JellyfinAPI(\n    getHostname(),\n    settings.jellyfin.apiKey,\n    admin.jellyfinDeviceId ?? ''\n  );\n\n  jellyfinClient.setUserId(admin.jellyfinUserId ?? '');\n  const resp = await jellyfinClient.getUsers();\n  const users = resp.users.map((user) => ({\n    username: user.Name,\n    id: user.Id,\n    thumb: `/avatarproxy/${user.Id}`,\n    email: user.Name,\n  }));\n\n  return res.status(200).json(users);\n});\n\nsettingsRoutes.get('/jellyfin/sync', (_req, res) => {\n  return res.status(200).json(jellyfinFullScanner.status());\n});\n\nsettingsRoutes.post('/jellyfin/sync', (req, res) => {\n  if (req.body.cancel) {\n    jellyfinFullScanner.cancel();\n  } else if (req.body.start) {\n    jellyfinFullScanner.run();\n  }\n  return res.status(200).json(jellyfinFullScanner.status());\n});\nsettingsRoutes.get('/tautulli', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.tautulli);\n});\n\nsettingsRoutes.post('/tautulli', async (req, res, next) => {\n  const settings = getSettings();\n\n  Object.assign(settings.tautulli, req.body);\n\n  if (settings.tautulli.hostname) {\n    try {\n      const tautulliClient = new TautulliAPI(settings.tautulli);\n\n      const result = await tautulliClient.getInfo();\n\n      if (!semver.gte(semver.coerce(result?.tautulli_version) ?? '', '2.9.0')) {\n        throw new Error('Tautulli version not supported');\n      }\n\n      await settings.save();\n    } catch (e) {\n      logger.error('Something went wrong testing Tautulli connection', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to connect to Tautulli.',\n      });\n    }\n  }\n\n  return res.status(200).json(settings.tautulli);\n});\n\nsettingsRoutes.get(\n  '/plex/users',\n  isAuthenticated(Permission.MANAGE_USERS),\n  async (req, res, next) => {\n    const userRepository = getRepository(User);\n    const qb = userRepository.createQueryBuilder('user');\n\n    try {\n      const admin = await userRepository.findOneOrFail({\n        select: { id: true, plexToken: true },\n        where: { id: 1 },\n      });\n      const plexApi = new PlexTvAPI(admin.plexToken ?? '');\n      const plexUsers = (await plexApi.getUsers()).MediaContainer.User.map(\n        (user) => user.$\n      ).filter((user) => user.email);\n\n      const unimportedPlexUsers: {\n        id: string;\n        title: string;\n        username: string;\n        email: string;\n        thumb: string;\n      }[] = [];\n\n      const plexIds = plexUsers.map((plexUser) => plexUser.id);\n      const plexEmails = plexUsers.map((plexUser) =>\n        plexUser.email.toLowerCase()\n      );\n      if (!plexIds.length) plexIds.push('-1');\n      if (!plexEmails.length) plexEmails.push('@');\n\n      const existingUsers = await qb\n        .where('user.plexId IN (:...plexIds)', { plexIds })\n        .orWhere('user.email IN (:...plexEmails)', { plexEmails })\n        .getMany();\n\n      await Promise.all(\n        plexUsers.map(async (plexUser) => {\n          if (\n            !existingUsers.find(\n              (user) =>\n                user.plexId === parseInt(plexUser.id) ||\n                user.email === plexUser.email.toLowerCase()\n            ) &&\n            (await plexApi.checkUserAccess(parseInt(plexUser.id)))\n          ) {\n            unimportedPlexUsers.push(plexUser);\n          }\n        })\n      );\n\n      return res.status(200).json(sortBy(unimportedPlexUsers, 'username'));\n    } catch (e) {\n      logger.error('Something went wrong getting unimported Plex users', {\n        label: 'API',\n        errorMessage: e.message,\n      });\n      next({\n        status: 500,\n        message: 'Unable to retrieve unimported Plex users.',\n      });\n    }\n  }\n);\n\nsettingsRoutes.get(\n  '/logs',\n  rateLimit({ windowMs: 60 * 1000, max: 50 }),\n  (req, res, next) => {\n    const pageSize = req.query.take ? Number(req.query.take) : 25;\n    const skip = req.query.skip ? Number(req.query.skip) : 0;\n    const search = (req.query.search as string) ?? '';\n    const searchRegexp = new RegExp(escapeRegExp(search), 'i');\n\n    let filter: string[] = [];\n    switch (req.query.filter) {\n      case 'debug':\n        filter.push('debug');\n      // falls through\n      case 'info':\n        filter.push('info');\n      // falls through\n      case 'warn':\n        filter.push('warn');\n      // falls through\n      case 'error':\n        filter.push('error');\n        break;\n      default:\n        filter = ['debug', 'info', 'warn', 'error'];\n    }\n\n    const logFile = process.env.CONFIG_DIRECTORY\n      ? `${process.env.CONFIG_DIRECTORY}/logs/.machinelogs.json`\n      : path.join(__dirname, '../../../config/logs/.machinelogs.json');\n    const logs: LogMessage[] = [];\n    const logMessageProperties = [\n      'timestamp',\n      'level',\n      'label',\n      'message',\n      'data',\n    ];\n\n    const deepValueStrings = (obj: Record<string, unknown>): string[] => {\n      const values = [];\n\n      for (const val of Object.values(obj)) {\n        if (typeof val === 'string') {\n          values.push(val);\n        } else if (typeof val === 'number') {\n          values.push(val.toString());\n        } else if (val !== null && typeof val === 'object') {\n          values.push(...deepValueStrings(val as Record<string, unknown>));\n        }\n      }\n\n      return values;\n    };\n\n    try {\n      fs.readFileSync(logFile, 'utf-8')\n        .split('\\n')\n        .forEach((line) => {\n          if (!line.length) return;\n\n          const logMessage = JSON.parse(line);\n\n          if (!filter.includes(logMessage.level)) {\n            return;\n          }\n\n          if (\n            !Object.keys(logMessage).every((key) =>\n              logMessageProperties.includes(key)\n            )\n          ) {\n            Object.keys(logMessage)\n              .filter((prop) => !logMessageProperties.includes(prop))\n              .forEach((prop) => {\n                set(logMessage, `data.${prop}`, logMessage[prop]);\n              });\n          }\n\n          if (req.query.search) {\n            if (\n              // label and data are sometimes undefined\n              !searchRegexp.test(logMessage.label ?? '') &&\n              !searchRegexp.test(logMessage.message) &&\n              !deepValueStrings(logMessage.data ?? {}).some((val) =>\n                searchRegexp.test(val)\n              )\n            ) {\n              return;\n            }\n          }\n\n          logs.push(logMessage);\n        });\n\n      const displayedLogs = logs.reverse().slice(skip, skip + pageSize);\n\n      return res.status(200).json({\n        pageInfo: {\n          pages: Math.ceil(logs.length / pageSize),\n          pageSize,\n          results: logs.length,\n          page: Math.ceil(skip / pageSize) + 1,\n        },\n        results: displayedLogs,\n      } as LogsResultsResponse);\n    } catch (error) {\n      logger.error('Something went wrong while retrieving logs', {\n        label: 'Logs',\n        errorMessage: error.message,\n      });\n      return next({\n        status: 500,\n        message: 'Unable to retrieve logs.',\n      });\n    }\n  }\n);\n\nsettingsRoutes.get('/jobs', (_req, res) => {\n  return res.status(200).json(\n    scheduledJobs.map((job) => ({\n      id: job.id,\n      name: job.name,\n      type: job.type,\n      interval: job.interval,\n      cronSchedule: job.cronSchedule,\n      nextExecutionTime: job.job.nextInvocation(),\n      running: job.running ? job.running() : false,\n    }))\n  );\n});\n\nsettingsRoutes.post<{ jobId: string }>('/jobs/:jobId/run', (req, res, next) => {\n  const scheduledJob = scheduledJobs.find((job) => job.id === req.params.jobId);\n\n  if (!scheduledJob) {\n    return next({ status: 404, message: 'Job not found.' });\n  }\n\n  scheduledJob.job.invoke();\n\n  return res.status(200).json({\n    id: scheduledJob.id,\n    name: scheduledJob.name,\n    type: scheduledJob.type,\n    interval: scheduledJob.interval,\n    cronSchedule: scheduledJob.cronSchedule,\n    nextExecutionTime: scheduledJob.job.nextInvocation(),\n    running: scheduledJob.running ? scheduledJob.running() : false,\n  });\n});\n\nsettingsRoutes.post<{ jobId: JobId }>(\n  '/jobs/:jobId/cancel',\n  (req, res, next) => {\n    const scheduledJob = scheduledJobs.find(\n      (job) => job.id === req.params.jobId\n    );\n\n    if (!scheduledJob) {\n      return next({ status: 404, message: 'Job not found.' });\n    }\n\n    if (scheduledJob.cancelFn) {\n      scheduledJob.cancelFn();\n    }\n\n    return res.status(200).json({\n      id: scheduledJob.id,\n      name: scheduledJob.name,\n      type: scheduledJob.type,\n      interval: scheduledJob.interval,\n      cronSchedule: scheduledJob.cronSchedule,\n      nextExecutionTime: scheduledJob.job.nextInvocation(),\n      running: scheduledJob.running ? scheduledJob.running() : false,\n    });\n  }\n);\n\nsettingsRoutes.post<{ jobId: JobId }>(\n  '/jobs/:jobId/schedule',\n  async (req, res, next) => {\n    const scheduledJob = scheduledJobs.find(\n      (job) => job.id === req.params.jobId\n    );\n\n    if (!scheduledJob) {\n      return next({ status: 404, message: 'Job not found.' });\n    }\n\n    const result = rescheduleJob(scheduledJob.job, req.body.schedule);\n    const settings = getSettings();\n\n    if (result) {\n      settings.jobs[scheduledJob.id].schedule = req.body.schedule;\n      await settings.save();\n\n      scheduledJob.cronSchedule = req.body.schedule;\n\n      return res.status(200).json({\n        id: scheduledJob.id,\n        name: scheduledJob.name,\n        type: scheduledJob.type,\n        interval: scheduledJob.interval,\n        cronSchedule: scheduledJob.cronSchedule,\n        nextExecutionTime: scheduledJob.job.nextInvocation(),\n        running: scheduledJob.running ? scheduledJob.running() : false,\n      });\n    } else {\n      return next({ status: 400, message: 'Invalid job schedule.' });\n    }\n  }\n);\n\nsettingsRoutes.get('/cache', async (_req, res) => {\n  const cacheManagerCaches = cacheManager.getAllCaches();\n\n  const apiCaches = Object.values(cacheManagerCaches).map((cache) => ({\n    id: cache.id,\n    name: cache.name,\n    stats: cache.getStats(),\n  }));\n\n  const tmdbImageCache = await ImageProxy.getImageStats('tmdb');\n  const avatarImageCache = await ImageProxy.getImageStats('avatar');\n\n  const stats: DnsStats | undefined = dnsCache?.getStats();\n  const entries: DnsEntries | undefined = dnsCache?.getCacheEntries();\n\n  return res.status(200).json({\n    apiCaches,\n    imageCache: {\n      tmdb: tmdbImageCache,\n      avatar: avatarImageCache,\n    },\n    dnsCache: {\n      stats,\n      entries,\n    },\n  });\n});\n\nsettingsRoutes.post<{ cacheId: AvailableCacheIds }>(\n  '/cache/:cacheId/flush',\n  (req, res, next) => {\n    const cache = cacheManager.getCache(req.params.cacheId);\n\n    if (cache) {\n      cache.flush();\n      return res.status(204).send();\n    }\n\n    next({ status: 404, message: 'Cache not found.' });\n  }\n);\n\nsettingsRoutes.post<{ dnsEntry: string }>(\n  '/cache/dns/:dnsEntry/flush',\n  (req, res, next) => {\n    const dnsEntry = req.params.dnsEntry;\n\n    if (dnsCache) {\n      dnsCache.clear(dnsEntry);\n      return res.status(204).send();\n    }\n\n    next({ status: 404, message: 'Cache not found.' });\n  }\n);\n\nsettingsRoutes.post(\n  '/initialize',\n  isAuthenticated(Permission.ADMIN),\n  async (_req, res) => {\n    const settings = getSettings();\n\n    settings.public.initialized = true;\n    await settings.save();\n\n    return res.status(200).json(settings.public);\n  }\n);\n\nsettingsRoutes.get('/about', async (req, res) => {\n  const mediaRepository = getRepository(Media);\n  const mediaRequestRepository = getRepository(MediaRequest);\n\n  const totalMediaItems = await mediaRepository.count();\n  const totalRequests = await mediaRequestRepository.count();\n\n  return res.status(200).json({\n    version: getAppVersion(),\n    totalMediaItems,\n    totalRequests,\n    tz: process.env.TZ,\n    appDataPath: appDataPath(),\n  } as SettingsAboutResponse);\n});\n\nexport default settingsRoutes;\n"
  },
  {
    "path": "server/routes/settings/metadata.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport Tvdb from '@server/api/tvdb';\nimport {\n  getSettings,\n  MetadataProviderType,\n  type MetadataSettings,\n} from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { Router } from 'express';\n\nfunction getTestResultString(testValue: number): string {\n  if (testValue === -1) return 'not tested';\n  if (testValue === 0) return 'failed';\n  return 'ok';\n}\n\nconst metadataRoutes = Router();\n\nmetadataRoutes.get('/', (_req, res) => {\n  const settings = getSettings();\n  res.status(200).json({\n    tv: settings.metadataSettings.tv,\n    anime: settings.metadataSettings.anime,\n  });\n});\n\nmetadataRoutes.put('/', async (req, res) => {\n  const settings = getSettings();\n  const body = req.body as MetadataSettings;\n\n  let tvdbTest = -1;\n  let tmdbTest = -1;\n\n  try {\n    if (\n      body.tv === MetadataProviderType.TVDB ||\n      body.anime === MetadataProviderType.TVDB\n    ) {\n      tvdbTest = 0;\n      const tvdb = await Tvdb.getInstance();\n      await tvdb.test();\n      tvdbTest = 1;\n    }\n  } catch (e) {\n    logger.error('Failed to test metadata provider', {\n      label: 'Metadata',\n      message: e.message,\n    });\n  }\n\n  try {\n    if (\n      body.tv === MetadataProviderType.TMDB ||\n      body.anime === MetadataProviderType.TMDB\n    ) {\n      tmdbTest = 0;\n      const tmdb = new TheMovieDb();\n      await tmdb.getTvShow({ tvId: 1054 });\n      tmdbTest = 1;\n    }\n  } catch (e) {\n    logger.error('Failed to test metadata provider', {\n      label: 'MetadataProvider',\n      message: e.message,\n    });\n  }\n\n  // If a test failed, return the test results\n  if (tvdbTest === 0 || tmdbTest === 0) {\n    return res.status(500).json({\n      success: false,\n      tests: {\n        tvdb: getTestResultString(tvdbTest),\n        tmdb: getTestResultString(tmdbTest),\n      },\n    });\n  }\n\n  settings.metadataSettings = {\n    tv: body.tv,\n    anime: body.anime,\n  };\n  await settings.save();\n\n  res.status(200).json({\n    success: true,\n    tv: body.tv,\n    anime: body.anime,\n    tests: {\n      tvdb: getTestResultString(tvdbTest),\n      tmdb: getTestResultString(tmdbTest),\n    },\n  });\n});\n\nmetadataRoutes.post('/test', async (req, res) => {\n  let tvdbTest = -1;\n  let tmdbTest = -1;\n\n  try {\n    const body = req.body as { tmdb: boolean; tvdb: boolean };\n\n    try {\n      if (body.tmdb) {\n        tmdbTest = 0;\n        const tmdb = new TheMovieDb();\n        await tmdb.getTvShow({ tvId: 1054 });\n        tmdbTest = 1;\n      }\n    } catch (e) {\n      logger.error('Failed to test metadata provider', {\n        label: 'MetadataProvider',\n        message: e.message,\n      });\n    }\n\n    try {\n      if (body.tvdb) {\n        tvdbTest = 0;\n        const tvdb = await Tvdb.getInstance();\n        await tvdb.test();\n        tvdbTest = 1;\n      }\n    } catch (e) {\n      logger.error('Failed to test metadata provider', {\n        label: 'MetadataProvider',\n        message: e.message,\n      });\n    }\n\n    const success = !(tvdbTest === 0 || tmdbTest === 0);\n    const statusCode = success ? 200 : 500;\n\n    return res.status(statusCode).json({\n      success: success,\n      tests: {\n        tmdb: getTestResultString(tmdbTest),\n        tvdb: getTestResultString(tvdbTest),\n      },\n    });\n  } catch (e) {\n    return res.status(500).json({\n      success: false,\n      tests: {\n        tmdb: getTestResultString(tmdbTest),\n        tvdb: getTestResultString(tvdbTest),\n      },\n      error: e.message,\n    });\n  }\n});\n\nexport default metadataRoutes;\n"
  },
  {
    "path": "server/routes/settings/notifications.ts",
    "content": "import type { User } from '@server/entity/User';\nimport { Notification } from '@server/lib/notifications';\nimport type { NotificationAgent } from '@server/lib/notifications/agents/agent';\nimport DiscordAgent from '@server/lib/notifications/agents/discord';\nimport EmailAgent from '@server/lib/notifications/agents/email';\nimport GotifyAgent from '@server/lib/notifications/agents/gotify';\nimport NtfyAgent from '@server/lib/notifications/agents/ntfy';\nimport PushbulletAgent from '@server/lib/notifications/agents/pushbullet';\nimport PushoverAgent from '@server/lib/notifications/agents/pushover';\nimport SlackAgent from '@server/lib/notifications/agents/slack';\nimport TelegramAgent from '@server/lib/notifications/agents/telegram';\nimport WebhookAgent from '@server/lib/notifications/agents/webhook';\nimport WebPushAgent from '@server/lib/notifications/agents/webpush';\nimport { getSettings } from '@server/lib/settings';\nimport { Router } from 'express';\n\nconst notificationRoutes = Router();\n\nconst sendTestNotification = async (agent: NotificationAgent, user: User) =>\n  await agent.send(Notification.TEST_NOTIFICATION, {\n    notifySystem: true,\n    notifyAdmin: false,\n    notifyUser: user,\n    subject: 'Test Notification',\n    message: 'Check check, 1, 2, 3. Are we coming in clear?',\n  });\n\nnotificationRoutes.get('/discord', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.notifications.agents.discord);\n});\n\nnotificationRoutes.post('/discord', async (req, res) => {\n  const settings = getSettings();\n\n  settings.notifications.agents.discord = req.body;\n  await settings.save();\n\n  res.status(200).json(settings.notifications.agents.discord);\n});\n\nnotificationRoutes.post('/discord/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  const discordAgent = new DiscordAgent(req.body);\n  if (await sendTestNotification(discordAgent, req.user)) {\n    return res.status(204).send();\n  } else {\n    return next({\n      status: 500,\n      message: 'Failed to send Discord notification.',\n    });\n  }\n});\n\nnotificationRoutes.get('/slack', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.notifications.agents.slack);\n});\n\nnotificationRoutes.post('/slack', async (req, res) => {\n  const settings = getSettings();\n\n  settings.notifications.agents.slack = req.body;\n  await settings.save();\n\n  res.status(200).json(settings.notifications.agents.slack);\n});\n\nnotificationRoutes.post('/slack/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  const slackAgent = new SlackAgent(req.body);\n  if (await sendTestNotification(slackAgent, req.user)) {\n    return res.status(204).send();\n  } else {\n    return next({\n      status: 500,\n      message: 'Failed to send Slack notification.',\n    });\n  }\n});\n\nnotificationRoutes.get('/telegram', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.notifications.agents.telegram);\n});\n\nnotificationRoutes.post('/telegram', async (req, res) => {\n  const settings = getSettings();\n\n  settings.notifications.agents.telegram = req.body;\n  await settings.save();\n\n  res.status(200).json(settings.notifications.agents.telegram);\n});\n\nnotificationRoutes.post('/telegram/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  const telegramAgent = new TelegramAgent(req.body);\n  if (await sendTestNotification(telegramAgent, req.user)) {\n    return res.status(204).send();\n  } else {\n    return next({\n      status: 500,\n      message: 'Failed to send Telegram notification.',\n    });\n  }\n});\n\nnotificationRoutes.get('/pushbullet', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.notifications.agents.pushbullet);\n});\n\nnotificationRoutes.post('/pushbullet', async (req, res) => {\n  const settings = getSettings();\n\n  settings.notifications.agents.pushbullet = req.body;\n  await settings.save();\n\n  res.status(200).json(settings.notifications.agents.pushbullet);\n});\n\nnotificationRoutes.post('/pushbullet/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  const pushbulletAgent = new PushbulletAgent(req.body);\n  if (await sendTestNotification(pushbulletAgent, req.user)) {\n    return res.status(204).send();\n  } else {\n    return next({\n      status: 500,\n      message: 'Failed to send Pushbullet notification.',\n    });\n  }\n});\n\nnotificationRoutes.get('/pushover', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.notifications.agents.pushover);\n});\n\nnotificationRoutes.post('/pushover', async (req, res) => {\n  const settings = getSettings();\n\n  settings.notifications.agents.pushover = req.body;\n  await settings.save();\n\n  res.status(200).json(settings.notifications.agents.pushover);\n});\n\nnotificationRoutes.post('/pushover/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  const pushoverAgent = new PushoverAgent(req.body);\n  if (await sendTestNotification(pushoverAgent, req.user)) {\n    return res.status(204).send();\n  } else {\n    return next({\n      status: 500,\n      message: 'Failed to send Pushover notification.',\n    });\n  }\n});\n\nnotificationRoutes.get('/email', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.notifications.agents.email);\n});\n\nnotificationRoutes.post('/email', async (req, res) => {\n  const settings = getSettings();\n\n  settings.notifications.agents.email = req.body;\n  await settings.save();\n\n  res.status(200).json(settings.notifications.agents.email);\n});\n\nnotificationRoutes.post('/email/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  const emailAgent = new EmailAgent(req.body);\n  if (await sendTestNotification(emailAgent, req.user)) {\n    return res.status(204).send();\n  } else {\n    return next({\n      status: 500,\n      message: 'Failed to send email notification.',\n    });\n  }\n});\n\nnotificationRoutes.get('/webpush', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.notifications.agents.webpush);\n});\n\nnotificationRoutes.post('/webpush', async (req, res) => {\n  const settings = getSettings();\n\n  settings.notifications.agents.webpush = req.body;\n  await settings.save();\n\n  res.status(200).json(settings.notifications.agents.webpush);\n});\n\nnotificationRoutes.post('/webpush/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  const webpushAgent = new WebPushAgent(req.body);\n  if (await sendTestNotification(webpushAgent, req.user)) {\n    return res.status(204).send();\n  } else {\n    return next({\n      status: 500,\n      message: 'Failed to send web push notification.',\n    });\n  }\n});\n\nnotificationRoutes.get('/webhook', (_req, res) => {\n  const settings = getSettings();\n\n  const webhookSettings = settings.notifications.agents.webhook;\n\n  const response: typeof webhookSettings = {\n    enabled: webhookSettings.enabled,\n    embedPoster: webhookSettings.embedPoster,\n    types: webhookSettings.types,\n    options: {\n      ...webhookSettings.options,\n      jsonPayload: JSON.parse(\n        Buffer.from(webhookSettings.options.jsonPayload, 'base64').toString(\n          'utf8'\n        )\n      ),\n      customHeaders: webhookSettings.options.customHeaders ?? [],\n      supportVariables: webhookSettings.options.supportVariables ?? false,\n    },\n  };\n\n  res.status(200).json(response);\n});\n\nnotificationRoutes.post('/webhook', async (req, res, next) => {\n  const settings = getSettings();\n  try {\n    JSON.parse(req.body.options.jsonPayload);\n\n    settings.notifications.agents.webhook = {\n      enabled: req.body.enabled,\n      embedPoster: req.body.embedPoster,\n      types: req.body.types,\n      options: {\n        jsonPayload: Buffer.from(req.body.options.jsonPayload).toString(\n          'base64'\n        ),\n        webhookUrl: req.body.options.webhookUrl,\n        authHeader: req.body.options.authHeader,\n        customHeaders: req.body.options.customHeaders ?? [],\n        supportVariables: req.body.options.supportVariables ?? false,\n      },\n    };\n    await settings.save();\n\n    res.status(200).json(settings.notifications.agents.webhook);\n  } catch (e) {\n    next({ status: 500, message: e.message });\n  }\n});\n\nnotificationRoutes.post('/webhook/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  try {\n    JSON.parse(req.body.options.jsonPayload);\n\n    const testBody = {\n      enabled: req.body.enabled,\n      embedPoster: req.body.embedPoster,\n      types: req.body.types,\n      options: {\n        jsonPayload: Buffer.from(req.body.options.jsonPayload).toString(\n          'base64'\n        ),\n        webhookUrl: req.body.options.webhookUrl,\n        authHeader: req.body.options.authHeader,\n        customHeaders: req.body.options.customHeaders ?? [],\n        supportVariables: req.body.options.supportVariables ?? false,\n      },\n    };\n\n    const webhookAgent = new WebhookAgent(testBody);\n    if (await sendTestNotification(webhookAgent, req.user)) {\n      return res.status(204).send();\n    } else {\n      return next({\n        status: 500,\n        message: 'Failed to send webhook notification.',\n      });\n    }\n  } catch (e) {\n    next({ status: 500, message: e.message });\n  }\n});\n\nnotificationRoutes.get('/gotify', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.notifications.agents.gotify);\n});\n\nnotificationRoutes.post('/gotify', async (req, res) => {\n  const settings = getSettings();\n\n  settings.notifications.agents.gotify = req.body;\n  await settings.save();\n\n  res.status(200).json(settings.notifications.agents.gotify);\n});\n\nnotificationRoutes.post('/gotify/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  const gotifyAgent = new GotifyAgent(req.body);\n  if (await sendTestNotification(gotifyAgent, req.user)) {\n    return res.status(204).send();\n  } else {\n    return next({\n      status: 500,\n      message: 'Failed to send Gotify notification.',\n    });\n  }\n});\n\nnotificationRoutes.get('/ntfy', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.notifications.agents.ntfy);\n});\n\nnotificationRoutes.post('/ntfy', async (req, res) => {\n  const settings = getSettings();\n\n  settings.notifications.agents.ntfy = req.body;\n  await settings.save();\n\n  res.status(200).json(settings.notifications.agents.ntfy);\n});\n\nnotificationRoutes.post('/ntfy/test', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 500,\n      message: 'User information is missing from the request.',\n    });\n  }\n\n  const ntfyAgent = new NtfyAgent(req.body);\n  if (await sendTestNotification(ntfyAgent, req.user)) {\n    return res.status(204).send();\n  } else {\n    return next({\n      status: 500,\n      message: 'Failed to send ntfy notification.',\n    });\n  }\n});\n\nexport default notificationRoutes;\n"
  },
  {
    "path": "server/routes/settings/radarr.ts",
    "content": "import RadarrAPI from '@server/api/servarr/radarr';\nimport type { RadarrSettings } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { Router } from 'express';\n\nconst radarrRoutes = Router();\n\nradarrRoutes.get('/', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.radarr);\n});\n\nradarrRoutes.post('/', async (req, res) => {\n  const settings = getSettings();\n\n  const newRadarr = req.body as RadarrSettings;\n  const lastItem = settings.radarr[settings.radarr.length - 1];\n  newRadarr.id = lastItem ? lastItem.id + 1 : 0;\n\n  // If we are setting this as the default, clear any previous defaults for the same type first\n  // ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true\n  // and are the default\n  if (req.body.isDefault) {\n    settings.radarr\n      .filter((radarrInstance) => radarrInstance.is4k === req.body.is4k)\n      .forEach((radarrInstance) => {\n        radarrInstance.isDefault = false;\n      });\n  }\n\n  settings.radarr = [...settings.radarr, newRadarr];\n  await settings.save();\n\n  return res.status(201).json(newRadarr);\n});\n\nradarrRoutes.post<\n  undefined,\n  Record<string, unknown>,\n  RadarrSettings & { tagLabel?: string }\n>('/test', async (req, res, next) => {\n  try {\n    const radarr = new RadarrAPI({\n      apiKey: req.body.apiKey,\n      url: RadarrAPI.buildUrl(req.body, '/api/v3'),\n    });\n\n    const urlBase = await radarr\n      .getSystemStatus()\n      .then((value) => value.urlBase)\n      .catch(() => req.body.baseUrl);\n    const profiles = await radarr.getProfiles();\n    const folders = await radarr.getRootFolders();\n    const tags = await radarr.getTags();\n\n    return res.status(200).json({\n      profiles,\n      rootFolders: folders.map((folder) => ({\n        id: folder.id,\n        path: folder.path,\n      })),\n      tags,\n      urlBase,\n    });\n  } catch (e) {\n    logger.error('Failed to test Radarr', {\n      label: 'Radarr',\n      message: e.message,\n    });\n\n    next({ status: 500, message: 'Failed to connect to Radarr' });\n  }\n});\n\nradarrRoutes.put<{ id: string }, RadarrSettings, RadarrSettings>(\n  '/:id',\n  async (req, res, next) => {\n    const settings = getSettings();\n\n    const radarrIndex = settings.radarr.findIndex(\n      (r) => r.id === Number(req.params.id)\n    );\n\n    if (radarrIndex === -1) {\n      return next({ status: '404', message: 'Settings instance not found' });\n    }\n\n    // If we are setting this as the default, clear any previous defaults for the same type first\n    // ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true\n    // and are the default\n    if (req.body.isDefault) {\n      settings.radarr\n        .filter((radarrInstance) => radarrInstance.is4k === req.body.is4k)\n        .forEach((radarrInstance) => {\n          radarrInstance.isDefault = false;\n        });\n    }\n\n    settings.radarr[radarrIndex] = {\n      ...req.body,\n      id: Number(req.params.id),\n    } as RadarrSettings;\n    await settings.save();\n\n    return res.status(200).json(settings.radarr[radarrIndex]);\n  }\n);\n\nradarrRoutes.get<{ id: string }>('/:id/profiles', async (req, res, next) => {\n  const settings = getSettings();\n\n  const radarrSettings = settings.radarr.find(\n    (r) => r.id === Number(req.params.id)\n  );\n\n  if (!radarrSettings) {\n    return next({ status: '404', message: 'Settings instance not found' });\n  }\n\n  const radarr = new RadarrAPI({\n    apiKey: radarrSettings.apiKey,\n    url: RadarrAPI.buildUrl(radarrSettings, '/api/v3'),\n  });\n\n  const profiles = await radarr.getProfiles();\n\n  return res.status(200).json(\n    profiles.map((profile) => ({\n      id: profile.id,\n      name: profile.name,\n    }))\n  );\n});\n\nradarrRoutes.delete<{ id: string }>('/:id', async (req, res, next) => {\n  const settings = getSettings();\n\n  const radarrIndex = settings.radarr.findIndex(\n    (r) => r.id === Number(req.params.id)\n  );\n\n  if (radarrIndex === -1) {\n    return next({ status: '404', message: 'Settings instance not found' });\n  }\n\n  const removed = settings.radarr.splice(radarrIndex, 1);\n  await settings.save();\n\n  return res.status(200).json(removed[0]);\n});\n\nexport default radarrRoutes;\n"
  },
  {
    "path": "server/routes/settings/sonarr.ts",
    "content": "import SonarrAPI from '@server/api/servarr/sonarr';\nimport type { SonarrSettings } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { Router } from 'express';\n\nconst sonarrRoutes = Router();\n\nsonarrRoutes.get('/', (_req, res) => {\n  const settings = getSettings();\n\n  res.status(200).json(settings.sonarr);\n});\n\nsonarrRoutes.post('/', async (req, res) => {\n  const settings = getSettings();\n\n  const newSonarr = req.body as SonarrSettings;\n  const lastItem = settings.sonarr[settings.sonarr.length - 1];\n  newSonarr.id = lastItem ? lastItem.id + 1 : 0;\n\n  // If we are setting this as the default, clear any previous defaults for the same type first\n  // ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true\n  // and are the default\n  if (req.body.isDefault) {\n    settings.sonarr\n      .filter((sonarrInstance) => sonarrInstance.is4k === req.body.is4k)\n      .forEach((sonarrInstance) => {\n        sonarrInstance.isDefault = false;\n      });\n  }\n\n  settings.sonarr = [...settings.sonarr, newSonarr];\n  await settings.save();\n\n  return res.status(201).json(newSonarr);\n});\n\nsonarrRoutes.post('/test', async (req, res, next) => {\n  try {\n    const sonarr = new SonarrAPI({\n      apiKey: req.body.apiKey,\n      url: SonarrAPI.buildUrl(req.body, '/api/v3'),\n    });\n\n    const systemStatus = await sonarr.getSystemStatus();\n    const sonarrMajorVersion = Number(systemStatus.version.split('.')[0]);\n\n    const urlBase = systemStatus.urlBase;\n    const profiles = await sonarr.getProfiles();\n    const folders = await sonarr.getRootFolders();\n    const languageProfiles =\n      sonarrMajorVersion <= 3 ? await sonarr.getLanguageProfiles() : null;\n    const tags = await sonarr.getTags();\n\n    return res.status(200).json({\n      profiles,\n      rootFolders: folders.map((folder) => ({\n        id: folder.id,\n        path: folder.path,\n      })),\n      languageProfiles,\n      tags,\n      urlBase,\n    });\n  } catch (e) {\n    logger.error('Failed to test Sonarr', {\n      label: 'Sonarr',\n      message: e.message,\n    });\n\n    next({ status: 500, message: 'Failed to connect to Sonarr' });\n  }\n});\n\nsonarrRoutes.put<{ id: string }>('/:id', async (req, res) => {\n  const settings = getSettings();\n\n  const sonarrIndex = settings.sonarr.findIndex(\n    (r) => r.id === Number(req.params.id)\n  );\n\n  if (sonarrIndex === -1) {\n    return res\n      .status(404)\n      .json({ status: '404', message: 'Settings instance not found' });\n  }\n\n  // If we are setting this as the default, clear any previous defaults for the same type first\n  // ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true\n  // and are the default\n  if (req.body.isDefault) {\n    settings.sonarr\n      .filter((sonarrInstance) => sonarrInstance.is4k === req.body.is4k)\n      .forEach((sonarrInstance) => {\n        sonarrInstance.isDefault = false;\n      });\n  }\n\n  settings.sonarr[sonarrIndex] = {\n    ...req.body,\n    id: Number(req.params.id),\n  } as SonarrSettings;\n  await settings.save();\n\n  return res.status(200).json(settings.sonarr[sonarrIndex]);\n});\n\nsonarrRoutes.delete<{ id: string }>('/:id', async (req, res) => {\n  const settings = getSettings();\n\n  const sonarrIndex = settings.sonarr.findIndex(\n    (r) => r.id === Number(req.params.id)\n  );\n\n  if (sonarrIndex === -1) {\n    return res\n      .status(404)\n      .json({ status: '404', message: 'Settings instance not found' });\n  }\n\n  const removed = settings.sonarr.splice(sonarrIndex, 1);\n  await settings.save();\n\n  return res.status(200).json(removed[0]);\n});\n\nexport default sonarrRoutes;\n"
  },
  {
    "path": "server/routes/tv.ts",
    "content": "import { getMetadataProvider } from '@server/api/metadata';\nimport RottenTomatoes from '@server/api/rating/rottentomatoes';\nimport TheMovieDb from '@server/api/themoviedb';\nimport { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants';\nimport type { TmdbKeyword } from '@server/api/themoviedb/interfaces';\nimport { MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport { Watchlist } from '@server/entity/Watchlist';\nimport logger from '@server/logger';\nimport { mapTvResult } from '@server/models/Search';\nimport { mapSeasonWithEpisodes, mapTvDetails } from '@server/models/Tv';\nimport { Router } from 'express';\n\nconst tvRoutes = Router();\n\ntvRoutes.get('/:id', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const tmdbTv = await tmdb.getTvShow({\n      tvId: Number(req.params.id),\n    });\n    const metadataProvider = tmdbTv.keywords.results.some(\n      (keyword: TmdbKeyword) => keyword.id === ANIME_KEYWORD_ID\n    )\n      ? await getMetadataProvider('anime')\n      : await getMetadataProvider('tv');\n    const tv = await metadataProvider.getTvShow({\n      tvId: Number(req.params.id),\n      language: (req.query.language as string) ?? req.locale,\n    });\n    const media = await Media.getMedia(tv.id, MediaType.TV);\n\n    const onUserWatchlist = await getRepository(Watchlist).exist({\n      where: {\n        tmdbId: Number(req.params.id),\n        mediaType: MediaType.TV,\n        requestedBy: {\n          id: req.user?.id,\n        },\n      },\n    });\n\n    const data = mapTvDetails(tv, media, onUserWatchlist);\n\n    // TMDB issue where it doesnt fallback to English when no overview is available in requested locale.\n    if (!data.overview) {\n      const tvEnglish = await metadataProvider.getTvShow({\n        tvId: Number(req.params.id),\n      });\n      data.overview = tvEnglish.overview;\n    }\n\n    return res.status(200).json(data);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving series', {\n      label: 'API',\n      errorMessage: e.message,\n      tvId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve series.',\n    });\n  }\n});\n\ntvRoutes.get('/:id/season/:seasonNumber', async (req, res, next) => {\n  try {\n    const tmdb = new TheMovieDb();\n    const tmdbTv = await tmdb.getTvShow({\n      tvId: Number(req.params.id),\n    });\n    const metadataProvider = tmdbTv.keywords.results.some(\n      (keyword: TmdbKeyword) => keyword.id === ANIME_KEYWORD_ID\n    )\n      ? await getMetadataProvider('anime')\n      : await getMetadataProvider('tv');\n\n    const season = await metadataProvider.getTvSeason({\n      tvId: Number(req.params.id),\n      seasonNumber: Number(req.params.seasonNumber),\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    return res.status(200).json(mapSeasonWithEpisodes(season));\n  } catch (e) {\n    logger.debug('Something went wrong retrieving season', {\n      label: 'API',\n      errorMessage: e.message,\n      tvId: req.params.id,\n      seasonNumber: req.params.seasonNumber,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve season.',\n    });\n  }\n});\n\ntvRoutes.get('/:id/recommendations', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const results = await tmdb.getTvRecommendations({\n      tvId: Number(req.params.id),\n      page: Number(req.query.page),\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      results.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: MediaType.TV,\n      }))\n    );\n\n    return res.status(200).json({\n      page: results.page,\n      totalPages: results.total_pages,\n      totalResults: results.total_results,\n      results: results.results.map((result) =>\n        mapTvResult(\n          result,\n          media.find(\n            (req) => req.tmdbId === result.id && req.mediaType === MediaType.TV\n          )\n        )\n      ),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving series recommendations', {\n      label: 'API',\n      errorMessage: e.message,\n      tvId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve series recommendations.',\n    });\n  }\n});\n\ntvRoutes.get('/:id/similar', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n\n  try {\n    const results = await tmdb.getTvSimilar({\n      tvId: Number(req.params.id),\n      page: Number(req.query.page),\n      language: (req.query.language as string) ?? req.locale,\n    });\n\n    const media = await Media.getRelatedMedia(\n      req.user,\n      results.results.map((result) => ({\n        tmdbId: result.id,\n        mediaType: MediaType.TV,\n      }))\n    );\n\n    return res.status(200).json({\n      page: results.page,\n      totalPages: results.total_pages,\n      totalResults: results.total_results,\n      results: results.results.map((result) =>\n        mapTvResult(\n          result,\n          media.find(\n            (req) => req.tmdbId === result.id && req.mediaType === MediaType.TV\n          )\n        )\n      ),\n    });\n  } catch (e) {\n    logger.debug('Something went wrong retrieving similar series', {\n      label: 'API',\n      errorMessage: e.message,\n      tvId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve similar series.',\n    });\n  }\n});\n\ntvRoutes.get('/:id/ratings', async (req, res, next) => {\n  const tmdb = new TheMovieDb();\n  const rtapi = new RottenTomatoes();\n\n  try {\n    const tv = await tmdb.getTvShow({\n      tvId: Number(req.params.id),\n    });\n\n    const rtratings = await rtapi.getTVRatings(\n      tv.name,\n      tv.first_air_date ? Number(tv.first_air_date.slice(0, 4)) : undefined\n    );\n\n    if (!rtratings) {\n      return next({\n        status: 404,\n        message: 'Rotten Tomatoes ratings not found.',\n      });\n    }\n\n    return res.status(200).json(rtratings);\n  } catch (e) {\n    logger.debug('Something went wrong retrieving series ratings', {\n      label: 'API',\n      errorMessage: e.message,\n      tvId: req.params.id,\n    });\n    return next({\n      status: 500,\n      message: 'Unable to retrieve series ratings.',\n    });\n  }\n});\n\nexport default tvRoutes;\n"
  },
  {
    "path": "server/routes/user/index.ts",
    "content": "import JellyfinAPI from '@server/api/jellyfin';\nimport PlexTvAPI from '@server/api/plextv';\nimport TautulliAPI from '@server/api/tautulli';\nimport { MediaType } from '@server/constants/media';\nimport { MediaServerType } from '@server/constants/server';\nimport { UserType } from '@server/constants/user';\nimport dataSource, { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport { MediaRequest } from '@server/entity/MediaRequest';\nimport { User } from '@server/entity/User';\nimport { UserPushSubscription } from '@server/entity/UserPushSubscription';\nimport { Watchlist } from '@server/entity/Watchlist';\nimport type { WatchlistResponse } from '@server/interfaces/api/discoverInterfaces';\nimport type {\n  QuotaResponse,\n  UserRequestsResponse,\n  UserResultsResponse,\n  UserWatchDataResponse,\n} from '@server/interfaces/api/userInterfaces';\nimport { Permission, hasPermission } from '@server/lib/permissions';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport { getHostname } from '@server/utils/getHostname';\nimport { normalizeJellyfinGuid } from '@server/utils/jellyfin';\nimport { isOwnProfileOrAdmin } from '@server/utils/profileMiddleware';\nimport { Router } from 'express';\nimport gravatarUrl from 'gravatar-url';\nimport { findIndex, sortBy } from 'lodash';\nimport type { EntityManager } from 'typeorm';\nimport { In, Not } from 'typeorm';\nimport userSettingsRoutes from './usersettings';\n\nconst router = Router();\n\nrouter.get('/', async (req, res, next) => {\n  try {\n    const includeIds = [\n      ...new Set(\n        req.query.includeIds ? req.query.includeIds.toString().split(',') : []\n      ),\n    ];\n    const pageSize = req.query.take\n      ? Number(req.query.take)\n      : Math.max(10, includeIds.length);\n    const skip = req.query.skip ? Number(req.query.skip) : 0;\n    const q = req.query.q ? req.query.q.toString().toLowerCase() : '';\n    let query = getRepository(User).createQueryBuilder('user');\n\n    if (q) {\n      query = query.where(\n        'LOWER(user.username) LIKE :q OR LOWER(user.email) LIKE :q OR LOWER(user.plexUsername) LIKE :q OR LOWER(user.jellyfinUsername) LIKE :q',\n        { q: `%${q}%` }\n      );\n    }\n\n    if (includeIds.length > 0) {\n      query.andWhereInIds(includeIds);\n    }\n\n    switch (req.query.sort) {\n      case 'updated':\n        query = query.orderBy('user.updatedAt', 'DESC');\n        break;\n      case 'displayname':\n        query = query\n          .addSelect(\n            `CASE WHEN (user.username IS NULL OR user.username = '') THEN (\n              CASE WHEN (user.plexUsername IS NULL OR user.plexUsername = '') THEN (\n                CASE WHEN (user.jellyfinUsername IS NULL OR user.jellyfinUsername = '') THEN\n                  \"user\".\"email\"\n                ELSE\n                  LOWER(user.jellyfinUsername)\n                END)\n              ELSE\n                LOWER(user.jellyfinUsername)\n              END)\n            ELSE\n              LOWER(user.username)\n            END`,\n            'displayname_sort_key'\n          )\n          .orderBy('displayname_sort_key', 'ASC');\n        break;\n      case 'requests':\n        query = query\n          .addSelect((subQuery) => {\n            return subQuery\n              .select('COUNT(request.id)', 'request_count')\n              .from(MediaRequest, 'request')\n              .where('request.requestedBy.id = user.id');\n          }, 'request_count')\n          .orderBy('request_count', 'DESC');\n        break;\n      default:\n        query = query.orderBy('user.id', 'ASC');\n        break;\n    }\n\n    const [users, userCount] = await query\n      .take(pageSize)\n      .skip(skip)\n      .distinct(true)\n      .getManyAndCount();\n\n    return res.status(200).json({\n      pageInfo: {\n        pages: Math.ceil(userCount / pageSize),\n        pageSize,\n        results: userCount,\n        page: Math.ceil(skip / pageSize) + 1,\n      },\n      results: User.filterMany(\n        users,\n        req.user?.hasPermission(Permission.MANAGE_USERS)\n      ),\n    } as UserResultsResponse);\n  } catch (e) {\n    next({ status: 500, message: e.message });\n  }\n});\n\nrouter.post(\n  '/',\n  isAuthenticated(Permission.MANAGE_USERS),\n  async (req, res, next) => {\n    try {\n      const settings = getSettings();\n\n      const body = req.body;\n      const email = body.email || body.username;\n      const userRepository = getRepository(User);\n\n      const existingUser = await userRepository\n        .createQueryBuilder('user')\n        .where('user.email = :email', {\n          email: email.toLowerCase(),\n        })\n        .getOne();\n\n      if (existingUser) {\n        return next({\n          status: 409,\n          message: 'User already exists with submitted email.',\n          errors: ['USER_EXISTS'],\n        });\n      }\n\n      const passedExplicitPassword = body.password && body.password.length > 0;\n      const avatar = gravatarUrl(email, { default: 'mm', size: 200 });\n\n      if (\n        !passedExplicitPassword &&\n        !settings.notifications.agents.email.enabled\n      ) {\n        throw new Error('Email notifications must be enabled');\n      }\n\n      const user = new User({\n        email,\n        avatar: body.avatar ?? avatar,\n        username: body.username,\n        password: body.password,\n        permissions: settings.main.defaultPermissions,\n        plexToken: '',\n        userType: UserType.LOCAL,\n      });\n\n      if (passedExplicitPassword) {\n        await user?.setPassword(body.password);\n      } else {\n        await user?.generatePassword();\n      }\n\n      await userRepository.save(user);\n      return res.status(201).json(user.filter());\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nrouter.post<\n  never,\n  unknown,\n  {\n    endpoint: string;\n    p256dh: string;\n    auth: string;\n    userAgent: string;\n  }\n>('/registerPushSubscription', async (req, res, next) => {\n  try {\n    // This prevents race conditions where two requests both pass the checks\n    await dataSource.transaction(\n      async (transactionalEntityManager: EntityManager) => {\n        const transactionalRepo =\n          transactionalEntityManager.getRepository(UserPushSubscription);\n\n        // Check for existing subscription by auth or endpoint within transaction\n        const existingSubscription = await transactionalRepo.findOne({\n          relations: { user: true },\n          where: [\n            { auth: req.body.auth, user: { id: req.user?.id } },\n            { endpoint: req.body.endpoint, user: { id: req.user?.id } },\n          ],\n        });\n\n        if (existingSubscription) {\n          // If endpoint matches but auth is different, update with new keys (iOS refresh case)\n          if (\n            existingSubscription.endpoint === req.body.endpoint &&\n            existingSubscription.auth !== req.body.auth\n          ) {\n            existingSubscription.auth = req.body.auth;\n            existingSubscription.p256dh = req.body.p256dh;\n            existingSubscription.userAgent = req.body.userAgent;\n\n            await transactionalRepo.save(existingSubscription);\n\n            logger.debug(\n              'Updated existing push subscription with new keys for same endpoint.',\n              { label: 'API' }\n            );\n            return;\n          }\n\n          logger.debug(\n            'Duplicate subscription detected. Skipping registration.',\n            { label: 'API' }\n          );\n          return;\n        }\n\n        // Clean up old subscriptions from the same device (userAgent) for this user\n        // iOS can silently refresh endpoints, leaving stale subscriptions in the database\n        // Only clean up if we're creating a new subscription (not updating an existing one)\n        if (req.body.userAgent) {\n          const staleSubscriptions = await transactionalRepo.find({\n            relations: { user: true },\n            where: {\n              userAgent: req.body.userAgent,\n              user: { id: req.user?.id },\n              // Only remove subscriptions with different endpoints (stale ones)\n              // Keep subscriptions that might be from different browsers/tabs\n              endpoint: Not(req.body.endpoint),\n            },\n          });\n\n          if (staleSubscriptions.length > 0) {\n            await transactionalRepo.remove(staleSubscriptions);\n            logger.debug(\n              `Removed ${staleSubscriptions.length} stale push subscription(s) from same device.`,\n              { label: 'API' }\n            );\n          }\n        }\n\n        const userPushSubscription = new UserPushSubscription({\n          auth: req.body.auth,\n          endpoint: req.body.endpoint,\n          p256dh: req.body.p256dh,\n          userAgent: req.body.userAgent,\n          user: req.user,\n        });\n\n        await transactionalRepo.save(userPushSubscription);\n      }\n    );\n\n    return res.status(204).send();\n  } catch {\n    logger.error('Failed to register user push subscription', {\n      label: 'API',\n    });\n    next({ status: 500, message: 'Failed to register subscription.' });\n  }\n});\n\nrouter.get<{ userId: string }>(\n  '/:userId/pushSubscriptions',\n  isOwnProfileOrAdmin(),\n  async (req, res, next) => {\n    try {\n      const userPushSubRepository = getRepository(UserPushSubscription);\n\n      const userPushSubs = await userPushSubRepository.find({\n        relations: { user: true },\n        where: { user: { id: Number(req.params.userId) } },\n      });\n\n      return res.status(200).json(userPushSubs);\n    } catch {\n      next({ status: 404, message: 'User subscriptions not found.' });\n    }\n  }\n);\n\nrouter.get<{ userId: string; endpoint: string }>(\n  '/:userId/pushSubscription/:endpoint',\n  isOwnProfileOrAdmin(),\n  async (req, res, next) => {\n    try {\n      const userPushSubRepository = getRepository(UserPushSubscription);\n\n      const userPushSub = await userPushSubRepository.findOneOrFail({\n        relations: {\n          user: true,\n        },\n        where: {\n          user: { id: Number(req.params.userId) },\n          endpoint: req.params.endpoint,\n        },\n      });\n\n      return res.status(200).json(userPushSub);\n    } catch {\n      next({ status: 404, message: 'User subscription not found.' });\n    }\n  }\n);\n\nrouter.delete<{ userId: string; endpoint: string }>(\n  '/:userId/pushSubscription/:endpoint',\n  isOwnProfileOrAdmin(),\n  async (req, res, next) => {\n    try {\n      const userPushSubRepository = getRepository(UserPushSubscription);\n\n      const userPushSub = await userPushSubRepository.findOne({\n        relations: { user: true },\n        where: {\n          user: { id: Number(req.params.userId) },\n          endpoint: req.params.endpoint,\n        },\n      });\n\n      // If not found, just return 204 to prevent push disable failure\n      // (rare scenario where user push sub does not exist)\n      if (!userPushSub) {\n        return res.status(204).send();\n      }\n\n      await userPushSubRepository.remove(userPushSub);\n      return res.status(204).send();\n    } catch (e) {\n      logger.error('Something went wrong deleting the user push subcription', {\n        label: 'API',\n        endpoint: req.params.endpoint,\n        errorMessage: e.message,\n      });\n      return next({\n        status: 500,\n        message: 'User push subcription not found',\n      });\n    }\n  }\n);\n\nrouter.get<{ id: string }>('/:id', async (req, res, next) => {\n  try {\n    const userRepository = getRepository(User);\n    const user = await userRepository.findOneOrFail({\n      where: { id: Number(req.params.id) },\n    });\n\n    const isOwnProfile = req.user?.id === user.id;\n    const isAdmin = req.user?.hasPermission(Permission.MANAGE_USERS);\n\n    return res.status(200).json(user.filter(isOwnProfile || isAdmin));\n  } catch {\n    next({ status: 404, message: 'User not found.' });\n  }\n});\n\nrouter.use('/:id/settings', userSettingsRoutes);\n\nrouter.get<{ id: string }, UserRequestsResponse>(\n  '/:id/requests',\n  async (req, res, next) => {\n    const pageSize = req.query.take ? Number(req.query.take) : 20;\n    const skip = req.query.skip ? Number(req.query.skip) : 0;\n\n    try {\n      const user = await getRepository(User).findOne({\n        where: { id: Number(req.params.id) },\n      });\n\n      if (!user) {\n        return next({ status: 404, message: 'User not found.' });\n      }\n\n      if (\n        user.id !== req.user?.id &&\n        !req.user?.hasPermission(\n          [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n          { type: 'or' }\n        )\n      ) {\n        return next({\n          status: 403,\n          message: \"You do not have permission to view this user's requests.\",\n        });\n      }\n\n      const [requests, requestCount] = await getRepository(MediaRequest)\n        .createQueryBuilder('request')\n        .leftJoinAndSelect('request.media', 'media')\n        .leftJoinAndSelect('request.seasons', 'seasons')\n        .leftJoinAndSelect('request.modifiedBy', 'modifiedBy')\n        .leftJoinAndSelect('request.requestedBy', 'requestedBy')\n        .andWhere('requestedBy.id = :id', {\n          id: user.id,\n        })\n        .orderBy('request.id', 'DESC')\n        .take(pageSize)\n        .skip(skip)\n        .getManyAndCount();\n\n      return res.status(200).json({\n        pageInfo: {\n          pages: Math.ceil(requestCount / pageSize),\n          pageSize,\n          results: requestCount,\n          page: Math.ceil(skip / pageSize) + 1,\n        },\n        results: requests,\n      });\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nexport const canMakePermissionsChange = (\n  permissions: number,\n  user?: User\n): boolean =>\n  // Only let the owner grant admin privileges\n  !(hasPermission(Permission.ADMIN, permissions) && user?.id !== 1);\n\nrouter.put<\n  Record<string, never>,\n  Partial<User>[],\n  { ids: string[]; permissions: number }\n>('/', isAuthenticated(Permission.MANAGE_USERS), async (req, res, next) => {\n  try {\n    const isOwner = req.user?.id === 1;\n\n    if (!canMakePermissionsChange(req.body.permissions, req.user)) {\n      return next({\n        status: 403,\n        message: 'You do not have permission to grant this level of access',\n      });\n    }\n\n    const userRepository = getRepository(User);\n\n    const users: User[] = await userRepository.find({\n      where: {\n        id: In(\n          isOwner ? req.body.ids : req.body.ids.filter((id) => Number(id) !== 1)\n        ),\n      },\n    });\n\n    const updatedUsers = await Promise.all(\n      users.map(async (user) => {\n        return userRepository.save(<User>{\n          ...user,\n          ...{ permissions: req.body.permissions },\n        });\n      })\n    );\n\n    return res.status(200).json(updatedUsers);\n  } catch (e) {\n    next({ status: 500, message: e.message });\n  }\n});\n\nrouter.put<{ id: string }>(\n  '/:id',\n  isAuthenticated(Permission.MANAGE_USERS),\n  async (req, res, next) => {\n    try {\n      const userRepository = getRepository(User);\n\n      const user = await userRepository.findOneOrFail({\n        where: { id: Number(req.params.id) },\n      });\n\n      // Only let the owner user modify themselves\n      if (user.id === 1 && req.user?.id !== 1) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to modify this user',\n        });\n      }\n\n      if (!canMakePermissionsChange(req.body.permissions, req.user)) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to grant this level of access',\n        });\n      }\n\n      Object.assign(user, {\n        username: req.body.username,\n        permissions: req.body.permissions,\n      });\n\n      await userRepository.save(user);\n\n      return res.status(200).json(user.filter());\n    } catch {\n      next({ status: 404, message: 'User not found.' });\n    }\n  }\n);\n\nrouter.delete<{ id: string }>(\n  '/:id',\n  isAuthenticated(Permission.MANAGE_USERS),\n  async (req, res, next) => {\n    try {\n      const userRepository = getRepository(User);\n\n      const user = await userRepository.findOne({\n        where: { id: Number(req.params.id) },\n        relations: { requests: true },\n      });\n\n      if (!user) {\n        return next({ status: 404, message: 'User not found.' });\n      }\n\n      if (user.id === 1) {\n        return next({\n          status: 405,\n          message: 'This account cannot be deleted.',\n        });\n      }\n\n      if (user.hasPermission(Permission.ADMIN) && req.user?.id !== 1) {\n        return next({\n          status: 405,\n          message: 'You cannot delete users with administrative privileges.',\n        });\n      }\n\n      const requestRepository = getRepository(MediaRequest);\n\n      /**\n       * Requests are usually deleted through a cascade constraint. Those however, do\n       * not trigger the removal event so listeners to not run and the parent Media\n       * will not be updated back to unknown for titles that were still pending. So\n       * we manually remove all requests from the user here so the parent media's\n       * properly reflect the change.\n       */\n      await requestRepository.remove(user.requests, {\n        /**\n         * Break-up into groups of 1000 requests to be removed at a time.\n         * Necessary for users with >1000 requests, else an SQLite 'Expression tree is too large' error occurs.\n         * https://typeorm.io/repository-api#additional-options\n         */\n        chunk: user.requests.length / 1000,\n      });\n\n      await userRepository.delete(user.id);\n      return res.status(200).json(user.filter());\n    } catch (e) {\n      logger.error('Something went wrong deleting a user', {\n        label: 'API',\n        userId: req.params.id,\n        errorMessage: e.message,\n      });\n      return next({\n        status: 500,\n        message: 'Something went wrong deleting the user',\n      });\n    }\n  }\n);\n\nrouter.post(\n  '/import-from-plex',\n  isAuthenticated(Permission.MANAGE_USERS),\n  async (req, res, next) => {\n    try {\n      const settings = getSettings();\n      const userRepository = getRepository(User);\n      const body = req.body as { plexIds: string[] } | undefined;\n\n      // taken from auth.ts\n      const mainUser = await userRepository.findOneOrFail({\n        select: { id: true, plexToken: true },\n        where: { id: 1 },\n      });\n      const mainPlexTv = new PlexTvAPI(mainUser.plexToken ?? '');\n\n      const plexUsersResponse = await mainPlexTv.getUsers();\n      const createdUsers: User[] = [];\n      for (const rawUser of plexUsersResponse.MediaContainer.User) {\n        const account = rawUser.$;\n\n        if (account.email) {\n          const user = await userRepository\n            .createQueryBuilder('user')\n            .where('user.plexId = :id', { id: account.id })\n            .orWhere('user.email = :email', {\n              email: account.email.toLowerCase(),\n            })\n            .getOne();\n\n          if (user) {\n            // Update the user's avatar with their Plex thumbnail, in case it changed\n            user.avatar = account.thumb;\n            user.email = account.email;\n            user.plexUsername = account.username;\n\n            // In case the user was previously a local account\n            if (user.userType === UserType.LOCAL) {\n              user.userType = UserType.PLEX;\n              user.plexId = parseInt(account.id);\n            }\n            await userRepository.save(user);\n          } else if (!body || body.plexIds.includes(account.id)) {\n            if (await mainPlexTv.checkUserAccess(parseInt(account.id))) {\n              const newUser = new User({\n                plexUsername: account.username,\n                email: account.email,\n                permissions: settings.main.defaultPermissions,\n                plexId: parseInt(account.id),\n                plexToken: '',\n                avatar: account.thumb,\n                userType: UserType.PLEX,\n              });\n              await userRepository.save(newUser);\n              createdUsers.push(newUser);\n            }\n          }\n        }\n      }\n\n      return res.status(201).json(User.filterMany(createdUsers));\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nrouter.post(\n  '/import-from-jellyfin',\n  isAuthenticated(Permission.MANAGE_USERS),\n  async (req, res, next) => {\n    try {\n      const settings = getSettings();\n      const userRepository = getRepository(User);\n      const body = req.body as { jellyfinUserIds: string[] };\n\n      // taken from auth.ts\n      const admin = await userRepository.findOneOrFail({\n        where: { id: 1 },\n        select: ['id', 'jellyfinDeviceId', 'jellyfinUserId'],\n        order: { id: 'ASC' },\n      });\n\n      const hostname = getHostname();\n      const jellyfinClient = new JellyfinAPI(\n        hostname,\n        settings.jellyfin.apiKey,\n        admin.jellyfinDeviceId ?? ''\n      );\n      jellyfinClient.setUserId(admin.jellyfinUserId ?? '');\n\n      //const jellyfinUsersResponse = await jellyfinClient.getUsers();\n      const createdUsers: User[] = [];\n\n      jellyfinClient.setUserId(admin.jellyfinUserId ?? '');\n      const jellyfinUsers = await jellyfinClient.getUsers();\n\n      const jellyfinUsersById = new Map(\n        jellyfinUsers.users.map((user) => [\n          normalizeJellyfinGuid(user.Id),\n          user,\n        ])\n      );\n\n      for (const rawJellyfinUserId of body.jellyfinUserIds) {\n        const jellyfinUserId = normalizeJellyfinGuid(rawJellyfinUserId);\n        if (!jellyfinUserId) {\n          continue;\n        }\n\n        const jellyfinUser = jellyfinUsersById.get(jellyfinUserId);\n\n        const user = await userRepository.findOne({\n          select: ['id', 'jellyfinUserId'],\n          where: { jellyfinUserId: jellyfinUserId },\n        });\n\n        if (!user) {\n          const newUser = new User({\n            jellyfinUsername: jellyfinUser?.Name,\n            jellyfinUserId: jellyfinUser?.Id,\n            jellyfinDeviceId: Buffer.from(\n              `BOT_seerr_${jellyfinUser?.Name ?? ''}`\n            ).toString('base64'),\n            email: jellyfinUser?.Name,\n            permissions: settings.main.defaultPermissions,\n            avatar: `/avatarproxy/${jellyfinUser?.Id}`,\n            userType:\n              settings.main.mediaServerType === MediaServerType.JELLYFIN\n                ? UserType.JELLYFIN\n                : UserType.EMBY,\n          });\n\n          await userRepository.save(newUser);\n          createdUsers.push(newUser);\n        }\n      }\n      return res.status(201).json(User.filterMany(createdUsers));\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nrouter.get<{ id: string }, QuotaResponse>(\n  '/:id/quota',\n  async (req, res, next) => {\n    try {\n      const userRepository = getRepository(User);\n\n      if (\n        Number(req.params.id) !== req.user?.id &&\n        !req.user?.hasPermission(\n          [Permission.MANAGE_USERS, Permission.MANAGE_REQUESTS],\n          { type: 'and' }\n        )\n      ) {\n        return next({\n          status: 403,\n          message:\n            \"You do not have permission to view this user's request limits.\",\n        });\n      }\n\n      const user = await userRepository.findOneOrFail({\n        where: { id: Number(req.params.id) },\n      });\n\n      const quotas = await user.getQuota();\n\n      return res.status(200).json(quotas);\n    } catch (e) {\n      next({ status: 404, message: e.message });\n    }\n  }\n);\n\nrouter.get<{ id: string }, UserWatchDataResponse>(\n  '/:id/watch_data',\n  isOwnProfileOrAdmin(),\n  async (req, res, next) => {\n    const settings = getSettings().tautulli;\n\n    if (!settings.hostname || !settings.port || !settings.apiKey) {\n      return next({\n        status: 404,\n        message: 'Tautulli API not configured.',\n      });\n    }\n\n    try {\n      const user = await getRepository(User).findOneOrFail({\n        where: { id: Number(req.params.id) },\n        select: { id: true, plexId: true },\n      });\n\n      const tautulli = new TautulliAPI(settings);\n\n      const watchStats = await tautulli.getUserWatchStats(user);\n      const watchHistory = await tautulli.getUserWatchHistory(user);\n\n      const recentlyWatched = sortBy(\n        await getRepository(Media).find({\n          where: [\n            {\n              mediaType: MediaType.MOVIE,\n              ratingKey: In(\n                watchHistory\n                  .filter((record) => record.media_type === 'movie')\n                  .map((record) => record.rating_key)\n              ),\n            },\n            {\n              mediaType: MediaType.MOVIE,\n              ratingKey4k: In(\n                watchHistory\n                  .filter((record) => record.media_type === 'movie')\n                  .map((record) => record.rating_key)\n              ),\n            },\n            {\n              mediaType: MediaType.TV,\n              ratingKey: In(\n                watchHistory\n                  .filter((record) => record.media_type === 'episode')\n                  .map((record) => record.grandparent_rating_key)\n              ),\n            },\n            {\n              mediaType: MediaType.TV,\n              ratingKey4k: In(\n                watchHistory\n                  .filter((record) => record.media_type === 'episode')\n                  .map((record) => record.grandparent_rating_key)\n              ),\n            },\n          ],\n        }),\n        [\n          (media) =>\n            findIndex(\n              watchHistory,\n              (record) =>\n                (!!media.ratingKey &&\n                  parseInt(media.ratingKey) ===\n                    (record.media_type === 'movie'\n                      ? record.rating_key\n                      : record.grandparent_rating_key)) ||\n                (!!media.ratingKey4k &&\n                  parseInt(media.ratingKey4k) ===\n                    (record.media_type === 'movie'\n                      ? record.rating_key\n                      : record.grandparent_rating_key))\n            ),\n        ]\n      );\n\n      return res.status(200).json({\n        recentlyWatched,\n        playCount: watchStats.total_plays,\n      });\n    } catch (e) {\n      logger.error('Something went wrong fetching user watch data', {\n        label: 'API',\n        errorMessage: e.message,\n        userId: req.params.id,\n      });\n      next({\n        status: 500,\n        message: 'Failed to fetch user watch data.',\n      });\n    }\n  }\n);\n\nrouter.get<{ id: string }, WatchlistResponse>(\n  '/:id/watchlist',\n  async (req, res, next) => {\n    if (\n      Number(req.params.id) !== req.user?.id &&\n      !req.user?.hasPermission(\n        [Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],\n        {\n          type: 'or',\n        }\n      )\n    ) {\n      return next({\n        status: 403,\n        message: \"You do not have permission to view this user's Watchlist.\",\n      });\n    }\n\n    const itemsPerPage = 20;\n    const page = req.query.page ? Number(req.query.page) : 1;\n    const offset = (page - 1) * itemsPerPage;\n\n    const user = await getRepository(User).findOneOrFail({\n      where: { id: Number(req.params.id) },\n      select: ['id', 'plexToken'],\n    });\n\n    if (user) {\n      const [result, total] = await getRepository(Watchlist).findAndCount({\n        where: { requestedBy: { id: user?.id } },\n        relations: {\n          /*requestedBy: true,media:true*/\n        },\n        // loadRelationIds: true,\n        take: itemsPerPage,\n        skip: offset,\n      });\n      if (total) {\n        return res.json({\n          page: page,\n          totalPages: Math.ceil(total / itemsPerPage),\n          totalResults: total,\n          results: result,\n        });\n      }\n    }\n\n    // We will just return an empty array if the user has no Plex token\n    if (!user.plexToken) {\n      return res.json({\n        page: 1,\n        totalPages: 1,\n        totalResults: 0,\n        results: [],\n      });\n    }\n\n    const plexTV = new PlexTvAPI(user.plexToken);\n\n    const watchlist = await plexTV.getWatchlist({ offset });\n\n    return res.json({\n      page,\n      totalPages: Math.ceil(watchlist.totalSize / itemsPerPage),\n      totalResults: watchlist.totalSize,\n      results: watchlist.items.map((item) => ({\n        id: item.tmdbId,\n        ratingKey: item.ratingKey,\n        title: item.title,\n        mediaType: item.type === 'show' ? 'tv' : 'movie',\n        tmdbId: item.tmdbId,\n      })),\n    });\n  }\n);\n\nexport default router;\n"
  },
  {
    "path": "server/routes/user/usersettings.ts",
    "content": "import JellyfinAPI from '@server/api/jellyfin';\nimport PlexTvAPI from '@server/api/plextv';\nimport { ApiErrorCode } from '@server/constants/error';\nimport { MediaServerType } from '@server/constants/server';\nimport { UserType } from '@server/constants/user';\nimport { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport { UserSettings } from '@server/entity/UserSettings';\nimport type {\n  UserSettingsGeneralResponse,\n  UserSettingsNotificationsResponse,\n} from '@server/interfaces/api/userSettingsInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { isAuthenticated } from '@server/middleware/auth';\nimport { ApiError } from '@server/types/error';\nimport { getHostname } from '@server/utils/getHostname';\nimport {\n  isOwnProfile,\n  isOwnProfileOrAdmin,\n} from '@server/utils/profileMiddleware';\nimport { Router } from 'express';\nimport net from 'net';\nimport { Not } from 'typeorm';\nimport { canMakePermissionsChange } from '.';\n\nconst userSettingsRoutes = Router({ mergeParams: true });\n\nuserSettingsRoutes.get<{ id: string }, UserSettingsGeneralResponse>(\n  '/main',\n  isOwnProfileOrAdmin(),\n  async (req, res, next) => {\n    const {\n      main: { defaultQuotas },\n    } = getSettings();\n    const userRepository = getRepository(User);\n\n    try {\n      const user = await userRepository.findOne({\n        where: { id: Number(req.params.id) },\n      });\n\n      if (!user) {\n        return next({ status: 404, message: 'User not found.' });\n      }\n\n      return res.status(200).json({\n        username: user.username,\n        email: user.email,\n        discordId: user.settings?.discordId,\n        locale: user.settings?.locale,\n        discoverRegion: user.settings?.discoverRegion,\n        streamingRegion: user.settings?.streamingRegion,\n        originalLanguage: user.settings?.originalLanguage,\n        movieQuotaLimit: user.movieQuotaLimit,\n        movieQuotaDays: user.movieQuotaDays,\n        tvQuotaLimit: user.tvQuotaLimit,\n        tvQuotaDays: user.tvQuotaDays,\n        globalMovieQuotaDays: defaultQuotas.movie.quotaDays,\n        globalMovieQuotaLimit: defaultQuotas.movie.quotaLimit,\n        globalTvQuotaDays: defaultQuotas.tv.quotaDays,\n        globalTvQuotaLimit: defaultQuotas.tv.quotaLimit,\n        watchlistSyncMovies: user.settings?.watchlistSyncMovies,\n        watchlistSyncTv: user.settings?.watchlistSyncTv,\n      });\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nuserSettingsRoutes.post<\n  { id: string },\n  UserSettingsGeneralResponse,\n  UserSettingsGeneralResponse\n>('/main', isOwnProfileOrAdmin(), async (req, res, next) => {\n  const userRepository = getRepository(User);\n\n  try {\n    const user = await userRepository.findOne({\n      where: { id: Number(req.params.id) },\n    });\n\n    if (!user) {\n      return next({ status: 404, message: 'User not found.' });\n    }\n\n    // \"Owner\" user settings cannot be modified by other users\n    if (user.id === 1 && req.user?.id !== 1) {\n      return next({\n        status: 403,\n        message: \"You do not have permission to modify this user's settings.\",\n      });\n    }\n\n    const oldEmail = user.email;\n    user.username = req.body.username;\n    if (user.userType !== UserType.PLEX) {\n      user.email = req.body.email || user.jellyfinUsername || user.email;\n    }\n\n    const existingUser = await userRepository.findOne({\n      where: { email: user.email, id: Not(user.id) },\n    });\n\n    if (oldEmail !== user.email && existingUser) {\n      throw new ApiError(400, ApiErrorCode.InvalidEmail);\n    }\n\n    // Update quota values only if the user has the correct permissions\n    if (\n      !user.hasPermission(Permission.MANAGE_USERS) &&\n      req.user?.id !== user.id\n    ) {\n      user.movieQuotaDays = req.body.movieQuotaDays;\n      user.movieQuotaLimit = req.body.movieQuotaLimit;\n      user.tvQuotaDays = req.body.tvQuotaDays;\n      user.tvQuotaLimit = req.body.tvQuotaLimit;\n    }\n\n    if (!user.settings) {\n      user.settings = new UserSettings({\n        user: req.user,\n        discordId: req.body.discordId,\n        locale: req.body.locale,\n        discoverRegion: req.body.discoverRegion,\n        streamingRegion: req.body.streamingRegion,\n        originalLanguage: req.body.originalLanguage,\n        watchlistSyncMovies: req.body.watchlistSyncMovies,\n        watchlistSyncTv: req.body.watchlistSyncTv,\n      });\n    } else {\n      user.settings.discordId = req.body.discordId;\n      user.settings.locale = req.body.locale;\n      user.settings.discoverRegion = req.body.discoverRegion;\n      user.settings.streamingRegion = req.body.streamingRegion;\n      user.settings.originalLanguage = req.body.originalLanguage;\n      user.settings.watchlistSyncMovies = req.body.watchlistSyncMovies;\n      user.settings.watchlistSyncTv = req.body.watchlistSyncTv;\n    }\n\n    const savedUser = await userRepository.save(user);\n\n    return res.status(200).json({\n      username: savedUser.username,\n      discordId: savedUser.settings?.discordId,\n      locale: savedUser.settings?.locale,\n      discoverRegion: savedUser.settings?.discoverRegion,\n      streamingRegion: savedUser.settings?.streamingRegion,\n      originalLanguage: savedUser.settings?.originalLanguage,\n      watchlistSyncMovies: savedUser.settings?.watchlistSyncMovies,\n      watchlistSyncTv: savedUser.settings?.watchlistSyncTv,\n      email: savedUser.email,\n    });\n  } catch (e) {\n    if (e.errorCode) {\n      return next({\n        status: e.statusCode,\n        message: e.errorCode,\n      });\n    }\n    return next({ status: 500, message: e.message });\n  }\n});\n\nuserSettingsRoutes.get<{ id: string }, { hasPassword: boolean }>(\n  '/password',\n  isOwnProfileOrAdmin(),\n  async (req, res, next) => {\n    const userRepository = getRepository(User);\n\n    try {\n      const user = await userRepository.findOne({\n        where: { id: Number(req.params.id) },\n        select: ['id', 'password'],\n      });\n\n      if (!user) {\n        return next({ status: 404, message: 'User not found.' });\n      }\n\n      return res.status(200).json({ hasPassword: !!user.password });\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nuserSettingsRoutes.post<\n  { id: string },\n  null,\n  { currentPassword?: string; newPassword: string }\n>('/password', isOwnProfileOrAdmin(), async (req, res, next) => {\n  const userRepository = getRepository(User);\n\n  try {\n    const user = await userRepository.findOne({\n      where: { id: Number(req.params.id) },\n    });\n\n    const userWithPassword = await userRepository.findOne({\n      select: ['id', 'password'],\n      where: { id: Number(req.params.id) },\n    });\n\n    if (!user || !userWithPassword) {\n      return next({ status: 404, message: 'User not found.' });\n    }\n\n    if (req.body.newPassword.length < 8) {\n      return next({\n        status: 400,\n        message: 'Password must be at least 8 characters.',\n      });\n    }\n\n    if (\n      (user.id === 1 && req.user?.id !== 1) ||\n      (user.hasPermission(Permission.ADMIN) &&\n        user.id !== req.user?.id &&\n        req.user?.id !== 1)\n    ) {\n      return next({\n        status: 403,\n        message: \"You do not have permission to modify this user's password.\",\n      });\n    }\n\n    // If the user has the permission to manage users and they are not\n    // editing themselves, we will just set the new password\n    if (\n      req.user?.hasPermission(Permission.MANAGE_USERS) &&\n      req.user?.id !== user.id\n    ) {\n      await user.setPassword(req.body.newPassword);\n      await userRepository.save(user);\n      logger.debug('Password overriden by user.', {\n        label: 'User Settings',\n        userEmail: user.email,\n        changingUser: req.user.email,\n      });\n      return res.status(204).send();\n    }\n\n    // If the user has a password, we need to check the currentPassword is correct\n    if (\n      user.password &&\n      (!req.body.currentPassword ||\n        !(await userWithPassword.passwordMatch(req.body.currentPassword)))\n    ) {\n      logger.debug(\n        'Attempt to change password for user failed. Invalid current password provided.',\n        { label: 'User Settings', userEmail: user.email }\n      );\n      return next({ status: 403, message: 'Current password is invalid.' });\n    }\n\n    await user.setPassword(req.body.newPassword);\n    await userRepository.save(user);\n\n    return res.status(204).send();\n  } catch (e) {\n    next({ status: 500, message: e.message });\n  }\n});\n\nuserSettingsRoutes.post<{ authToken: string }>(\n  '/linked-accounts/plex',\n  isOwnProfile(),\n  async (req, res) => {\n    const settings = getSettings();\n    const userRepository = getRepository(User);\n\n    if (!req.user) {\n      return res.status(404).json({ code: ApiErrorCode.Unauthorized });\n    }\n    // Make sure Plex login is enabled\n    if (settings.main.mediaServerType !== MediaServerType.PLEX) {\n      return res.status(500).json({ message: 'Plex login is disabled' });\n    }\n\n    // First we need to use this auth token to get the user's email from plex.tv\n    const plextv = new PlexTvAPI(req.body.authToken);\n    const account = await plextv.getUser();\n\n    // Do not allow linking of an already linked account\n    if (await userRepository.exist({ where: { plexId: account.id } })) {\n      return res.status(422).json({\n        message: 'This Plex account is already linked to a Seerr user',\n      });\n    }\n\n    const user = req.user;\n\n    // Emails do not match\n    if (user.email !== account.email) {\n      return res.status(422).json({\n        message:\n          'This Plex account is registered under a different email address.',\n      });\n    }\n\n    // valid plex user found, link to current user\n    user.userType = UserType.PLEX;\n    user.plexId = account.id;\n    user.plexUsername = account.username;\n    user.plexToken = account.authToken;\n    await userRepository.save(user);\n\n    return res.status(204).send();\n  }\n);\n\nuserSettingsRoutes.delete<{ id: string }>(\n  '/linked-accounts/plex',\n  isOwnProfileOrAdmin(),\n  async (req, res) => {\n    const settings = getSettings();\n    const userRepository = getRepository(User);\n\n    // Make sure Plex login is enabled\n    if (settings.main.mediaServerType !== MediaServerType.PLEX) {\n      return res.status(500).json({ message: 'Plex login is disabled' });\n    }\n\n    try {\n      const user = await userRepository\n        .createQueryBuilder('user')\n        .addSelect('user.password')\n        .where({\n          id: Number(req.params.id),\n        })\n        .getOne();\n\n      if (!user) {\n        return res.status(404).json({ message: 'User not found.' });\n      }\n\n      if (user.id === 1) {\n        return res.status(400).json({\n          message:\n            'Cannot unlink media server accounts for the primary administrator.',\n        });\n      }\n\n      if (!user.email || !user.password) {\n        return res.status(400).json({\n          message: 'User does not have a local email or password set.',\n        });\n      }\n\n      user.userType = UserType.LOCAL;\n      user.plexId = null;\n      user.plexUsername = null;\n      user.plexToken = null;\n      await userRepository.save(user);\n\n      return res.status(204).send();\n    } catch (e) {\n      return res.status(500).json({ message: e.message });\n    }\n  }\n);\n\nuserSettingsRoutes.post<{ username: string; password: string }>(\n  '/linked-accounts/jellyfin',\n  isOwnProfile(),\n  async (req, res) => {\n    const settings = getSettings();\n    const userRepository = getRepository(User);\n\n    if (!req.user) {\n      return res.status(401).json({ code: ApiErrorCode.Unauthorized });\n    }\n    // Make sure jellyfin login is enabled\n    if (\n      settings.main.mediaServerType !== MediaServerType.JELLYFIN &&\n      settings.main.mediaServerType !== MediaServerType.EMBY\n    ) {\n      return res\n        .status(500)\n        .json({ message: 'Jellyfin/Emby login is disabled' });\n    }\n\n    // Do not allow linking of an already linked account\n    if (\n      await userRepository.exist({\n        where: { jellyfinUsername: req.body.username },\n      })\n    ) {\n      return res.status(422).json({\n        message: 'The specified account is already linked to a Seerr user',\n      });\n    }\n\n    const hostname = getHostname();\n    const deviceId = Buffer.from(\n      req.user?.id === 1 ? 'BOT_seerr' : `BOT_seerr_${req.user.username ?? ''}`\n    ).toString('base64');\n\n    const jellyfinserver = new JellyfinAPI(hostname, undefined, deviceId);\n\n    const ip = req.ip;\n    let clientIp: string | undefined;\n    if (ip) {\n      if (net.isIPv4(ip)) {\n        clientIp = ip;\n      } else if (net.isIPv6(ip)) {\n        clientIp = ip.startsWith('::ffff:') ? ip.substring(7) : ip;\n      }\n    }\n\n    try {\n      const account = await jellyfinserver.login(\n        req.body.username,\n        req.body.password,\n        clientIp\n      );\n\n      // Do not allow linking of an already linked account\n      if (\n        await userRepository.exist({\n          where: { jellyfinUserId: account.User.Id },\n        })\n      ) {\n        return res.status(422).json({\n          message: 'The specified account is already linked to a Seerr user',\n        });\n      }\n\n      const user = req.user;\n\n      // valid jellyfin user found, link to current user\n      user.userType =\n        settings.main.mediaServerType === MediaServerType.EMBY\n          ? UserType.EMBY\n          : UserType.JELLYFIN;\n      user.jellyfinUserId = account.User.Id;\n      user.jellyfinUsername = account.User.Name;\n      user.jellyfinAuthToken = account.AccessToken;\n      user.jellyfinDeviceId = deviceId;\n      await userRepository.save(user);\n\n      return res.status(204).send();\n    } catch (e) {\n      logger.error('Failed to link account to user.', {\n        label: 'API',\n        ip: req.ip,\n        error: e,\n      });\n      if (\n        e instanceof ApiError &&\n        e.errorCode === ApiErrorCode.InvalidCredentials\n      ) {\n        return res.status(401).json({ code: e.errorCode });\n      }\n\n      return res.status(500).send();\n    }\n  }\n);\n\nuserSettingsRoutes.delete<{ id: string }>(\n  '/linked-accounts/jellyfin',\n  isOwnProfileOrAdmin(),\n  async (req, res) => {\n    const settings = getSettings();\n    const userRepository = getRepository(User);\n\n    // Make sure jellyfin login is enabled\n    if (\n      settings.main.mediaServerType !== MediaServerType.JELLYFIN &&\n      settings.main.mediaServerType !== MediaServerType.EMBY\n    ) {\n      return res\n        .status(500)\n        .json({ message: 'Jellyfin/Emby login is disabled' });\n    }\n\n    try {\n      const user = await userRepository\n        .createQueryBuilder('user')\n        .addSelect('user.password')\n        .where({\n          id: Number(req.params.id),\n        })\n        .getOne();\n\n      if (!user) {\n        return res.status(404).json({ message: 'User not found.' });\n      }\n\n      if (user.id === 1) {\n        return res.status(400).json({\n          message:\n            'Cannot unlink media server accounts for the primary administrator.',\n        });\n      }\n\n      if (!user.email || !user.password) {\n        return res.status(400).json({\n          message: 'User does not have a local email or password set.',\n        });\n      }\n\n      user.userType = UserType.LOCAL;\n      user.jellyfinUserId = null;\n      user.jellyfinUsername = null;\n      user.jellyfinAuthToken = null;\n      user.jellyfinDeviceId = null;\n      await userRepository.save(user);\n\n      return res.status(204).send();\n    } catch (e) {\n      return res.status(500).json({ message: e.message });\n    }\n  }\n);\n\nuserSettingsRoutes.get<{ id: string }, UserSettingsNotificationsResponse>(\n  '/notifications',\n  isOwnProfileOrAdmin(),\n  async (req, res, next) => {\n    const userRepository = getRepository(User);\n    const settings = getSettings()?.notifications.agents;\n\n    try {\n      const user = await userRepository.findOne({\n        where: { id: Number(req.params.id) },\n      });\n\n      if (!user) {\n        return next({ status: 404, message: 'User not found.' });\n      }\n\n      return res.status(200).json({\n        emailEnabled: settings.email.enabled,\n        pgpKey: user.settings?.pgpKey,\n        discordEnabled:\n          settings?.discord.enabled && settings.discord.options.enableMentions,\n        discordEnabledTypes:\n          settings?.discord.enabled && settings.discord.options.enableMentions\n            ? settings.discord.types\n            : 0,\n        discordId: user.settings?.discordId,\n        pushbulletAccessToken: user.settings?.pushbulletAccessToken,\n        pushoverApplicationToken: user.settings?.pushoverApplicationToken,\n        pushoverUserKey: user.settings?.pushoverUserKey,\n        pushoverSound: user.settings?.pushoverSound,\n        telegramEnabled: settings.telegram.enabled,\n        telegramBotUsername: settings.telegram.options.botUsername,\n        telegramChatId: user.settings?.telegramChatId,\n        telegramMessageThreadId: user.settings?.telegramMessageThreadId,\n        telegramSendSilently: user.settings?.telegramSendSilently,\n        webPushEnabled: settings.webpush.enabled,\n        notificationTypes: user.settings?.notificationTypes ?? {},\n      });\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nuserSettingsRoutes.post<{ id: string }, UserSettingsNotificationsResponse>(\n  '/notifications',\n  isOwnProfileOrAdmin(),\n  async (req, res, next) => {\n    const userRepository = getRepository(User);\n\n    try {\n      const user = await userRepository.findOne({\n        where: { id: Number(req.params.id) },\n      });\n\n      if (!user) {\n        return next({ status: 404, message: 'User not found.' });\n      }\n\n      // \"Owner\" user settings cannot be modified by other users\n      if (user.id === 1 && req.user?.id !== 1) {\n        return next({\n          status: 403,\n          message: \"You do not have permission to modify this user's settings.\",\n        });\n      }\n\n      if (!user.settings) {\n        user.settings = new UserSettings({\n          user: req.user,\n          pgpKey: req.body.pgpKey,\n          discordId: req.body.discordId,\n          pushbulletAccessToken: req.body.pushbulletAccessToken,\n          pushoverApplicationToken: req.body.pushoverApplicationToken,\n          pushoverUserKey: req.body.pushoverUserKey,\n          telegramChatId: req.body.telegramChatId,\n          telegramMessageThreadId: req.body.telegramMessageThreadId,\n          telegramSendSilently: req.body.telegramSendSilently,\n          notificationTypes: req.body.notificationTypes,\n        });\n      } else {\n        user.settings.pgpKey = req.body.pgpKey;\n        user.settings.discordId = req.body.discordId;\n        user.settings.pushbulletAccessToken = req.body.pushbulletAccessToken;\n        user.settings.pushoverApplicationToken =\n          req.body.pushoverApplicationToken;\n        user.settings.pushoverUserKey = req.body.pushoverUserKey;\n        user.settings.pushoverSound = req.body.pushoverSound;\n        user.settings.telegramChatId = req.body.telegramChatId;\n        user.settings.telegramMessageThreadId =\n          req.body.telegramMessageThreadId;\n        user.settings.telegramSendSilently = req.body.telegramSendSilently;\n        user.settings.notificationTypes = Object.assign(\n          {},\n          user.settings.notificationTypes,\n          req.body.notificationTypes\n        );\n      }\n\n      userRepository.save(user);\n\n      return res.status(200).json({\n        pgpKey: user.settings.pgpKey,\n        discordId: user.settings.discordId,\n        pushbulletAccessToken: user.settings.pushbulletAccessToken,\n        pushoverApplicationToken: user.settings.pushoverApplicationToken,\n        pushoverUserKey: user.settings.pushoverUserKey,\n        pushoverSound: user.settings.pushoverSound,\n        telegramChatId: user.settings.telegramChatId,\n        telegramMessageThreadId: user.settings.telegramMessageThreadId,\n        telegramSendSilently: user.settings.telegramSendSilently,\n        notificationTypes: user.settings.notificationTypes,\n      });\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nuserSettingsRoutes.get<{ id: string }, { permissions?: number }>(\n  '/permissions',\n  isAuthenticated(Permission.MANAGE_USERS),\n  async (req, res, next) => {\n    const userRepository = getRepository(User);\n\n    try {\n      const user = await userRepository.findOne({\n        where: { id: Number(req.params.id) },\n      });\n\n      if (!user) {\n        return next({ status: 404, message: 'User not found.' });\n      }\n\n      return res.status(200).json({ permissions: user.permissions });\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nuserSettingsRoutes.post<\n  { id: string },\n  { permissions?: number },\n  { permissions: number }\n>(\n  '/permissions',\n  isAuthenticated(Permission.MANAGE_USERS),\n  async (req, res, next) => {\n    const userRepository = getRepository(User);\n\n    try {\n      const user = await userRepository.findOne({\n        where: { id: Number(req.params.id) },\n      });\n\n      if (!user) {\n        return next({ status: 404, message: 'User not found.' });\n      }\n\n      // \"Owner\" user permissions cannot be modified, and users cannot set their own permissions\n      if (user.id === 1 || req.user?.id === user.id) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to modify this user',\n        });\n      }\n\n      if (!canMakePermissionsChange(req.body.permissions, req.user)) {\n        return next({\n          status: 403,\n          message: 'You do not have permission to grant this level of access',\n        });\n      }\n      user.permissions = req.body.permissions;\n\n      await userRepository.save(user);\n\n      return res.status(200).json({ permissions: user.permissions });\n    } catch (e) {\n      next({ status: 500, message: e.message });\n    }\n  }\n);\n\nexport default userSettingsRoutes;\n"
  },
  {
    "path": "server/routes/watchlist.ts",
    "content": "import {\n  DuplicateWatchlistRequestError,\n  NotFoundError,\n  Watchlist,\n} from '@server/entity/Watchlist';\nimport logger from '@server/logger';\nimport { Router } from 'express';\nimport { QueryFailedError } from 'typeorm';\n\nimport { MediaType } from '@server/constants/media';\nimport { watchlistCreate } from '@server/interfaces/api/watchlistCreate';\n\nconst watchlistRoutes = Router();\n\nwatchlistRoutes.post<never, Watchlist, Watchlist>(\n  '/',\n  async (req, res, next) => {\n    try {\n      if (!req.user) {\n        return next({\n          status: 401,\n          message: 'You must be logged in to add watchlist.',\n        });\n      }\n      const values = watchlistCreate.parse(req.body);\n\n      const request = await Watchlist.createWatchlist({\n        watchlistRequest: values,\n        user: req.user,\n      });\n      return res.status(201).json(request);\n    } catch (error) {\n      if (!(error instanceof Error)) {\n        return;\n      }\n      switch (error.constructor) {\n        case QueryFailedError:\n          logger.warn('Something wrong with data watchlist', {\n            tmdbId: req.body.tmdbId,\n            mediaType: req.body.mediaType,\n            label: 'Watchlist',\n          });\n          return next({ status: 409, message: 'Something wrong' });\n        case DuplicateWatchlistRequestError:\n          return next({ status: 409, message: error.message });\n        default:\n          return next({ status: 500, message: error.message });\n      }\n    }\n  }\n);\n\nwatchlistRoutes.delete('/:tmdbId', async (req, res, next) => {\n  if (!req.user) {\n    return next({\n      status: 401,\n      message: 'You must be logged in to delete watchlist data.',\n    });\n  }\n  try {\n    const mediaType = req.query.mediaType;\n    if (mediaType !== MediaType.MOVIE && mediaType !== MediaType.TV) {\n      return next({\n        status: 400,\n        message: 'Invalid mediaType query parameter.',\n      });\n    }\n\n    await Watchlist.deleteWatchlist(\n      Number(req.params.tmdbId),\n      mediaType,\n      req.user\n    );\n    return res.status(204).send();\n  } catch (e) {\n    if (e instanceof NotFoundError) {\n      return next({\n        status: 404,\n        message: e.message,\n      });\n    }\n    return next({ status: 500, message: e.message });\n  }\n});\n\nexport default watchlistRoutes;\n"
  },
  {
    "path": "server/scripts/prepareTestDb.ts",
    "content": "import { seedTestDb } from '@server/utils/seedTestDb';\nimport { copyFileSync } from 'fs';\nimport path from 'path';\n\nconst prepareDb = async () => {\n  // Copy over test settings.json\n  copyFileSync(\n    path.join(__dirname, '../../cypress/config/settings.cypress.json'),\n    path.join(__dirname, '../../config/settings.json')\n  );\n\n  await seedTestDb({\n    preserveDb: process.env.PRESERVE_DB === 'true',\n    withMigrations: process.env.WITH_MIGRATIONS === 'true',\n  });\n};\n\nprepareDb();\n"
  },
  {
    "path": "server/subscriber/IssueCommentSubscriber.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport { IssueType, IssueTypeName } from '@server/constants/issue';\nimport { MediaType } from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport IssueComment from '@server/entity/IssueComment';\nimport Media from '@server/entity/Media';\nimport { User } from '@server/entity/User';\nimport notificationManager, { Notification } from '@server/lib/notifications';\nimport { Permission } from '@server/lib/permissions';\nimport logger from '@server/logger';\nimport { sortBy } from 'lodash';\nimport type { EntitySubscriberInterface, InsertEvent } from 'typeorm';\nimport { EventSubscriber } from 'typeorm';\n\n@EventSubscriber()\nexport class IssueCommentSubscriber implements EntitySubscriberInterface<IssueComment> {\n  public listenTo(): typeof IssueComment {\n    return IssueComment;\n  }\n\n  private async sendIssueCommentNotification(entity: IssueComment) {\n    let title: string;\n    let image: string;\n    const tmdb = new TheMovieDb();\n\n    try {\n      const issue = (\n        await getRepository(IssueComment).findOneOrFail({\n          where: { id: entity.id },\n          relations: { issue: true },\n        })\n      ).issue;\n\n      const createdBy = await getRepository(User).findOneOrFail({\n        where: { id: issue.createdBy.id },\n      });\n\n      const media = await getRepository(Media).findOneOrFail({\n        where: { id: issue.media.id },\n      });\n\n      if (media.mediaType === MediaType.MOVIE) {\n        const movie = await tmdb.getMovie({ movieId: media.tmdbId });\n\n        title = `${movie.title}${\n          movie.release_date ? ` (${movie.release_date.slice(0, 4)})` : ''\n        }`;\n        image = `https://image.tmdb.org/t/p/w600_and_h900_bestv2${movie.poster_path}`;\n      } else {\n        const tvshow = await tmdb.getTvShow({ tvId: media.tmdbId });\n\n        title = `${tvshow.name}${\n          tvshow.first_air_date ? ` (${tvshow.first_air_date.slice(0, 4)})` : ''\n        }`;\n        image = `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tvshow.poster_path}`;\n      }\n\n      const [firstComment] = sortBy(issue.comments, 'id');\n\n      if (entity.id !== firstComment.id) {\n        // Send notifications to all issue managers\n        notificationManager.sendNotification(Notification.ISSUE_COMMENT, {\n          event: `New Comment on ${\n            issue.issueType !== IssueType.OTHER\n              ? `${IssueTypeName[issue.issueType]} `\n              : ''\n          }Issue`,\n          subject: title,\n          message: firstComment.message,\n          comment: entity,\n          issue,\n          media,\n          image,\n          notifyAdmin: true,\n          notifySystem: true,\n          notifyUser:\n            !createdBy.hasPermission(Permission.MANAGE_ISSUES) &&\n            createdBy.id !== entity.user.id\n              ? createdBy\n              : undefined,\n        });\n      }\n    } catch (e) {\n      logger.error(\n        'Something went wrong sending issue comment notification(s)',\n        {\n          label: 'Notifications',\n          errorMessage: e.message,\n          commentId: entity.id,\n        }\n      );\n    }\n  }\n\n  public afterInsert(event: InsertEvent<IssueComment>): void {\n    if (!event.entity) {\n      return;\n    }\n\n    this.sendIssueCommentNotification(event.entity);\n  }\n}\n"
  },
  {
    "path": "server/subscriber/IssueSubscriber.ts",
    "content": "import TheMovieDb from '@server/api/themoviedb';\nimport { IssueStatus, IssueType, IssueTypeName } from '@server/constants/issue';\nimport { MediaType } from '@server/constants/media';\nimport Issue from '@server/entity/Issue';\nimport notificationManager, { Notification } from '@server/lib/notifications';\nimport { Permission } from '@server/lib/permissions';\nimport logger from '@server/logger';\nimport { sortBy } from 'lodash';\nimport type {\n  EntitySubscriberInterface,\n  InsertEvent,\n  UpdateEvent,\n} from 'typeorm';\nimport { EventSubscriber } from 'typeorm';\n\n@EventSubscriber()\nexport class IssueSubscriber implements EntitySubscriberInterface<Issue> {\n  public listenTo(): typeof Issue {\n    return Issue;\n  }\n\n  private async sendIssueNotification(entity: Issue, type: Notification) {\n    let title: string;\n    let image: string;\n    const tmdb = new TheMovieDb();\n\n    try {\n      if (entity.media.mediaType === MediaType.MOVIE) {\n        const movie = await tmdb.getMovie({ movieId: entity.media.tmdbId });\n\n        title = `${movie.title}${\n          movie.release_date ? ` (${movie.release_date.slice(0, 4)})` : ''\n        }`;\n        image = `https://image.tmdb.org/t/p/w600_and_h900_bestv2${movie.poster_path}`;\n      } else {\n        const tvshow = await tmdb.getTvShow({ tvId: entity.media.tmdbId });\n\n        title = `${tvshow.name}${\n          tvshow.first_air_date ? ` (${tvshow.first_air_date.slice(0, 4)})` : ''\n        }`;\n        image = `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tvshow.poster_path}`;\n      }\n\n      const [firstComment] = sortBy(entity.comments, 'id');\n      const extra: { name: string; value: string }[] = [];\n\n      if (entity.media.mediaType === MediaType.TV && entity.problemSeason > 0) {\n        extra.push({\n          name: 'Affected Season',\n          value: entity.problemSeason.toString(),\n        });\n\n        if (entity.problemEpisode > 0) {\n          extra.push({\n            name: 'Affected Episode',\n            value: entity.problemEpisode.toString(),\n          });\n        }\n      }\n\n      notificationManager.sendNotification(type, {\n        event:\n          type === Notification.ISSUE_CREATED\n            ? `New ${\n                entity.issueType !== IssueType.OTHER\n                  ? `${IssueTypeName[entity.issueType]} `\n                  : ''\n              }Issue Reported`\n            : type === Notification.ISSUE_RESOLVED\n              ? `${\n                  entity.issueType !== IssueType.OTHER\n                    ? `${IssueTypeName[entity.issueType]} `\n                    : ''\n                }Issue Resolved`\n              : `${\n                  entity.issueType !== IssueType.OTHER\n                    ? `${IssueTypeName[entity.issueType]} `\n                    : ''\n                }Issue Reopened`,\n        subject: title,\n        message: firstComment.message,\n        issue: entity,\n        media: entity.media,\n        image,\n        extra,\n        notifyAdmin: true,\n        notifySystem: true,\n        notifyUser:\n          !entity.createdBy.hasPermission(Permission.MANAGE_ISSUES) &&\n          entity.modifiedBy?.id !== entity.createdBy.id &&\n          (type === Notification.ISSUE_RESOLVED ||\n            type === Notification.ISSUE_REOPENED)\n            ? entity.createdBy\n            : undefined,\n      });\n    } catch (e) {\n      logger.error('Something went wrong sending issue notification(s)', {\n        label: 'Notifications',\n        errorMessage: e.message,\n        issueId: entity.id,\n      });\n    }\n  }\n\n  public afterInsert(event: InsertEvent<Issue>): void {\n    if (!event.entity) {\n      return;\n    }\n\n    this.sendIssueNotification(event.entity, Notification.ISSUE_CREATED);\n  }\n\n  public beforeUpdate(event: UpdateEvent<Issue>): void {\n    if (!event.entity) {\n      return;\n    }\n\n    if (\n      event.entity.status === IssueStatus.RESOLVED &&\n      event.databaseEntity.status !== IssueStatus.RESOLVED\n    ) {\n      this.sendIssueNotification(\n        event.entity as Issue,\n        Notification.ISSUE_RESOLVED\n      );\n    } else if (\n      event.entity.status === IssueStatus.OPEN &&\n      event.databaseEntity.status !== IssueStatus.OPEN\n    ) {\n      this.sendIssueNotification(\n        event.entity as Issue,\n        Notification.ISSUE_REOPENED\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "server/subscriber/MediaRequestSubscriber.ts",
    "content": "import type { RadarrMovieOptions } from '@server/api/servarr/radarr';\nimport RadarrAPI from '@server/api/servarr/radarr';\nimport type {\n  AddSeriesOptions,\n  SonarrSeries,\n} from '@server/api/servarr/sonarr';\nimport SonarrAPI from '@server/api/servarr/sonarr';\nimport TheMovieDb from '@server/api/themoviedb';\nimport { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants';\nimport {\n  MediaRequestStatus,\n  MediaStatus,\n  MediaType,\n} from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport { MediaRequest } from '@server/entity/MediaRequest';\nimport Season from '@server/entity/Season';\nimport SeasonRequest from '@server/entity/SeasonRequest';\nimport notificationManager, { Notification } from '@server/lib/notifications';\nimport { getSettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport { isEqual, truncate } from 'lodash';\nimport type {\n  EntityManager,\n  EntitySubscriberInterface,\n  InsertEvent,\n  RemoveEvent,\n  UpdateEvent,\n} from 'typeorm';\nimport { EventSubscriber, Not } from 'typeorm';\n\nconst sanitizeDisplayName = (displayName: string): string => {\n  return displayName\n    .normalize('NFD')\n    .replace(/[\\u0300-\\u036f]/g, '')\n    .replace(/\\s+/g, '-')\n    .replace(/[^a-z0-9-]/gi, '')\n    .replace(/-+/g, '-')\n    .replace(/^-|-$/g, '');\n};\n\n@EventSubscriber()\nexport class MediaRequestSubscriber implements EntitySubscriberInterface<MediaRequest> {\n  private async notifyAvailableMovie(\n    entity: MediaRequest,\n    event?: UpdateEvent<MediaRequest>\n  ) {\n    // Get fresh media state using event manager\n    let latestMedia: Media | null = null;\n    if (event?.manager) {\n      latestMedia = await event.manager.findOne(Media, {\n        where: { id: entity.media.id },\n      });\n    }\n    if (!latestMedia) {\n      const mediaRepository = getRepository(Media);\n      latestMedia = await mediaRepository.findOne({\n        where: { id: entity.media.id },\n      });\n    }\n\n    // Check availability using fresh media state\n    if (\n      !latestMedia ||\n      latestMedia[entity.is4k ? 'status4k' : 'status'] !== MediaStatus.AVAILABLE\n    ) {\n      return;\n    }\n\n    const tmdb = new TheMovieDb();\n\n    try {\n      const movie = await tmdb.getMovie({\n        movieId: entity.media.tmdbId,\n      });\n\n      notificationManager.sendNotification(Notification.MEDIA_AVAILABLE, {\n        event: `${entity.is4k ? '4K ' : ''}Movie Request Now Available`,\n        notifyAdmin: false,\n        notifySystem: true,\n        notifyUser: entity.requestedBy,\n        subject: `${movie.title}${\n          movie.release_date ? ` (${movie.release_date.slice(0, 4)})` : ''\n        }`,\n        message: truncate(movie.overview, {\n          length: 500,\n          separator: /\\s/,\n          omission: '…',\n        }),\n        media: latestMedia,\n        image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${movie.poster_path}`,\n        request: entity,\n      });\n    } catch (e) {\n      logger.error('Something went wrong sending media notification(s)', {\n        label: 'Notifications',\n        errorMessage: e.message,\n        mediaId: entity.id,\n      });\n    }\n  }\n\n  private async notifyAvailableSeries(\n    entity: MediaRequest,\n    event?: UpdateEvent<MediaRequest>\n  ) {\n    // Get fresh media state with seasons using event manager\n    let latestMedia: Media | null = null;\n    if (event?.manager) {\n      latestMedia = await event.manager.findOne(Media, {\n        where: { id: entity.media.id },\n        relations: { seasons: true },\n      });\n    }\n    if (!latestMedia) {\n      const mediaRepository = getRepository(Media);\n      latestMedia = await mediaRepository.findOne({\n        where: { id: entity.media.id },\n        relations: { seasons: true },\n      });\n    }\n\n    if (!latestMedia) {\n      return;\n    }\n\n    // Check availability using fresh media state\n    const requestedSeasons =\n      entity.seasons?.map((entitySeason) => entitySeason.seasonNumber) ?? [];\n    const availableSeasons = latestMedia.seasons.filter(\n      (season) =>\n        season[entity.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE &&\n        requestedSeasons.includes(season.seasonNumber)\n    );\n    const isMediaAvailable =\n      availableSeasons.length > 0 &&\n      availableSeasons.length === requestedSeasons.length;\n\n    if (!isMediaAvailable) {\n      return;\n    }\n\n    const tmdb = new TheMovieDb();\n\n    try {\n      const tv = await tmdb.getTvShow({ tvId: entity.media.tmdbId });\n\n      notificationManager.sendNotification(Notification.MEDIA_AVAILABLE, {\n        event: `${entity.is4k ? '4K ' : ''}Series Request Now Available`,\n        subject: `${tv.name}${\n          tv.first_air_date ? ` (${tv.first_air_date.slice(0, 4)})` : ''\n        }`,\n        message: truncate(tv.overview, {\n          length: 500,\n          separator: /\\s/,\n          omission: '…',\n        }),\n        notifyAdmin: false,\n        notifySystem: true,\n        notifyUser: entity.requestedBy,\n        image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tv.poster_path}`,\n        media: latestMedia,\n        extra: [\n          {\n            name: 'Requested Seasons',\n            value: entity.seasons\n              .map((season) => season.seasonNumber)\n              .join(', '),\n          },\n        ],\n        request: entity,\n      });\n    } catch (e) {\n      logger.error('Something went wrong sending media notification(s)', {\n        label: 'Notifications',\n        errorMessage: e.message,\n        mediaId: entity.id,\n      });\n    }\n  }\n\n  public async sendToRadarr(entity: MediaRequest): Promise<void> {\n    if (\n      entity.status === MediaRequestStatus.APPROVED &&\n      entity.type === MediaType.MOVIE\n    ) {\n      try {\n        const mediaRepository = getRepository(Media);\n        const settings = getSettings();\n        if (settings.radarr.length === 0 && !settings.radarr[0]) {\n          logger.info(\n            'No Radarr server configured, skipping request processing',\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n            }\n          );\n          return;\n        }\n\n        let radarrSettings = settings.radarr.find(\n          (radarr) => radarr.isDefault && radarr.is4k === entity.is4k\n        );\n\n        if (\n          entity.serverId !== null &&\n          entity.serverId >= 0 &&\n          radarrSettings?.id !== entity.serverId\n        ) {\n          radarrSettings = settings.radarr.find(\n            (radarr) => radarr.id === entity.serverId\n          );\n          logger.info(\n            `Request has an override server: ${radarrSettings?.name}`,\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n            }\n          );\n        }\n\n        if (!radarrSettings) {\n          logger.warn(\n            `There is no default ${\n              entity.is4k ? '4K ' : ''\n            }Radarr server configured. Did you set any of your ${\n              entity.is4k ? '4K ' : ''\n            }Radarr servers as default?`,\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n            }\n          );\n          return;\n        }\n\n        let rootFolder = radarrSettings.activeDirectory;\n        let qualityProfile = radarrSettings.activeProfileId;\n        let tags = radarrSettings.tags ? [...radarrSettings.tags] : [];\n\n        if (\n          entity.rootFolder &&\n          entity.rootFolder !== '' &&\n          entity.rootFolder !== radarrSettings.activeDirectory\n        ) {\n          rootFolder = entity.rootFolder;\n          logger.info(`Request has an override root folder: ${rootFolder}`, {\n            label: 'Media Request',\n            requestId: entity.id,\n            mediaId: entity.media.id,\n          });\n        }\n\n        if (\n          entity.profileId &&\n          entity.profileId !== radarrSettings.activeProfileId\n        ) {\n          qualityProfile = entity.profileId;\n          logger.info(\n            `Request has an override quality profile ID: ${qualityProfile}`,\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n            }\n          );\n        }\n\n        if (entity.tags && !isEqual(entity.tags, radarrSettings.tags)) {\n          tags = entity.tags;\n          logger.info(`Request has override tags`, {\n            label: 'Media Request',\n            requestId: entity.id,\n            mediaId: entity.media.id,\n            tagIds: tags,\n          });\n        }\n\n        const tmdb = new TheMovieDb();\n        const radarr = new RadarrAPI({\n          apiKey: radarrSettings.apiKey,\n          url: RadarrAPI.buildUrl(radarrSettings, '/api/v3'),\n        });\n        const movie = await tmdb.getMovie({ movieId: entity.media.tmdbId });\n\n        const media = await mediaRepository.findOne({\n          where: { id: entity.media.id },\n        });\n\n        if (!media) {\n          logger.error('Media data not found', {\n            label: 'Media Request',\n            requestId: entity.id,\n            mediaId: entity.media.id,\n          });\n          return;\n        }\n\n        if (radarrSettings.tagRequests) {\n          const radarrTags = await radarr.getTags();\n          // old tags had space around the hyphen\n          let userTag = radarrTags.find((v) =>\n            v.label.startsWith(entity.requestedBy.id + ' - ')\n          );\n          // new tags do not have spaces around the hyphen, since spaces are not allowed anymore\n          if (!userTag) {\n            userTag = radarrTags.find((v) =>\n              v.label.startsWith(entity.requestedBy.id + '-')\n            );\n          }\n          if (!userTag) {\n            logger.info(`Requester has no active tag. Creating new`, {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n              userId: entity.requestedBy.id,\n              newTag:\n                entity.requestedBy.id +\n                '-' +\n                sanitizeDisplayName(entity.requestedBy.displayName),\n            });\n            userTag = await radarr.createTag({\n              label:\n                entity.requestedBy.id +\n                '-' +\n                sanitizeDisplayName(entity.requestedBy.displayName),\n            });\n          }\n          if (userTag.id) {\n            if (!tags?.find((v) => v === userTag?.id)) {\n              tags?.push(userTag.id);\n            }\n          } else {\n            logger.warn(`Requester has no tag and failed to add one`, {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n              userId: entity.requestedBy.id,\n              radarrServer: radarrSettings.hostname + ':' + radarrSettings.port,\n            });\n          }\n        }\n\n        if (\n          media[entity.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE\n        ) {\n          logger.warn('Media already exists, marking request as COMPLETED', {\n            label: 'Media Request',\n            requestId: entity.id,\n            mediaId: entity.media.id,\n          });\n\n          const requestRepository = getRepository(MediaRequest);\n          entity.status = MediaRequestStatus.COMPLETED;\n          await requestRepository.save(entity);\n          return;\n        }\n\n        const radarrMovieOptions: RadarrMovieOptions = {\n          profileId: qualityProfile,\n          qualityProfileId: qualityProfile,\n          rootFolderPath: rootFolder,\n          minimumAvailability: radarrSettings.minimumAvailability,\n          title: movie.title,\n          tmdbId: movie.id,\n          year: Number(movie.release_date.slice(0, 4)),\n          monitored: true,\n          tags,\n          searchNow: !radarrSettings.preventSearch,\n        };\n\n        // Run entity asynchronously so we don't wait for it on the UI side\n        radarr\n          .addMovie(radarrMovieOptions)\n          .then(async (radarrMovie) => {\n            // We grab media again here to make sure we have the latest version of it\n            const media = await mediaRepository.findOne({\n              where: { id: entity.media.id },\n            });\n\n            if (!media) {\n              throw new Error('Media data not found');\n            }\n\n            media[entity.is4k ? 'externalServiceId4k' : 'externalServiceId'] =\n              radarrMovie.id;\n            media[\n              entity.is4k ? 'externalServiceSlug4k' : 'externalServiceSlug'\n            ] = radarrMovie.titleSlug;\n            media[entity.is4k ? 'serviceId4k' : 'serviceId'] =\n              radarrSettings?.id;\n            await mediaRepository.save(media);\n          })\n          .catch(async () => {\n            try {\n              const requestRepository = getRepository(MediaRequest);\n\n              if (entity.status !== MediaRequestStatus.FAILED) {\n                entity.status = MediaRequestStatus.FAILED;\n                await requestRepository.save(entity);\n              }\n            } catch (saveError) {\n              logger.error('Failed to mark request as FAILED', {\n                label: 'Media Request',\n                requestId: entity.id,\n                errorMessage:\n                  saveError instanceof Error\n                    ? saveError.message\n                    : String(saveError),\n              });\n            }\n\n            logger.warn(\n              'Something went wrong sending movie request to Radarr, marking status as FAILED',\n              {\n                label: 'Media Request',\n                requestId: entity.id,\n                mediaId: entity.media.id,\n                radarrMovieOptions,\n              }\n            );\n\n            MediaRequest.sendNotification(\n              entity,\n              media,\n              Notification.MEDIA_FAILED\n            );\n          })\n          .finally(() => {\n            radarr.clearCache({\n              tmdbId: movie.id,\n              externalId: entity.is4k\n                ? media.externalServiceId4k\n                : media.externalServiceId,\n            });\n          });\n        logger.info('Sent request to Radarr', {\n          label: 'Media Request',\n          requestId: entity.id,\n          mediaId: entity.media.id,\n        });\n      } catch (e) {\n        const requestRepository = getRepository(MediaRequest);\n        const mediaRepository = getRepository(Media);\n        const media = await mediaRepository.findOne({\n          where: { id: entity.media.id },\n        });\n\n        if (media) {\n          entity.status = MediaRequestStatus.FAILED;\n          await requestRepository.save(entity);\n\n          logger.warn(\n            'Failed to send movie request to Radarr due to connection or configuration error, marking status as FAILED',\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n              errorMessage: e.message,\n            }\n          );\n\n          MediaRequest.sendNotification(\n            entity,\n            media,\n            Notification.MEDIA_FAILED\n          );\n        }\n      }\n    }\n  }\n\n  public async sendToSonarr(entity: MediaRequest): Promise<void> {\n    if (\n      entity.status === MediaRequestStatus.APPROVED &&\n      entity.type === MediaType.TV\n    ) {\n      try {\n        const mediaRepository = getRepository(Media);\n        const settings = getSettings();\n        if (settings.sonarr.length === 0 && !settings.sonarr[0]) {\n          logger.warn(\n            'No Sonarr server configured, skipping request processing',\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n            }\n          );\n          return;\n        }\n\n        let sonarrSettings = settings.sonarr.find(\n          (sonarr) => sonarr.isDefault && sonarr.is4k === entity.is4k\n        );\n\n        if (\n          entity.serverId !== null &&\n          entity.serverId >= 0 &&\n          sonarrSettings?.id !== entity.serverId\n        ) {\n          sonarrSettings = settings.sonarr.find(\n            (sonarr) => sonarr.id === entity.serverId\n          );\n          logger.info(\n            `Request has an override server: ${sonarrSettings?.name}`,\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n            }\n          );\n        }\n\n        if (!sonarrSettings) {\n          logger.warn(\n            `There is no default ${\n              entity.is4k ? '4K ' : ''\n            }Sonarr server configured. Did you set any of your ${\n              entity.is4k ? '4K ' : ''\n            }Sonarr servers as default?`,\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n            }\n          );\n          return;\n        }\n\n        const media = await mediaRepository.findOne({\n          where: { id: entity.media.id },\n        });\n\n        if (!media) {\n          throw new Error('Media data not found');\n        }\n\n        if (\n          media[entity.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE\n        ) {\n          logger.warn('Media already exists, marking request as COMPLETED', {\n            label: 'Media Request',\n            requestId: entity.id,\n            mediaId: entity.media.id,\n          });\n\n          const requestRepository = getRepository(MediaRequest);\n          entity.status = MediaRequestStatus.COMPLETED;\n          entity.seasons.forEach((season) => {\n            season.status = MediaRequestStatus.COMPLETED;\n          });\n          await requestRepository.save(entity);\n          return;\n        }\n\n        const tmdb = new TheMovieDb();\n        const sonarr = new SonarrAPI({\n          apiKey: sonarrSettings.apiKey,\n          url: SonarrAPI.buildUrl(sonarrSettings, '/api/v3'),\n        });\n        const series = await tmdb.getTvShow({ tvId: media.tmdbId });\n        const tvdbId = series.external_ids.tvdb_id ?? media.tvdbId;\n\n        if (!tvdbId) {\n          const requestRepository = getRepository(MediaRequest);\n          await mediaRepository.remove(media);\n          await requestRepository.remove(entity);\n          throw new Error('TVDB ID not found');\n        }\n\n        let seriesType: SonarrSeries['seriesType'] = 'standard';\n\n        // Change series type to anime if the anime keyword is present on tmdb\n        if (\n          series.keywords.results.some(\n            (keyword) => keyword.id === ANIME_KEYWORD_ID\n          )\n        ) {\n          seriesType = sonarrSettings.animeSeriesType ?? 'anime';\n        }\n\n        let rootFolder =\n          seriesType === 'anime' && sonarrSettings.activeAnimeDirectory\n            ? sonarrSettings.activeAnimeDirectory\n            : sonarrSettings.activeDirectory;\n        let qualityProfile =\n          seriesType === 'anime' && sonarrSettings.activeAnimeProfileId\n            ? sonarrSettings.activeAnimeProfileId\n            : sonarrSettings.activeProfileId;\n        let languageProfile =\n          seriesType === 'anime' && sonarrSettings.activeAnimeLanguageProfileId\n            ? sonarrSettings.activeAnimeLanguageProfileId\n            : sonarrSettings.activeLanguageProfileId;\n        let tags =\n          seriesType === 'anime'\n            ? sonarrSettings.animeTags\n              ? [...sonarrSettings.animeTags]\n              : []\n            : sonarrSettings.tags\n              ? [...sonarrSettings.tags]\n              : [];\n\n        if (\n          entity.rootFolder &&\n          entity.rootFolder !== '' &&\n          entity.rootFolder !== rootFolder\n        ) {\n          rootFolder = entity.rootFolder;\n          logger.info(`Request has an override root folder: ${rootFolder}`, {\n            label: 'Media Request',\n            requestId: entity.id,\n            mediaId: entity.media.id,\n          });\n        }\n\n        if (entity.profileId && entity.profileId !== qualityProfile) {\n          qualityProfile = entity.profileId;\n          logger.info(\n            `Request has an override quality profile ID: ${qualityProfile}`,\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n            }\n          );\n        }\n\n        if (\n          entity.languageProfileId &&\n          entity.languageProfileId !== languageProfile\n        ) {\n          languageProfile = entity.languageProfileId;\n          logger.info(\n            `Request has an override language profile ID: ${languageProfile}`,\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n            }\n          );\n        }\n\n        if (entity.tags && !isEqual(entity.tags, tags)) {\n          tags = entity.tags;\n          logger.info(`Request has override tags`, {\n            label: 'Media Request',\n            requestId: entity.id,\n            mediaId: entity.media.id,\n            tagIds: tags,\n          });\n        }\n\n        if (sonarrSettings.tagRequests) {\n          const sonarrTags = await sonarr.getTags();\n          // old tags had space around the hyphen\n          let userTag = sonarrTags.find((v) =>\n            v.label.startsWith(entity.requestedBy.id + ' - ')\n          );\n          // new tags do not have spaces around the hyphen, since spaces are not allowed anymore\n          if (!userTag) {\n            userTag = sonarrTags.find((v) =>\n              v.label.startsWith(entity.requestedBy.id + '-')\n            );\n          }\n          if (!userTag) {\n            logger.info(`Requester has no active tag. Creating new`, {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n              userId: entity.requestedBy.id,\n              newTag:\n                entity.requestedBy.id +\n                '-' +\n                sanitizeDisplayName(entity.requestedBy.displayName),\n            });\n            userTag = await sonarr.createTag({\n              label:\n                entity.requestedBy.id +\n                '-' +\n                sanitizeDisplayName(entity.requestedBy.displayName),\n            });\n          }\n          if (userTag.id) {\n            if (!tags?.find((v) => v === userTag?.id)) {\n              tags?.push(userTag.id);\n            }\n          } else {\n            logger.warn(`Requester has no tag and failed to add one`, {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n              userId: entity.requestedBy.id,\n              sonarrServer: sonarrSettings.hostname + ':' + sonarrSettings.port,\n            });\n          }\n        }\n\n        const sonarrSeriesOptions: AddSeriesOptions = {\n          profileId: qualityProfile,\n          languageProfileId: languageProfile,\n          rootFolderPath: rootFolder,\n          title: series.name,\n          tvdbid: tvdbId,\n          seasons: entity.seasons.map((season) => season.seasonNumber),\n          seasonFolder: sonarrSettings.enableSeasonFolders,\n          seriesType,\n          tags,\n          monitored: true,\n          monitorNewItems: sonarrSettings.monitorNewItems,\n          searchNow: !sonarrSettings.preventSearch,\n        };\n\n        // Run entity asynchronously so we don't wait for it on the UI side\n        sonarr\n          .addSeries(sonarrSeriesOptions)\n          .then(async (sonarrSeries) => {\n            // We grab media again here to make sure we have the latest version of it\n            const media = await mediaRepository.findOne({\n              where: { id: entity.media.id },\n            });\n\n            if (!media) {\n              throw new Error('Media data not found');\n            }\n\n            media[entity.is4k ? 'externalServiceId4k' : 'externalServiceId'] =\n              sonarrSeries.id;\n            media[\n              entity.is4k ? 'externalServiceSlug4k' : 'externalServiceSlug'\n            ] = sonarrSeries.titleSlug;\n            media[entity.is4k ? 'serviceId4k' : 'serviceId'] =\n              sonarrSettings?.id;\n            await mediaRepository.save(media);\n          })\n          .catch(async () => {\n            try {\n              const requestRepository = getRepository(MediaRequest);\n\n              if (entity.status !== MediaRequestStatus.FAILED) {\n                entity.status = MediaRequestStatus.FAILED;\n                await requestRepository.save(entity);\n              }\n            } catch (saveError) {\n              logger.error('Failed to mark request as FAILED', {\n                label: 'Media Request',\n                requestId: entity.id,\n                errorMessage:\n                  saveError instanceof Error\n                    ? saveError.message\n                    : String(saveError),\n              });\n            }\n\n            logger.warn(\n              'Something went wrong sending series request to Sonarr, marking status as FAILED',\n              {\n                label: 'Media Request',\n                requestId: entity.id,\n                mediaId: entity.media.id,\n                sonarrSeriesOptions,\n              }\n            );\n\n            MediaRequest.sendNotification(\n              entity,\n              media,\n              Notification.MEDIA_FAILED\n            );\n          })\n          .finally(() => {\n            sonarr.clearCache({\n              tvdbId,\n              externalId: entity.is4k\n                ? media.externalServiceId4k\n                : media.externalServiceId,\n              title: series.name,\n            });\n          });\n        logger.info('Sent request to Sonarr', {\n          label: 'Media Request',\n          requestId: entity.id,\n          mediaId: entity.media.id,\n        });\n      } catch (e) {\n        const requestRepository = getRepository(MediaRequest);\n        const mediaRepository = getRepository(Media);\n        const media = await mediaRepository.findOne({\n          where: { id: entity.media.id },\n        });\n\n        if (media) {\n          entity.status = MediaRequestStatus.FAILED;\n          await requestRepository.save(entity);\n\n          logger.warn(\n            'Failed to send series request to Sonarr due to connection or configuration error, marking status as FAILED',\n            {\n              label: 'Media Request',\n              requestId: entity.id,\n              mediaId: entity.media.id,\n              errorMessage: e.message,\n            }\n          );\n\n          MediaRequest.sendNotification(\n            entity,\n            media,\n            Notification.MEDIA_FAILED\n          );\n        }\n      }\n    }\n  }\n\n  public async updateParentStatus(entity: MediaRequest): Promise<void> {\n    const mediaRepository = getRepository(Media);\n    const media = await mediaRepository.findOne({\n      where: { id: entity.media.id },\n    });\n    if (!media) {\n      logger.error('Media data not found', {\n        label: 'Media Request',\n        requestId: entity.id,\n        mediaId: entity.media.id,\n      });\n      return;\n    }\n\n    const statusKey = entity.is4k ? 'status4k' : 'status';\n    const seasonRequestRepository = getRepository(SeasonRequest);\n    const requestRepository = getRepository(MediaRequest);\n\n    if (\n      entity.status === MediaRequestStatus.APPROVED &&\n      // Do not update the status if the item is already partially available or available\n      media[statusKey] !== MediaStatus.AVAILABLE &&\n      media[statusKey] !== MediaStatus.PARTIALLY_AVAILABLE &&\n      media[statusKey] !== MediaStatus.PROCESSING\n    ) {\n      media[statusKey] = MediaStatus.PROCESSING;\n      await mediaRepository.save(media);\n    }\n\n    if (\n      media.mediaType === MediaType.MOVIE &&\n      entity.status === MediaRequestStatus.DECLINED &&\n      media[statusKey] !== MediaStatus.DELETED\n    ) {\n      media[statusKey] = MediaStatus.UNKNOWN;\n      await mediaRepository.save(media);\n    }\n\n    /**\n     * If the media type is TV, and we are declining a request,\n     * we must check if its the only pending request and that\n     * there the current media status is just pending (meaning no\n     * other requests have yet to be approved)\n     */\n    if (\n      media.mediaType === MediaType.TV &&\n      entity.status === MediaRequestStatus.DECLINED &&\n      media[statusKey] === MediaStatus.PENDING\n    ) {\n      const pendingCount = await requestRepository.count({\n        where: {\n          media: { id: media.id },\n          status: MediaRequestStatus.PENDING,\n          is4k: entity.is4k,\n          id: Not(entity.id),\n        },\n      });\n\n      if (pendingCount === 0) {\n        // Re-fetch media without requests to avoid cascade issues\n        const freshMedia = await mediaRepository.findOne({\n          where: { id: media.id },\n        });\n        if (freshMedia) {\n          freshMedia[statusKey] = MediaStatus.UNKNOWN;\n          await mediaRepository.save(freshMedia);\n        }\n      }\n    }\n\n    // Reset season statuses when a TV request is declined\n    if (\n      media.mediaType === MediaType.TV &&\n      entity.status === MediaRequestStatus.DECLINED\n    ) {\n      const seasonRepository = getRepository(Season);\n      const actualSeasons = await seasonRepository.find({\n        where: { media: { id: media.id } },\n      });\n\n      for (const seasonRequest of entity.seasons) {\n        seasonRequest.status = MediaRequestStatus.DECLINED;\n        await seasonRequestRepository.save(seasonRequest);\n\n        const season = actualSeasons.find(\n          (s) => s.seasonNumber === seasonRequest.seasonNumber\n        );\n\n        if (season && season[statusKey] === MediaStatus.PENDING) {\n          const otherActiveRequests = await requestRepository\n            .createQueryBuilder('request')\n            .leftJoinAndSelect('request.seasons', 'season')\n            .where('request.mediaId = :mediaId', { mediaId: media.id })\n            .andWhere('request.id != :requestId', { requestId: entity.id })\n            .andWhere('request.is4k = :is4k', { is4k: entity.is4k })\n            .andWhere('request.status NOT IN (:...statuses)', {\n              statuses: [\n                MediaRequestStatus.DECLINED,\n                MediaRequestStatus.COMPLETED,\n              ],\n            })\n            .andWhere('season.seasonNumber = :seasonNumber', {\n              seasonNumber: season.seasonNumber,\n            })\n            .getCount();\n\n          if (otherActiveRequests === 0) {\n            season[statusKey] = MediaStatus.UNKNOWN;\n            await seasonRepository.save(season);\n          }\n        }\n      }\n    }\n\n    // Approve child seasons if parent is approved\n    if (\n      media.mediaType === MediaType.TV &&\n      entity.status === MediaRequestStatus.APPROVED\n    ) {\n      entity.seasons.forEach((season) => {\n        season.status = MediaRequestStatus.APPROVED;\n        seasonRequestRepository.save(season);\n      });\n    }\n  }\n\n  public async handleRemoveParentUpdate(\n    manager: EntityManager,\n    entity: MediaRequest\n  ): Promise<void> {\n    const fullMedia = await manager.findOneOrFail(Media, {\n      where: { id: entity.media.id },\n      relations: { requests: true },\n    });\n\n    const needsStatusUpdate =\n      !fullMedia.requests.some((request) => !request.is4k) &&\n      fullMedia.status !== MediaStatus.AVAILABLE;\n\n    const needs4kStatusUpdate =\n      !fullMedia.requests.some((request) => request.is4k) &&\n      fullMedia.status4k !== MediaStatus.AVAILABLE;\n\n    if (needsStatusUpdate || needs4kStatusUpdate) {\n      // Re-fetch WITHOUT requests to avoid cascade issues on save\n      const cleanMedia = await manager.findOneOrFail(Media, {\n        where: { id: entity.media.id },\n      });\n\n      if (needsStatusUpdate) {\n        cleanMedia.status = MediaStatus.UNKNOWN;\n      }\n      if (needs4kStatusUpdate) {\n        cleanMedia.status4k = MediaStatus.UNKNOWN;\n      }\n\n      await manager.save(cleanMedia);\n    }\n  }\n\n  public async afterUpdate(event: UpdateEvent<MediaRequest>): Promise<void> {\n    if (!event.entity) {\n      return;\n    }\n\n    try {\n      await this.sendToRadarr(event.entity as MediaRequest);\n      await this.sendToSonarr(event.entity as MediaRequest);\n    } catch (e) {\n      logger.error('Error while sending to *arr in afterUpdate subscriber', {\n        label: 'Media Request',\n        requestId: (event.entity as MediaRequest).id,\n        errorMessage: e instanceof Error ? e.message : String(e),\n      });\n    }\n\n    try {\n      await this.updateParentStatus(event.entity as MediaRequest);\n\n      if (event.entity.status === MediaRequestStatus.COMPLETED) {\n        if (event.entity.media.mediaType === MediaType.MOVIE) {\n          await this.notifyAvailableMovie(event.entity as MediaRequest, event);\n        }\n        if (event.entity.media.mediaType === MediaType.TV) {\n          await this.notifyAvailableSeries(event.entity as MediaRequest, event);\n        }\n      }\n    } catch (e) {\n      logger.error(\n        'Error while updating parent status in afterUpdate subscriber',\n        {\n          label: 'Media Request',\n          requestId: (event.entity as MediaRequest).id,\n          errorMessage: e instanceof Error ? e.message : String(e),\n        }\n      );\n    }\n  }\n\n  public async afterInsert(event: InsertEvent<MediaRequest>): Promise<void> {\n    if (!event.entity) {\n      return;\n    }\n\n    try {\n      await this.sendToRadarr(event.entity as MediaRequest);\n      await this.sendToSonarr(event.entity as MediaRequest);\n    } catch (e) {\n      logger.error('Error while sending to *arr in afterInsert subscriber', {\n        label: 'Media Request',\n        requestId: (event.entity as MediaRequest).id,\n        errorMessage: e instanceof Error ? e.message : String(e),\n      });\n    }\n\n    try {\n      await this.updateParentStatus(event.entity as MediaRequest);\n    } catch (e) {\n      logger.error(\n        'Error while updating parent status in afterInsert subscriber',\n        {\n          label: 'Media Request',\n          requestId: (event.entity as MediaRequest).id,\n          errorMessage: e instanceof Error ? e.message : String(e),\n        }\n      );\n    }\n  }\n\n  public async afterRemove(event: RemoveEvent<MediaRequest>): Promise<void> {\n    if (!event.entity) {\n      return;\n    }\n\n    await this.handleRemoveParentUpdate(\n      event.manager as EntityManager,\n      event.entity as MediaRequest\n    );\n  }\n\n  public listenTo(): typeof MediaRequest {\n    return MediaRequest;\n  }\n}\n"
  },
  {
    "path": "server/subscriber/MediaSubscriber.ts",
    "content": "import {\n  MediaRequestStatus,\n  MediaStatus,\n  MediaType,\n} from '@server/constants/media';\nimport { getRepository } from '@server/datasource';\nimport Media from '@server/entity/Media';\nimport { MediaRequest } from '@server/entity/MediaRequest';\nimport Season from '@server/entity/Season';\nimport SeasonRequest from '@server/entity/SeasonRequest';\nimport type { EntitySubscriberInterface, UpdateEvent } from 'typeorm';\nimport { EventSubscriber, In } from 'typeorm';\n\n@EventSubscriber()\nexport class MediaSubscriber implements EntitySubscriberInterface<Media> {\n  private async updateChildRequestStatus(event: Media, is4k: boolean) {\n    const requestRepository = getRepository(MediaRequest);\n\n    const requests = await requestRepository.find({\n      where: { media: { id: event.id } },\n    });\n\n    for (const request of requests) {\n      if (\n        request.is4k === is4k &&\n        request.status === MediaRequestStatus.PENDING\n      ) {\n        request.status = MediaRequestStatus.APPROVED;\n        await requestRepository.save(request);\n      }\n    }\n  }\n\n  private async updateRelatedMediaRequest(\n    event: Media,\n    databaseEvent: Media,\n    is4k: boolean\n  ) {\n    const requestRepository = getRepository(MediaRequest);\n    const seasonRequestRepository = getRepository(SeasonRequest);\n\n    const relatedRequests = await requestRepository.find({\n      relations: {\n        media: true,\n      },\n      where: {\n        media: { id: event.id },\n        status: In([MediaRequestStatus.APPROVED, MediaRequestStatus.FAILED]),\n        is4k,\n      },\n    });\n\n    // Check the media entity status and if available\n    // or deleted, set the related request to completed\n    if (relatedRequests.length > 0) {\n      const completedRequests: MediaRequest[] = [];\n\n      for (const request of relatedRequests) {\n        let shouldComplete = false;\n\n        if (\n          (event[request.is4k ? 'status4k' : 'status'] ===\n            MediaStatus.AVAILABLE ||\n            event[request.is4k ? 'status4k' : 'status'] ===\n              MediaStatus.DELETED) &&\n          event.mediaType === MediaType.MOVIE\n        ) {\n          shouldComplete = true;\n        } else if (event.mediaType === 'tv') {\n          const allSeasonResults = await Promise.all(\n            request.seasons.map(async (requestSeason) => {\n              const matchingSeason = event.seasons.find(\n                (mediaSeason) =>\n                  mediaSeason.seasonNumber === requestSeason.seasonNumber\n              );\n              const matchingOldSeason = databaseEvent.seasons.find(\n                (oldSeason) =>\n                  oldSeason.seasonNumber === requestSeason.seasonNumber\n              );\n\n              if (!matchingSeason) {\n                return false;\n              }\n\n              const currentSeasonStatus =\n                matchingSeason[request.is4k ? 'status4k' : 'status'];\n              const previousSeasonStatus =\n                matchingOldSeason?.[request.is4k ? 'status4k' : 'status'];\n\n              const hasStatusChanged =\n                currentSeasonStatus !== previousSeasonStatus;\n\n              const shouldUpdate =\n                (hasStatusChanged ||\n                  requestSeason.status === MediaRequestStatus.COMPLETED) &&\n                (currentSeasonStatus === MediaStatus.AVAILABLE ||\n                  currentSeasonStatus === MediaStatus.DELETED);\n\n              if (shouldUpdate) {\n                requestSeason.status = MediaRequestStatus.COMPLETED;\n                await seasonRequestRepository.save(requestSeason);\n\n                return true;\n              }\n\n              return false;\n            })\n          );\n\n          const allSeasonsReady = allSeasonResults.every((result) => result);\n          shouldComplete = allSeasonsReady;\n        }\n\n        if (shouldComplete) {\n          request.status = MediaRequestStatus.COMPLETED;\n          completedRequests.push(request);\n        }\n      }\n\n      await requestRepository.save(completedRequests);\n    }\n  }\n\n  public async beforeUpdate(event: UpdateEvent<Media>): Promise<void> {\n    if (!event.entity) {\n      return;\n    }\n\n    if (\n      event.entity.status === MediaStatus.AVAILABLE &&\n      event.databaseEntity.status === MediaStatus.PENDING\n    ) {\n      this.updateChildRequestStatus(event.entity as Media, false);\n    }\n\n    if (\n      event.entity.status4k === MediaStatus.AVAILABLE &&\n      event.databaseEntity.status4k === MediaStatus.PENDING\n    ) {\n      this.updateChildRequestStatus(event.entity as Media, true);\n    }\n\n    // Manually load related seasons into databaseEntity\n    // for seasonStatusCheck in afterUpdate\n    const seasons = await event.manager\n      .getRepository(Season)\n      .createQueryBuilder('season')\n      .leftJoin('season.media', 'media')\n      .where('media.id = :id', { id: event.databaseEntity.id })\n      .getMany();\n\n    event.databaseEntity.seasons = seasons;\n  }\n\n  public async afterUpdate(event: UpdateEvent<Media>): Promise<void> {\n    if (!event.entity) {\n      return;\n    }\n\n    const validStatuses = [\n      MediaStatus.PARTIALLY_AVAILABLE,\n      MediaStatus.AVAILABLE,\n      MediaStatus.DELETED,\n    ];\n\n    const seasonStatusCheck = (is4k: boolean) => {\n      return event.entity?.seasons?.some((season: Season, index: number) => {\n        const previousSeason = event.databaseEntity.seasons[index];\n\n        return (\n          season[is4k ? 'status4k' : 'status'] !==\n          previousSeason?.[is4k ? 'status4k' : 'status']\n        );\n      });\n    };\n\n    if (\n      (event.entity.status !== event.databaseEntity?.status ||\n        (event.entity.mediaType === MediaType.TV &&\n          seasonStatusCheck(false))) &&\n      validStatuses.includes(event.entity.status)\n    ) {\n      this.updateRelatedMediaRequest(\n        event.entity as Media,\n        event.databaseEntity as Media,\n        false\n      );\n    }\n\n    if (\n      (event.entity.status4k !== event.databaseEntity?.status4k ||\n        (event.entity.mediaType === MediaType.TV && seasonStatusCheck(true))) &&\n      validStatuses.includes(event.entity.status4k)\n    ) {\n      this.updateRelatedMediaRequest(\n        event.entity as Media,\n        event.databaseEntity as Media,\n        true\n      );\n    }\n  }\n\n  public listenTo(): typeof Media {\n    return Media;\n  }\n}\n"
  },
  {
    "path": "server/templates/email/generatedpassword/html.pug",
    "content": "doctype html\nhead\n  meta(charset='utf-8')\n  meta(name='x-apple-disable-message-reformatting')\n  meta(http-equiv='x-ua-compatible' content='ie=edge')\n  meta(name='viewport' content='width=device-width, initial-scale=1')\n  meta(name='format-detection' content='telephone=no, date=no, address=no, email=no')\n  style.\n    .title:hover * {\n    text-decoration: underline;\n    }\n    @media only screen and (max-width:600px) {\n    table {\n    font-size: 20px !important;\n    width: 100% !important;\n    }\n    }\ndiv(style='display: block; background-color: #111827; padding: 2.5rem 0;')\n  table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Helvetica Neue\", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')\n    tr\n      td(style=\"text-align: center;\")\n        if applicationUrl\n          a(href=applicationUrl style='margin: 0 1rem;')\n            img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')\n        else\n          div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')\n            | #{applicationTitle}\n    if recipientName !== recipientEmail\n      tr\n        td(style='text-align: center;')\n          div(style='margin: 1rem 0 0; font-size: 1.25em;')\n            | Hi, #{recipientName.replace(/\\.|@/g, ((x) => x + '\\ufeff'))}!\n    tr\n      td(style='text-align: center;')\n        div(style='margin: 1rem 0 0; font-size: 1.25em;')\n          | An account has been created for you at #{applicationTitle}.\n    tr\n      td(style='text-align: center;')\n        div(style='margin: 1rem 0 0; font-size: 1.25em;')\n          | Your password is:\n        div(style='font-size: 1.25em; font-weight: 500; line-height: 2.25em;')\n          span(style='padding: 0.5rem; font-weight: 500; border: 1px solid rgb(100,100,100); font-family: monospace;')\n            | #{password}\n    if applicationUrl\n      tr\n        td\n          a(href=applicationUrl style='display: block; margin: 1.5rem 3rem 0; text-decoration: none; font-size: 1.0em; line-height: 2.25em;')\n            span(style='padding: 0.2rem; font-weight: 500; text-align: center; border-radius: 10px; background-color: rgb(99,102,241); color: #fff; display: block; border: 1px solid rgba(255,255,255,0.2);')\n              | Open #{applicationTitle}\n"
  },
  {
    "path": "server/templates/email/generatedpassword/subject.pug",
    "content": "!= `Account Information [${applicationTitle}]`\n"
  },
  {
    "path": "server/templates/email/media-issue/html.pug",
    "content": "doctype html\nhead\n  meta(charset='utf-8')\n  meta(name='x-apple-disable-message-reformatting')\n  meta(http-equiv='x-ua-compatible' content='ie=edge')\n  meta(name='viewport' content='width=device-width, initial-scale=1')\n  meta(name='format-detection' content='telephone=no, date=no, address=no, email=no')\n  style.\n    .title:hover * {\n    text-decoration: underline;\n    }\n    @media only screen and (max-width:600px) {\n    table {\n    font-size: 20px !important;\n    width: 100% !important;\n    }\n    }\ndiv(style='display: block; background-color: #111827; padding: 2.5rem 0;')\n  table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Helvetica Neue\", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')\n    tr\n      td(style=\"text-align: center;\")\n        if applicationUrl\n          a(href=applicationUrl style='margin: 0 1rem;')\n            img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')\n        else\n          div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')\n            | #{applicationTitle}\n    if recipientName !== recipientEmail\n      tr\n        td(style='text-align: center;')\n          div(style='margin: 1rem 0 0; font-size: 1.25em;')\n            | Hi, #{recipientName.replace(/\\.|@/g, ((x) => x + '\\ufeff'))}!\n    tr\n      td(style='text-align: center;')\n        div(style='margin: 1rem 0 0; font-size: 1.25em;')\n          | #{body}\n    if issueComment\n      tr\n        td(style='text-align: center;')\n          div(style='margin: 1rem 0 0; font-size: 1.25em;')\n            | #{issueComment}\n    else if issueDescription\n      tr\n        td(style='text-align: center;')\n          div(style='margin: 1rem 0 0; font-size: 1.25em;')\n            | #{issueDescription}\n    if actionUrl\n      tr\n        td\n          a(href=actionUrl style='display: block; margin: 1.5rem 3rem 0; text-decoration: none; font-size: 1.0em; line-height: 2.25em;')\n            span(style='padding: 0.2rem; font-weight: 500; text-align: center; border-radius: 10px; background-color: rgb(99,102,241); color: #fff; display: block; border: 1px solid rgba(255,255,255,0.2);')\n              | View Issue in #{applicationTitle}\n"
  },
  {
    "path": "server/templates/email/media-issue/subject.pug",
    "content": "!= `${event} - ${mediaName} [${applicationTitle}]`\n"
  },
  {
    "path": "server/templates/email/media-request/html.pug",
    "content": "doctype html\nhead\n  meta(charset='utf-8')\n  meta(name='x-apple-disable-message-reformatting')\n  meta(http-equiv='x-ua-compatible' content='ie=edge')\n  meta(name='viewport' content='width=device-width, initial-scale=1')\n  meta(name='format-detection' content='telephone=no, date=no, address=no, email=no')\n  style.\n    .title:hover * {\n    text-decoration: underline;\n    }\n    @media only screen and (max-width:600px) {\n    table {\n    font-size: 20px !important;\n    width: 100% !important;\n    }\n    }\ndiv(style='display: block; background-color: #111827; padding: 2.5rem 0;')\n  table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Helvetica Neue\", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')\n    tr\n      td(style=\"text-align: center;\")\n        if applicationUrl\n          a(href=applicationUrl style='margin: 0 1rem;')\n            img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')\n        else\n          div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')\n            | #{applicationTitle}\n    if recipientName !== recipientEmail\n      tr\n        td(style='text-align: center;')\n          div(style='margin: 1rem 0 0; font-size: 1.25em;')\n            | Hi, #{recipientName.replace(/\\.|@/g, ((x) => x + '\\ufeff'))}!\n    tr\n      td(style='text-align: center;')\n        div(style='margin: 1rem 0 0; font-size: 1.25em;')\n          | #{body}\n    tr\n      td\n        div(style='box-sizing: border-box; margin: 1.5rem 0 0; width: 100%; color: #fff; border-radius: .75rem; padding: 1rem; border: 1px solid rgb(100,100,100); background: linear-gradient(135deg, rgba(17,24,39,0.47) 0%, rgb(17,24,39) 75%), url(' + imageUrl + ') center 25%/cover')\n          table(style='color: #fff; width: 100%;')\n            tr\n              td(style='vertical-align: top;')\n                a(href=actionUrl style='display: block; max-width: 20rem; color: #fff; font-weight: 700; text-decoration: none; margin: 0 1rem 0.25rem 0; font-size: 1.3em; line-height: 1.25em; margin-bottom: 5px;' class='title')\n                  | #{mediaName}\n                div(style='overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #d1d5db; font-size: .975em; line-height: 1.45em; padding-top: .25rem; padding-bottom: .25rem;')\n                  span(style='display: block;')\n                    b(style='color: #9ca3af; font-weight: 700;')\n                      | Requested By&nbsp;\n                    | #{requestedBy.replace(/\\.|@/g, ((x) => x + '\\ufeff'))}\n                  each extra in mediaExtra\n                    span(style='display: block;')\n                      b(style='color: #9ca3af; font-weight: 700;')\n                        | #{extra.name}&nbsp;\n                      | #{extra.value}\n              if imageUrl\n                td(rowspan='2' style='width: 7rem;')\n                  a(style='display: block; width: 7rem; overflow: hidden; border-radius: .375rem;' href=actionUrl)\n                    div(style='overflow: hidden; box-sizing: border-box; margin: 0px;')\n                      img(alt='' src=imageUrl style='box-sizing: border-box; padding: 0px; border: none; margin: auto; display: block; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%;')\n            tr\n              td(style='font-size: .85em; color: #9ca3af; line-height: 1em; vertical-align: bottom; margin-right: 1rem')\n                span\n                  | #{timestamp}\n    if actionUrl\n      tr\n        td\n          a(href=actionUrl style='display: block; margin: 1.5rem 3rem 0; text-decoration: none; font-size: 1.0em; line-height: 2.25em;')\n            span(style='padding: 0.2rem; font-weight: 500; text-align: center; border-radius: 10px; background-color: rgb(99,102,241); color: #fff; display: block; border: 1px solid rgba(255,255,255,0.2);')\n              | View Media in #{applicationTitle}\n"
  },
  {
    "path": "server/templates/email/media-request/subject.pug",
    "content": "!= `${event} - ${mediaName} [${applicationTitle}]`\n"
  },
  {
    "path": "server/templates/email/resetpassword/html.pug",
    "content": "doctype html\nhead\n  meta(charset='utf-8')\n  meta(name='x-apple-disable-message-reformatting')\n  meta(http-equiv='x-ua-compatible' content='ie=edge')\n  meta(name='viewport' content='width=device-width, initial-scale=1')\n  meta(name='format-detection' content='telephone=no, date=no, address=no, email=no')\n  style.\n    .title:hover * {\n    text-decoration: underline;\n    }\n    @media only screen and (max-width:600px) {\n    table {\n    font-size: 20px !important;\n    width: 100% !important;\n    }\n    }\ndiv(style='display: block; background-color: #111827; padding: 2.5rem 0;')\n  table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Helvetica Neue\", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')\n    tr\n      td(style=\"text-align: center;\")\n        if applicationUrl\n          a(href=applicationUrl style='margin: 0 1rem;')\n            img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')\n        else\n          div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')\n            | #{applicationTitle}\n    if recipientName !== recipientEmail\n      tr\n        td(style='text-align: center;')\n          div(style='margin: 1rem 0 0; font-size: 1.25em;')\n            | Hi, #{recipientName.replace(/\\.|@/g, ((x) => x + '\\ufeff'))}!\n    tr\n      td(style='text-align: center;')\n        div(style='margin: 1rem 0 0; font-size: 1.25em;')\n          | A request has been received to change the password for your #{applicationTitle} account.\n    tr\n      td\n        a(href=resetPasswordLink style='display: block; margin: 1.5rem 3rem; text-decoration: none; font-size: 1.0em; line-height: 2.25em;')\n          span(style='padding: 0.2rem; font-weight: 500; text-align: center; border-radius: 10px; background-color: rgb(99,102,241); color: #fff; display: block; border: 1px solid rgba(255,255,255,0.2);')\n            | Reset Password\n    tr\n      td(style='text-align: center;')\n        div(style='margin: 1rem 0 0; font-size: 1.25em;')\n          | The above link will expire in 24 hours.\n    tr\n      td(style='text-align: center;')\n        div(style='margin: 1rem 1rem 0; font-size: 1.25em;')\n          | If you did not initiate this request, you may safely disregard this message."
  },
  {
    "path": "server/templates/email/resetpassword/subject.pug",
    "content": "!= `Password Reset [${applicationTitle}]`\n"
  },
  {
    "path": "server/templates/email/test-email/html.pug",
    "content": "doctype html\nhead\n  meta(charset='utf-8')\n  meta(name='x-apple-disable-message-reformatting')\n  meta(http-equiv='x-ua-compatible' content='ie=edge')\n  meta(name='viewport' content='width=device-width, initial-scale=1')\n  meta(name='format-detection' content='telephone=no, date=no, address=no, email=no')\n  style.\n    .title:hover * {\n    text-decoration: underline;\n    }\n    @media only screen and (max-width:600px) {\n    table {\n    font-size: 20px !important;\n    width: 100% !important;\n    }\n    }\ndiv(style='display: block; background-color: #111827; padding: 2.5rem 0;')\n  table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Helvetica Neue\", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')\n    tr\n      td(style=\"text-align: center;\")\n        if applicationUrl\n          a(href=applicationUrl style='margin: 0 1rem;')\n            img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')\n        else\n          div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')\n            | #{applicationTitle}\n    if recipientName !== recipientEmail\n      tr\n        td(style='text-align: center;')\n          div(style='margin: 1rem 0 0; font-size: 1.25em;')\n            | Hi, #{recipientName.replace(/\\.|@/g, ((x) => x + '\\ufeff'))}!\n    tr\n      td(style='text-align: center;')\n        div(style='margin: 1rem 0 0; font-size: 1.25em;')\n          | #{body}\n    if applicationUrl\n      tr\n        td\n          a(href=applicationUrl style='display: block; margin: 1.5rem 3rem 0; text-decoration: none; font-size: 1.0em; line-height: 2.25em;')\n            span(style='padding: 0.2rem; font-weight: 500; text-align: center; border-radius: 10px; background-color: rgb(99,102,241); color: #fff; display: block; border: 1px solid rgba(255,255,255,0.2);')\n              | Open #{applicationTitle}\n"
  },
  {
    "path": "server/templates/email/test-email/subject.pug",
    "content": "!= `Test Notification [${applicationTitle}]`\n"
  },
  {
    "path": "server/test/db.ts",
    "content": "import { resetTestDb, seedTestDb } from '@server/utils/seedTestDb';\nimport { before, beforeEach } from 'node:test';\n\nexport function setupTestDb() {\n  before(async () => {\n    await seedTestDb();\n  });\n  beforeEach(async () => {\n    await resetTestDb();\n  });\n}\n"
  },
  {
    "path": "server/test/index.mts",
    "content": "// Runs unit tests using the `node:test` runner.\n\nimport { Command, Option } from 'commander';\nimport { createWriteStream } from 'node:fs';\nimport { glob } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { run } from 'node:test';\nimport * as reporters from 'node:test/reporters';\nimport { fileURLToPath } from 'node:url';\n\nconst resolveImport = (specifier: string) =>\n  fileURLToPath(import.meta.resolve(specifier));\nconst BASE_DIR = join(import.meta.dirname, '../..');\n\nconst program = new Command();\nprogram\n  .name('test')\n  .argument('[file...]', 'Test file(s) to run (default: all)')\n  .option(\n    '-m, --test-name-pattern <pattern>',\n    'Run tests matching the given pattern',\n    (v, acc: string[]) => [...acc, v],\n    [] as string[]\n  )\n  .option(\n    '--test-reporter <reporter>',\n    'Test reporter to use (repeatable)',\n    (v, acc: string[]) => [...acc, v],\n    [] as string[]\n  )\n  .option(\n    '--test-reporter-destination <dest>',\n    'Test reporter destination: stdout, stderr, or a file path (repeatable)',\n    (v, acc: string[]) => [...acc, v],\n    [] as string[]\n  )\n  .option(\n    '--coverage, --experimental-test-coverage',\n    'Enable code coverage collection'\n  )\n  // ignore additional options passed by vscode test runner\n  .addOption(new Option('--test').hideHelp())\n  .parse();\n\nconst positionals: string[] = program.args;\nconst opts = program.opts<{\n  testNamePattern: string[];\n  testReporter: string[];\n  testReporterDestination: string[];\n  experimentalTestCoverage: boolean;\n}>();\n\nlet files: string[];\n\nif (positionals.length > 0) {\n  files = positionals.map((f) => resolve(f));\n} else {\n  files = [];\n  for await (const entry of glob(join(BASE_DIR, 'server/**/*.test.ts'))) {\n    files.push(resolve(entry));\n  }\n  files.sort();\n}\n\n// @ts-ignore\nprocess.env.NODE_ENV = 'test';\n// configure ts\nprocess.env.TS_NODE_PROJECT = resolveImport('../tsconfig.json');\nprocess.env.TS_NODE_FILES = 'true';\n\nconst stream = run({\n  files,\n  execArgv: [\n    '--experimental-test-module-mocks',\n    '-r',\n    'ts-node/register',\n    '-r',\n    'tsconfig-paths/register',\n    '-r',\n    resolveImport('./setup.ts'),\n  ],\n  coverage: opts.experimentalTestCoverage,\n  coverageExcludeGlobs: [\n    join(BASE_DIR, 'server/test/**'),\n    join(BASE_DIR, 'server/migration/**'),\n  ],\n  testNamePatterns: opts.testNamePattern,\n});\n\n// In CI, write a JUnit report to a file for use by GitHub\nif (process.env.CI) {\n  const reportStream = createWriteStream(join(BASE_DIR, 'report.xml'));\n  stream.compose(reporters.junit).pipe(reportStream);\n}\n\nif (opts.testReporter.length > 0) {\n  for (let i = 0; i < opts.testReporter.length; i++) {\n    const reporterName = opts.testReporter[i];\n    // check built-in reporters, otherwise import\n    const reporter =\n      reporterName in reporters\n        ? reporters[reporterName as keyof typeof reporters]\n        : await import(reporterName).then((m) => m.default);\n\n    if (reporter == null) {\n      console.error('Invalid test reporter: ', reporterName);\n      process.exit(1);\n    }\n\n    const destArg = opts.testReporterDestination[i];\n    const dest =\n      destArg === 'stdout' || destArg == null\n        ? process.stdout\n        : destArg === 'stderr'\n          ? process.stderr\n          : createWriteStream(destArg);\n\n    stream.compose(reporter).pipe(dest);\n  }\n} else {\n  stream.compose(reporters.spec).pipe(process.stdout);\n}\n"
  },
  {
    "path": "server/test/setup.ts",
    "content": "import logger from '@server/logger';\nimport { after, before } from 'node:test';\n\nbefore(() => {\n  if (process.env.VERBOSE != 'true') logger.silent = true;\n});\n\nafter(() => {\n  if (process.env.VERBOSE != 'true') logger.silent = false;\n});\n"
  },
  {
    "path": "server/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"commonjs\",\n    \"outDir\": \"../dist\",\n    \"noEmit\": false,\n    \"incremental\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@server/*\": [\"*\"]\n    }\n  },\n  \"include\": [\"**/*.ts\"]\n}\n"
  },
  {
    "path": "server/types/custom.d.ts",
    "content": "declare module '@dr.pogodin/csurf' {\n  import csrf from 'csurf';\n  export = csrf;\n}\n"
  },
  {
    "path": "server/types/error.ts",
    "content": "import type { ApiErrorCode } from '@server/constants/error';\n\nexport class ApiError extends Error {\n  constructor(\n    public statusCode: number,\n    public errorCode: ApiErrorCode\n  ) {\n    super();\n\n    this.name = 'apiError';\n  }\n}\n"
  },
  {
    "path": "server/types/express-session.d.ts",
    "content": "import 'express-session';\n\n// Declaration merging to apply our own types to SessionData\n// See: (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express-session/index.d.ts#L23)\ndeclare module 'express-session' {\n  interface SessionData {\n    userId: number;\n  }\n}\n"
  },
  {
    "path": "server/types/express.d.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unused-vars */\nimport type { User } from '@server/entity/User';\nimport type { NextFunction, Request, Response } from 'express';\nimport 'express-session';\n\ndeclare global {\n  namespace Express {\n    export interface Request {\n      user?: User;\n      locale?: string;\n    }\n  }\n\n  export type Middleware = <ParamsDictionary, any, any>(\n    req: Request,\n    res: Response,\n    next: NextFunction\n  ) => Promise<void | NextFunction> | void | NextFunction;\n}\n"
  },
  {
    "path": "server/types/languages.d.ts",
    "content": "export type AvailableLocale =\n  | 'ar'\n  | 'bg'\n  | 'ca'\n  | 'cs'\n  | 'da'\n  | 'de'\n  | 'en'\n  | 'el'\n  | 'es'\n  | 'es-MX'\n  | 'fi'\n  | 'fr'\n  | 'hr'\n  | 'he'\n  | 'hi'\n  | 'hu'\n  | 'it'\n  | 'ja'\n  | 'ko'\n  | 'lb'\n  | 'lt'\n  | 'nb-NO'\n  | 'nl'\n  | 'pl'\n  | 'pt-BR'\n  | 'pt-PT'\n  | 'ro'\n  | 'ru'\n  | 'sq'\n  | 'sr'\n  | 'sv'\n  | 'tr'\n  | 'uk'\n  | 'zh-CN'\n  | 'zh-TW'\n  | 'vi';\n"
  },
  {
    "path": "server/utils/DbColumnHelper.ts",
    "content": "import { isPgsql } from '@server/datasource';\nimport type { ColumnOptions, ColumnType } from 'typeorm';\nimport { Column } from 'typeorm';\nconst pgTypeMapping: { [key: string]: ColumnType } = {\n  datetime: 'timestamp with time zone',\n};\n\nexport function resolveDbType(pgType: ColumnType): ColumnType {\n  if (isPgsql && pgType.toString() in pgTypeMapping) {\n    return pgTypeMapping[pgType.toString()];\n  }\n  return pgType;\n}\n\nexport function DbAwareColumn(columnOptions: ColumnOptions) {\n  if (columnOptions.type) {\n    columnOptions.type = resolveDbType(columnOptions.type);\n  }\n  return Column(columnOptions);\n}\n"
  },
  {
    "path": "server/utils/appDataVolume.ts",
    "content": "import { accessSync, existsSync } from 'fs';\nimport path from 'path';\n\nconst CONFIG_PATH = process.env.CONFIG_DIRECTORY\n  ? process.env.CONFIG_DIRECTORY\n  : path.join(__dirname, '../../config');\n\nconst DOCKER_PATH = `${CONFIG_PATH}/DOCKER`;\n\nexport const appDataStatus = (): boolean => {\n  return !existsSync(DOCKER_PATH);\n};\n\nexport const appDataPath = (): string => {\n  return CONFIG_PATH;\n};\n\nexport const appDataPermissions = (): boolean => {\n  try {\n    accessSync(CONFIG_PATH);\n    return true;\n  } catch {\n    return false;\n  }\n};\n"
  },
  {
    "path": "server/utils/appVersion.ts",
    "content": "import logger from '@server/logger';\nimport { existsSync } from 'fs';\nimport path from 'path';\n\nconst COMMIT_TAG_PATH = path.join(__dirname, '../../committag.json');\nlet commitTag = 'local';\n\nif (existsSync(COMMIT_TAG_PATH)) {\n  // eslint-disable-next-line @typescript-eslint/no-require-imports\n  commitTag = require(COMMIT_TAG_PATH).commitTag;\n  logger.info(`Commit Tag: ${commitTag}`);\n}\n\nexport const getCommitTag = (): string => {\n  return commitTag;\n};\n\nexport const getAppVersion = (): string => {\n  // eslint-disable-next-line @typescript-eslint/no-require-imports\n  const { version } = require('../../package.json');\n\n  let finalVersion = version;\n\n  if (version === '0.1.0') {\n    finalVersion = `develop-${getCommitTag()}`;\n  }\n\n  return finalVersion;\n};\n"
  },
  {
    "path": "server/utils/asyncLock.ts",
    "content": "import { EventEmitter } from 'events';\n\n// whenever you need to run async code on tv show or movie that does \"get existing\" / \"check if need to create new\" / \"save\"\n// then you need to put all of that code in \"await asyncLock.dispatch\" callback based on media id\n// this will guarantee that only one part of code will run at the same for this media id to avoid code\n// trying to create two or more entries for same movie/tvshow (which would result in sqlite unique constraint failrue)\n\nclass AsyncLock {\n  private locked: { [key: string]: boolean } = {};\n  private ee = new EventEmitter();\n\n  constructor() {\n    this.ee.setMaxListeners(0);\n  }\n\n  private acquire = async (key: string) => {\n    return new Promise((resolve) => {\n      if (!this.locked[key]) {\n        this.locked[key] = true;\n        return resolve(undefined);\n      }\n\n      const nextAcquire = () => {\n        if (!this.locked[key]) {\n          this.locked[key] = true;\n          this.ee.removeListener(key, nextAcquire);\n          return resolve(undefined);\n        }\n      };\n\n      this.ee.on(key, nextAcquire);\n    });\n  };\n\n  private release = (key: string): void => {\n    delete this.locked[key];\n    setImmediate(() => this.ee.emit(key));\n  };\n\n  public dispatch = async (\n    key: string | number,\n    callback: () => Promise<void>\n  ) => {\n    const skey = String(key);\n    await this.acquire(skey);\n    try {\n      await callback();\n    } finally {\n      this.release(skey);\n    }\n  };\n}\n\nexport default AsyncLock;\n"
  },
  {
    "path": "server/utils/customProxyAgent.ts",
    "content": "import type { ProxySettings } from '@server/lib/settings';\nimport logger from '@server/logger';\nimport axios, { type InternalAxiosRequestConfig } from 'axios';\nimport { HttpProxyAgent } from 'http-proxy-agent';\nimport { HttpsProxyAgent } from 'https-proxy-agent';\nimport type { Dispatcher } from 'undici';\nimport { Agent, ProxyAgent, setGlobalDispatcher } from 'undici';\n\nexport let requestInterceptorFunction: (\n  config: InternalAxiosRequestConfig\n) => InternalAxiosRequestConfig;\n\nexport default async function createCustomProxyAgent(\n  proxySettings: ProxySettings,\n  forceIpv4First?: boolean\n) {\n  const defaultAgent = new Agent({\n    keepAliveTimeout: 5000,\n    connections: 50,\n    connect: forceIpv4First ? { family: 4 } : undefined,\n  });\n\n  const skipUrl = (url: string | URL) => {\n    const hostname =\n      typeof url === 'string' ? new URL(url).hostname : url.hostname;\n\n    if (proxySettings.bypassLocalAddresses && isLocalAddress(hostname)) {\n      return true;\n    }\n\n    for (const address of proxySettings.bypassFilter.split(',')) {\n      const trimmedAddress = address.trim();\n      if (!trimmedAddress) {\n        continue;\n      }\n\n      if (trimmedAddress.startsWith('*')) {\n        const domain = trimmedAddress.slice(1);\n        if (hostname.endsWith(domain)) {\n          return true;\n        }\n      } else if (hostname === trimmedAddress) {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  const noProxyInterceptor = (\n    dispatch: Dispatcher['dispatch']\n  ): Dispatcher['dispatch'] => {\n    return (opts, handler) => {\n      return opts.origin && skipUrl(opts.origin)\n        ? defaultAgent.dispatch(opts, handler)\n        : dispatch(opts, handler);\n    };\n  };\n\n  const token =\n    proxySettings.user && proxySettings.password\n      ? `Basic ${Buffer.from(\n          `${proxySettings.user}:${proxySettings.password}`\n        ).toString('base64')}`\n      : undefined;\n\n  try {\n    const proxyUrl = `${proxySettings.useSsl ? 'https' : 'http'}://${\n      proxySettings.hostname\n    }:${proxySettings.port}`;\n    const proxyAgent = new ProxyAgent({\n      uri: proxyUrl,\n      token,\n      keepAliveTimeout: 5000,\n      connections: 50,\n      connect: forceIpv4First ? { family: 4 } : undefined,\n    });\n\n    setGlobalDispatcher(proxyAgent.compose(noProxyInterceptor));\n\n    const agentOptions = {\n      headers: token ? { 'proxy-authorization': token } : undefined,\n      keepAlive: true,\n      maxSockets: 50,\n      maxFreeSockets: 10,\n      timeout: 5000,\n      scheduling: 'lifo' as const,\n      family: forceIpv4First ? 4 : undefined,\n    };\n    axios.defaults.httpAgent = new HttpProxyAgent(proxyUrl, agentOptions);\n    axios.defaults.httpsAgent = new HttpsProxyAgent(proxyUrl, agentOptions);\n\n    requestInterceptorFunction = (config) => {\n      const url = config.baseURL\n        ? new URL(config.baseURL + (config.url || ''))\n        : config.url;\n      if (url && skipUrl(url)) {\n        config.httpAgent = false;\n        config.httpsAgent = false;\n      }\n      return config;\n    };\n    axios.interceptors.request.use(requestInterceptorFunction);\n  } catch (e) {\n    logger.error('Failed to connect to the proxy: ' + e.message, {\n      label: 'Proxy',\n    });\n    setGlobalDispatcher(defaultAgent);\n    return;\n  }\n\n  try {\n    await axios.head('https://www.google.com');\n    logger.debug('HTTP(S) proxy connected successfully', { label: 'Proxy' });\n  } catch (e) {\n    logger.error(\n      'Failed to connect to the proxy: ' + e.message + ': ' + e.cause,\n      { label: 'Proxy' }\n    );\n    setGlobalDispatcher(defaultAgent);\n  }\n}\n\nfunction isLocalAddress(hostname: string) {\n  if (\n    hostname === 'localhost' ||\n    hostname === '127.0.0.1' ||\n    hostname === '::1'\n  ) {\n    return true;\n  }\n\n  const privateIpRanges = [\n    /^10\\./, // 10.x.x.x\n    /^172\\.(1[6-9]|2[0-9]|3[0-1])\\./, // 172.16.x.x - 172.31.x.x\n    /^192\\.168\\./, // 192.168.x.x\n  ];\n  if (privateIpRanges.some((regex) => regex.test(hostname))) {\n    return true;\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "server/utils/dateHelpers.ts",
    "content": "import { addYears } from 'date-fns';\nimport { Between } from 'typeorm';\n\nexport const AfterDate = (date: Date) => Between(date, addYears(date, 100));\n"
  },
  {
    "path": "server/utils/dnsCache.ts",
    "content": "import logger from '@server/logger';\nimport { DnsCacheManager } from 'dns-caching';\n\nexport let dnsCache: DnsCacheManager | undefined;\n\nexport function initializeDnsCache({\n  forceMinTtl,\n  forceMaxTtl,\n}: {\n  forceMinTtl?: number;\n  forceMaxTtl?: number;\n}) {\n  if (dnsCache) {\n    logger.warn('DNS Cache is already initialized', { label: 'DNS Cache' });\n    return;\n  }\n\n  logger.info('Initializing DNS Cache', { label: 'DNS Cache' });\n\n  dnsCache = new DnsCacheManager({\n    logger,\n    forceMinTtl: typeof forceMinTtl === 'number' ? forceMinTtl * 1000 : 0,\n    forceMaxTtl: typeof forceMaxTtl === 'number' ? forceMaxTtl * 1000 : -1,\n  });\n  dnsCache.initialize();\n}\n"
  },
  {
    "path": "server/utils/getHostname.ts",
    "content": "import { getSettings } from '@server/lib/settings';\n\ninterface HostnameParams {\n  useSsl?: boolean;\n  ip?: string;\n  port?: number;\n  urlBase?: string;\n}\n\nexport const getHostname = (params?: HostnameParams): string => {\n  const settings = params ? params : getSettings().jellyfin;\n\n  const { useSsl, ip, port, urlBase } = settings;\n\n  const hostname = `${useSsl ? 'https' : 'http'}://${ip}:${port}${urlBase}`;\n\n  return hostname;\n};\n"
  },
  {
    "path": "server/utils/jellyfin.ts",
    "content": "export function normalizeJellyfinGuid(\n  value: string | null | undefined\n): string | null {\n  if (!value) {\n    return null;\n  }\n\n  const normalized = value.replace(/-/g, '').toLowerCase();\n\n  if (!/^[0-9a-f]{32}$/.test(normalized)) {\n    return null;\n  }\n\n  return normalized;\n}\n"
  },
  {
    "path": "server/utils/profileMiddleware.ts",
    "content": "import { Permission } from '@server/lib/permissions';\n\nexport const isOwnProfile = (): Middleware => {\n  return (req, res, next) => {\n    if (req.user?.id !== Number(req.params.id)) {\n      return next({\n        status: 403,\n        message: \"You do not have permission to view this user's settings.\",\n      });\n    }\n    next();\n  };\n};\n\nexport const isOwnProfileOrAdmin = (): Middleware => {\n  const authMiddleware: Middleware = (req, res, next) => {\n    if (\n      !req.user?.hasPermission(Permission.MANAGE_USERS) &&\n      req.user?.id !== Number(req.params.id)\n    ) {\n      return next({\n        status: 403,\n        message: \"You do not have permission to view this user's settings.\",\n      });\n    }\n\n    next();\n  };\n  return authMiddleware;\n};\n"
  },
  {
    "path": "server/utils/restartFlag.ts",
    "content": "import type { AllSettings, NetworkSettings } from '@server/lib/settings';\nimport { getSettings } from '@server/lib/settings';\n\nclass RestartFlag {\n  private networkSettings: NetworkSettings;\n\n  public initializeSettings(settings: AllSettings): void {\n    this.networkSettings = {\n      ...settings.network,\n      proxy: { ...settings.network.proxy },\n    };\n  }\n\n  public isSet(): boolean {\n    const networkSettings = getSettings().network;\n\n    return (\n      this.networkSettings.csrfProtection !== networkSettings.csrfProtection ||\n      this.networkSettings.trustProxy !== networkSettings.trustProxy ||\n      this.networkSettings.proxy.enabled !== networkSettings.proxy.enabled\n    );\n  }\n}\n\nconst restartFlag = new RestartFlag();\n\nexport default restartFlag;\n"
  },
  {
    "path": "server/utils/seedTestDb.ts",
    "content": "import { UserType } from '@server/constants/user';\nimport dataSource, { getRepository } from '@server/datasource';\nimport { User } from '@server/entity/User';\nimport gravatarUrl from 'gravatar-url';\n\nexport interface SeedDbOptions {\n  /** If true, preserves existing data instead of dropping the database */\n  preserveDb?: boolean;\n  /** If true, runs migrations instead of synchronizing schema */\n  withMigrations?: boolean;\n}\n\n// Precomputed bcrypt hash of 'test1234'. We precompute this to avoid\n// having to hash the password every time we seed the database.\nconst TEST_USER_PASSWORD_HASH =\n  '$2b$12$Z5V2P5HZgmx4/AnWFMZN1.aD5AM1NucNi.mhNTSQ9oVtmdzu7Le/a';\n\n/**\n * Seeds test users into the database.\n * Assumes the database schema is already set up.\n */\nasync function seedTestUsers(): Promise<void> {\n  const userRepository = getRepository(User);\n\n  const admin = await userRepository.findOne({\n    select: { id: true, plexId: true },\n    where: { id: 1 },\n  });\n\n  // Create the admin user\n  const user =\n    (await userRepository.findOne({\n      where: { email: 'admin@seerr.dev' },\n    })) ?? new User();\n  user.plexId = admin?.plexId ?? 1;\n  user.plexToken = '1234';\n  user.plexUsername = 'admin';\n  user.username = 'admin';\n  user.email = 'admin@seerr.dev';\n  user.userType = UserType.PLEX;\n  user.password = TEST_USER_PASSWORD_HASH;\n  user.permissions = 2;\n  user.avatar = gravatarUrl('admin@seerr.dev', { default: 'mm', size: 200 });\n  await userRepository.save(user);\n\n  // Create the other user\n  const otherUser =\n    (await userRepository.findOne({\n      where: { email: 'friend@seerr.dev' },\n    })) ?? new User();\n  otherUser.plexId = admin?.plexId ?? 1;\n  otherUser.plexToken = '1234';\n  otherUser.plexUsername = 'friend';\n  otherUser.username = 'friend';\n  otherUser.email = 'friend@seerr.dev';\n  otherUser.userType = UserType.PLEX;\n  otherUser.password = TEST_USER_PASSWORD_HASH;\n  otherUser.permissions = 32;\n  otherUser.avatar = gravatarUrl('friend@seerr.dev', {\n    default: 'mm',\n    size: 200,\n  });\n  await userRepository.save(otherUser);\n}\n\n/**\n * Initializes the database connection and seeds test users.\n * Used by both Cypress tests and Vitest unit tests.\n */\nexport async function seedTestDb(options: SeedDbOptions = {}): Promise<void> {\n  const dbConnection = dataSource.isInitialized\n    ? dataSource\n    : await dataSource.initialize();\n\n  if (!options.preserveDb) {\n    await dbConnection.dropDatabase();\n  }\n\n  if (options.withMigrations) {\n    await dbConnection.runMigrations();\n  } else {\n    await dbConnection.synchronize();\n  }\n\n  await seedTestUsers();\n}\n\n/**\n * Resets the database to a clean state with seeded test users.\n * Used between tests to ensure isolation.\n * Assumes DB has been initialized.\n */\nexport async function resetTestDb(): Promise<void> {\n  await dataSource.synchronize(true);\n  await seedTestUsers();\n}\n"
  },
  {
    "path": "server/utils/typeHelpers.ts",
    "content": "import type {\n  TmdbCollectionResult,\n  TmdbMovieDetails,\n  TmdbMovieResult,\n  TmdbPersonDetails,\n  TmdbPersonResult,\n  TmdbTvDetails,\n  TmdbTvResult,\n} from '@server/api/themoviedb/interfaces';\n\nexport const isMovie = (\n  movie:\n    | TmdbMovieResult\n    | TmdbTvResult\n    | TmdbPersonResult\n    | TmdbCollectionResult\n): movie is TmdbMovieResult => {\n  return (movie as TmdbMovieResult).title !== undefined;\n};\n\nexport const isPerson = (\n  person:\n    | TmdbMovieResult\n    | TmdbTvResult\n    | TmdbPersonResult\n    | TmdbCollectionResult\n): person is TmdbPersonResult => {\n  return (person as TmdbPersonResult).known_for !== undefined;\n};\n\nexport const isCollection = (\n  collection:\n    | TmdbMovieResult\n    | TmdbTvResult\n    | TmdbPersonResult\n    | TmdbCollectionResult\n): collection is TmdbCollectionResult => {\n  return (collection as TmdbCollectionResult).media_type === 'collection';\n};\n\nexport const isMovieDetails = (\n  movie: TmdbMovieDetails | TmdbTvDetails | TmdbPersonDetails\n): movie is TmdbMovieDetails => {\n  return (movie as TmdbMovieDetails).title !== undefined;\n};\n\nexport const isTvDetails = (\n  tv: TmdbMovieDetails | TmdbTvDetails | TmdbPersonDetails\n): tv is TmdbTvDetails => {\n  return (tv as TmdbTvDetails).number_of_seasons !== undefined;\n};\n"
  },
  {
    "path": "src/components/AirDateBadge/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport defineMessages from '@app/utils/defineMessages';\nimport { FormattedRelativeTime, useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.AirDateBadge', {\n  airedrelative: 'Aired {relativeTime}',\n  airsrelative: 'Airing {relativeTime}',\n});\n\ntype AirDateBadgeProps = {\n  airDate: string;\n};\n\nconst AirDateBadge = ({ airDate }: AirDateBadgeProps) => {\n  const WEEK = 1000 * 60 * 60 * 24 * 8;\n  const intl = useIntl();\n  const dAirDate = new Date(airDate);\n  const nowDate = new Date();\n  const alreadyAired = dAirDate.getTime() < nowDate.getTime();\n  const compareWeek = new Date(\n    alreadyAired ? Date.now() - WEEK : Date.now() + WEEK\n  );\n  let showRelative = false;\n  if (\n    (alreadyAired && dAirDate.getTime() > compareWeek.getTime()) ||\n    (!alreadyAired && dAirDate.getTime() < compareWeek.getTime())\n  ) {\n    showRelative = true;\n  }\n\n  const diffInDays = Math.round(\n    (dAirDate.getTime() - nowDate.getTime()) / (1000 * 60 * 60 * 24)\n  );\n\n  return (\n    <div className=\"flex items-center space-x-2\">\n      <Badge badgeType=\"light\">\n        {intl.formatDate(dAirDate, {\n          year: 'numeric',\n          month: 'long',\n          day: 'numeric',\n          timeZone: 'UTC',\n        })}\n      </Badge>\n      {showRelative && (\n        <Badge badgeType=\"light\">\n          {intl.formatMessage(\n            alreadyAired ? messages.airedrelative : messages.airsrelative,\n            {\n              relativeTime: (\n                <FormattedRelativeTime\n                  value={diffInDays}\n                  unit=\"day\"\n                  numeric=\"auto\"\n                />\n              ),\n            }\n          )}\n        </Badge>\n      )}\n    </div>\n  );\n};\n\nexport default AirDateBadge;\n"
  },
  {
    "path": "src/components/AppDataWarning/index.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport defineMessages from '@app/utils/defineMessages';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.AppDataWarning', {\n  dockerVolumeMissingDescription:\n    'The <code>{appDataPath}</code> volume mount was not configured properly. All data will be cleared when the container is stopped or restarted.',\n});\n\nconst AppDataWarning = () => {\n  const intl = useIntl();\n  const { data, error } = useSWR<{ appData: boolean; appDataPath: string }>(\n    '/api/v1/status/appdata'\n  );\n\n  if (!data && !error) {\n    return null;\n  }\n\n  if (!data) {\n    return null;\n  }\n\n  return (\n    <>\n      {!data.appData && (\n        <Alert\n          title={intl.formatMessage(messages.dockerVolumeMissingDescription, {\n            code: (msg: React.ReactNode) => (\n              <code className=\"bg-gray-800/50\">{msg}</code>\n            ),\n            appDataPath: data.appDataPath,\n          })}\n        />\n      )}\n    </>\n  );\n};\n\nexport default AppDataWarning;\n"
  },
  {
    "path": "src/components/Blocklist/index.tsx",
    "content": "import BlocklistedTagsBadge from '@app/components/BlocklistedTagsBadge';\nimport Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport ConfirmButton from '@app/components/Common/ConfirmButton';\nimport Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDebouncedState from '@app/hooks/useDebouncedState';\nimport { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport {\n  ChevronLeftIcon,\n  ChevronRightIcon,\n  FunnelIcon,\n  MagnifyingGlassIcon,\n  TrashIcon,\n} from '@heroicons/react/24/solid';\nimport type {\n  BlocklistItem,\n  BlocklistResultsResponse,\n} from '@server/interfaces/api/blocklistInterfaces';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport axios from 'axios';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport type { ChangeEvent } from 'react';\nimport { useState } from 'react';\nimport { useInView } from 'react-intersection-observer';\nimport { FormattedRelativeTime, useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Blocklist', {\n  blocklistsettings: 'Blocklist Settings',\n  blocklistSettingsDescription: 'Manage blocklisted media.',\n  mediaName: 'Name',\n  mediaType: 'Type',\n  mediaTmdbId: 'tmdb Id',\n  blocklistdate: 'date',\n  blocklistedby: '{date} by {user}',\n  blocklistNotFoundError: '<strong>{title}</strong> is not blocklisted.',\n  filterManual: 'Manual',\n  filterBlocklistedTags: 'Blocklisted Tags',\n  showAllBlocklisted: 'Show All Blocklisted Media',\n});\n\nenum Filter {\n  ALL = 'all',\n  MANUAL = 'manual',\n  BLOCKLISTEDTAGS = 'blocklistedTags',\n}\n\nconst isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {\n  return (movie as MovieDetails).title !== undefined;\n};\n\nconst Blocklist = () => {\n  const [currentPageSize, setCurrentPageSize] = useState<number>(10);\n  const [searchFilter, debouncedSearchFilter, setSearchFilter] =\n    useDebouncedState('');\n  const [currentFilter, setCurrentFilter] = useState<Filter>(Filter.MANUAL);\n  const router = useRouter();\n  const intl = useIntl();\n\n  const page = router.query.page ? Number(router.query.page) : 1;\n  const pageIndex = page - 1;\n  const updateQueryParams = useUpdateQueryParams({ page: page.toString() });\n\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<BlocklistResultsResponse>(\n    `/api/v1/blocklist/?take=${currentPageSize}&skip=${\n      pageIndex * currentPageSize\n    }&filter=${currentFilter}${\n      debouncedSearchFilter ? `&search=${debouncedSearchFilter}` : ''\n    }`,\n    {\n      refreshInterval: 0,\n      revalidateOnFocus: false,\n    }\n  );\n\n  // check if there's no data and no errors in the table\n  // so as to show a spinner inside the table and not refresh the whole component\n  if (!data && error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const searchItem = (e: ChangeEvent<HTMLInputElement>) => {\n    // Remove the \"page\" query param from the URL\n    // so that the \"skip\" query param on line 62 is empty\n    // and the search returns results without skipping items\n    if (router.query.page) router.replace(router.basePath);\n\n    setSearchFilter(e.target.value as string);\n  };\n\n  const hasNextPage = data && data.pageInfo.pages > pageIndex + 1;\n  const hasPrevPage = pageIndex > 0;\n\n  return (\n    <>\n      <PageTitle title={[intl.formatMessage(globalMessages.blocklist)]} />\n      <div className=\"mb-4 flex flex-col justify-between lg:flex-row lg:items-end\">\n        <Header>{intl.formatMessage(globalMessages.blocklist)}</Header>\n\n        <div className=\"mt-2 flex flex-grow flex-col sm:flex-row lg:flex-grow-0\">\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n              <FunnelIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"filter\"\n              name=\"filter\"\n              onChange={(e) => {\n                setCurrentFilter(e.target.value as Filter);\n                router.push({\n                  pathname: router.pathname,\n                  query: router.query.userId\n                    ? { userId: router.query.userId }\n                    : {},\n                });\n              }}\n              value={currentFilter}\n              className=\"rounded-r-only\"\n            >\n              <option value=\"all\">\n                {intl.formatMessage(globalMessages.all)}\n              </option>\n              <option value=\"manual\">\n                {intl.formatMessage(messages.filterManual)}\n              </option>\n              <option value=\"blocklistedTags\">\n                {intl.formatMessage(messages.filterBlocklistedTags)}\n              </option>\n            </select>\n          </div>\n\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 md:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n              <MagnifyingGlassIcon className=\"h-6 w-6\" />\n            </span>\n            <input\n              type=\"text\"\n              className=\"rounded-r-only\"\n              value={searchFilter}\n              onChange={(e) => searchItem(e)}\n            />\n          </div>\n        </div>\n      </div>\n\n      {!data ? (\n        <LoadingSpinner />\n      ) : data.results.length === 0 ? (\n        <div className=\"flex w-full flex-col items-center justify-center py-24 text-white\">\n          <span className=\"text-2xl text-gray-400\">\n            {intl.formatMessage(globalMessages.noresults)}\n          </span>\n          {currentFilter !== Filter.ALL && (\n            <div className=\"mt-4\">\n              <Button\n                buttonType=\"primary\"\n                onClick={() => setCurrentFilter(Filter.ALL)}\n              >\n                {intl.formatMessage(messages.showAllBlocklisted)}\n              </Button>\n            </div>\n          )}\n        </div>\n      ) : (\n        data.results.map((item: BlocklistItem) => {\n          return (\n            <div\n              className=\"py-2\"\n              key={`request-list-${item.mediaType}-${item.tmdbId}`}\n            >\n              <BlocklistedItem item={item} revalidateList={revalidate} />\n            </div>\n          );\n        })\n      )}\n\n      <div className=\"actions\">\n        <nav\n          className=\"mb-3 flex flex-col items-center space-y-3 sm:flex-row sm:space-y-0\"\n          aria-label=\"Pagination\"\n        >\n          <div className=\"hidden lg:flex lg:flex-1\">\n            <p className=\"text-sm\">\n              {data &&\n                (data?.results.length ?? 0) > 0 &&\n                intl.formatMessage(globalMessages.showingresults, {\n                  from: pageIndex * currentPageSize + 1,\n                  to:\n                    data.results.length < currentPageSize\n                      ? pageIndex * currentPageSize + data.results.length\n                      : (pageIndex + 1) * currentPageSize,\n                  total: data.pageInfo.results,\n                  strong: (msg: React.ReactNode) => (\n                    <span className=\"font-medium\">{msg}</span>\n                  ),\n                })}\n            </p>\n          </div>\n          <div className=\"flex justify-center sm:flex-1 sm:justify-start lg:justify-center\">\n            <span className=\"-mt-3 items-center truncate text-sm sm:mt-0\">\n              {intl.formatMessage(globalMessages.resultsperpage, {\n                pageSize: (\n                  <select\n                    id=\"pageSize\"\n                    name=\"pageSize\"\n                    onChange={(e) => {\n                      setCurrentPageSize(Number(e.target.value));\n                      router\n                        .push({\n                          pathname: router.pathname,\n                          query: router.query.userId\n                            ? { userId: router.query.userId }\n                            : {},\n                        })\n                        .then(() => window.scrollTo(0, 0));\n                    }}\n                    value={currentPageSize}\n                    className=\"short inline\"\n                  >\n                    <option value=\"5\">5</option>\n                    <option value=\"10\">10</option>\n                    <option value=\"25\">25</option>\n                    <option value=\"50\">50</option>\n                    <option value=\"100\">100</option>\n                  </select>\n                ),\n              })}\n            </span>\n          </div>\n          <div className=\"flex flex-auto justify-center space-x-2 sm:flex-1 sm:justify-end\">\n            <Button\n              disabled={!hasPrevPage}\n              onClick={() => updateQueryParams('page', (page - 1).toString())}\n            >\n              <ChevronLeftIcon />\n              <span>{intl.formatMessage(globalMessages.previous)}</span>\n            </Button>\n            <Button\n              disabled={!hasNextPage}\n              onClick={() => updateQueryParams('page', (page + 1).toString())}\n            >\n              <span>{intl.formatMessage(globalMessages.next)}</span>\n              <ChevronRightIcon />\n            </Button>\n          </div>\n        </nav>\n      </div>\n    </>\n  );\n};\n\nexport default Blocklist;\n\ninterface BlocklistedItemProps {\n  item: BlocklistItem;\n  revalidateList: () => void;\n}\n\nconst BlocklistedItem = ({ item, revalidateList }: BlocklistedItemProps) => {\n  const [isUpdating, setIsUpdating] = useState<boolean>(false);\n  const { addToast } = useToasts();\n  const { ref, inView } = useInView({\n    triggerOnce: true,\n  });\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n\n  const url =\n    item.mediaType === 'movie'\n      ? `/api/v1/movie/${item.tmdbId}`\n      : `/api/v1/tv/${item.tmdbId}`;\n  const { data: title, error } = useSWR<MovieDetails | TvDetails>(\n    inView ? url : null\n  );\n\n  if (!title && !error) {\n    return (\n      <div\n        className=\"h-64 w-full animate-pulse rounded-xl bg-gray-800 xl:h-28\"\n        ref={ref}\n      />\n    );\n  }\n\n  const removeFromBlocklist = async (tmdbId: number, title?: string) => {\n    setIsUpdating(true);\n\n    try {\n      await axios.delete(\n        `/api/v1/blocklist/${tmdbId}?mediaType=${item.mediaType}`\n      );\n\n      addToast(\n        <span>\n          {intl.formatMessage(globalMessages.removeFromBlocklistSuccess, {\n            title,\n            strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n          })}\n        </span>,\n        { appearance: 'success', autoDismiss: true }\n      );\n    } catch {\n      addToast(intl.formatMessage(globalMessages.blocklistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n\n    revalidateList();\n    setIsUpdating(false);\n  };\n\n  return (\n    <div className=\"relative flex w-full flex-col justify-between overflow-hidden rounded-xl bg-gray-800 py-4 text-gray-400 shadow-md ring-1 ring-gray-700 xl:h-28 xl:flex-row\">\n      {title && title.backdropPath && (\n        <div className=\"absolute inset-0 z-0 w-full bg-cover bg-center xl:w-2/3\">\n          <CachedImage\n            type=\"tmdb\"\n            src={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${title.backdropPath}`}\n            alt=\"\"\n            style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n            fill\n          />\n          <div\n            className=\"absolute inset-0\"\n            style={{\n              backgroundImage:\n                'linear-gradient(90deg, rgba(31, 41, 55, 0.47) 0%, rgba(31, 41, 55, 1) 100%)',\n            }}\n          />\n        </div>\n      )}\n      <div className=\"relative flex w-full flex-col justify-between overflow-hidden sm:flex-row\">\n        <div className=\"relative z-10 flex w-full items-center overflow-hidden pl-4 pr-4 sm:pr-0 xl:w-7/12 2xl:w-2/3\">\n          <Link\n            href={\n              item.mediaType === 'movie'\n                ? `/movie/${item.tmdbId}`\n                : `/tv/${item.tmdbId}`\n            }\n            className=\"relative h-auto w-12 flex-shrink-0 scale-100 transform-gpu overflow-hidden rounded-md transition duration-300 hover:scale-105\"\n          >\n            <CachedImage\n              type=\"tmdb\"\n              src={\n                title?.posterPath\n                  ? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`\n                  : '/images/seerr_poster_not_found.png'\n              }\n              alt=\"\"\n              sizes=\"100vw\"\n              style={{ width: '100%', height: 'auto', objectFit: 'cover' }}\n              width={600}\n              height={900}\n            />\n          </Link>\n          <div className=\"flex flex-col justify-center overflow-hidden pl-2 xl:pl-4\">\n            <div className=\"pt-0.5 text-xs font-medium text-white sm:pt-1\">\n              {title &&\n                (isMovie(title)\n                  ? title.releaseDate\n                  : title.firstAirDate\n                )?.slice(0, 4)}\n            </div>\n            <Link\n              href={\n                item.mediaType === 'movie'\n                  ? `/movie/${item.tmdbId}`\n                  : `/tv/${item.tmdbId}`\n              }\n            >\n              <span className=\"mr-2 min-w-0 truncate text-lg font-bold text-white hover:underline xl:text-xl\">\n                {title && (isMovie(title) ? title.title : title.name)}\n              </span>\n            </Link>\n          </div>\n        </div>\n\n        <div className=\"z-10 ml-4 mt-4 flex w-full flex-col justify-center overflow-hidden pr-4 text-sm sm:ml-2 sm:mt-0 xl:flex-1 xl:pr-0\">\n          <div className=\"card-field\">\n            <span className=\"card-field-name\">Status</span>\n            <Badge badgeType=\"danger\">\n              {intl.formatMessage(globalMessages.blocklisted)}\n            </Badge>\n          </div>\n\n          {item.createdAt && (\n            <div className=\"card-field\">\n              <span className=\"card-field-name\">\n                {intl.formatMessage(globalMessages.blocklisted)}\n              </span>\n              <span className=\"flex truncate text-sm text-gray-300\">\n                {intl.formatMessage(messages.blocklistedby, {\n                  date: (\n                    <FormattedRelativeTime\n                      value={Math.floor(\n                        (new Date(item.createdAt).getTime() - Date.now()) / 1000\n                      )}\n                      updateIntervalInSeconds={1}\n                      numeric=\"auto\"\n                    />\n                  ),\n                  user: item.user ? (\n                    <Link href={`/users/${item.user.id}`}>\n                      <span className=\"group flex items-center truncate\">\n                        <CachedImage\n                          type=\"avatar\"\n                          src={item.user.avatar}\n                          alt=\"\"\n                          className=\"avatar-sm ml-1.5\"\n                          width={20}\n                          height={20}\n                          style={{ objectFit: 'cover' }}\n                        />\n                        <span className=\"ml-1 truncate text-sm font-semibold group-hover:text-white group-hover:underline\">\n                          {item.user.displayName}\n                        </span>\n                      </span>\n                    </Link>\n                  ) : item.blocklistedTags ? (\n                    <span className=\"ml-1\">\n                      <BlocklistedTagsBadge data={item} />\n                    </span>\n                  ) : (\n                    <span className=\"ml-1 truncate text-sm font-semibold\">\n                      ???\n                    </span>\n                  ),\n                })}\n              </span>\n            </div>\n          )}\n          <div className=\"card-field\">\n            {item.mediaType === 'movie' ? (\n              <div className=\"pointer-events-none z-40 self-start rounded-full border border-blue-500 bg-blue-600/80 shadow-md\">\n                <div className=\"flex h-4 items-center px-2 py-2 text-center text-xs font-medium uppercase tracking-wider text-white sm:h-5\">\n                  {intl.formatMessage(globalMessages.movie)}\n                </div>\n              </div>\n            ) : (\n              <div className=\"pointer-events-none z-40 self-start rounded-full border border-purple-600 bg-purple-600/80 shadow-md\">\n                <div className=\"flex h-4 items-center px-2 py-2 text-center text-xs font-medium uppercase tracking-wider text-white sm:h-5\">\n                  {intl.formatMessage(globalMessages.tvshow)}\n                </div>\n              </div>\n            )}\n          </div>\n        </div>\n      </div>\n      <div className=\"z-10 mt-4 flex w-full flex-col justify-center space-y-2 pl-4 pr-4 xl:mt-0 xl:w-96 xl:items-end xl:pl-0\">\n        {hasPermission(Permission.MANAGE_BLOCKLIST) && (\n          <ConfirmButton\n            onClick={() =>\n              removeFromBlocklist(\n                item.tmdbId,\n                title && (isMovie(title) ? title.title : title.name)\n              )\n            }\n            confirmText={intl.formatMessage(\n              isUpdating ? globalMessages.deleting : globalMessages.areyousure\n            )}\n            className={`w-full ${\n              isUpdating ? 'pointer-events-none opacity-50' : ''\n            }`}\n          >\n            <TrashIcon />\n            <span>\n              {intl.formatMessage(globalMessages.removefromBlocklist)}\n            </span>\n          </ConfirmButton>\n        )}\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "src/components/BlocklistBlock/index.tsx",
    "content": "import BlocklistedTagsBadge from '@app/components/BlocklistedTagsBadge';\nimport Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { CalendarIcon, TrashIcon, UserIcon } from '@heroicons/react/24/solid';\nimport type { MediaType } from '@server/constants/media';\nimport type { Blocklist } from '@server/entity/Blocklist';\nimport axios from 'axios';\nimport Link from 'next/link';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('component.BlocklistBlock', {\n  blocklistedby: 'Blocklisted By',\n  blocklistdate: 'Blocklisted date',\n});\n\ninterface BlocklistBlockProps {\n  tmdbId: number;\n  mediaType: MediaType;\n  onUpdate?: () => void;\n  onDelete?: () => void;\n}\n\nconst BlocklistBlock = ({\n  tmdbId,\n  mediaType,\n  onUpdate,\n  onDelete,\n}: BlocklistBlockProps) => {\n  const { user } = useUser();\n  const intl = useIntl();\n  const [isUpdating, setIsUpdating] = useState(false);\n  const { addToast } = useToasts();\n  const { data } = useSWR<Blocklist>(\n    `/api/v1/blocklist/${tmdbId}?mediaType=${mediaType}`\n  );\n\n  const removeFromBlocklist = async (tmdbId: number, title?: string) => {\n    setIsUpdating(true);\n\n    try {\n      await axios.delete(`/api/v1/blocklist/${tmdbId}?mediaType=${mediaType}`);\n\n      addToast(\n        <span>\n          {intl.formatMessage(globalMessages.removeFromBlocklistSuccess, {\n            title,\n            strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n          })}\n        </span>,\n        { appearance: 'success', autoDismiss: true }\n      );\n    } catch {\n      addToast(intl.formatMessage(globalMessages.blocklistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n\n    onUpdate?.();\n    onDelete?.();\n\n    setIsUpdating(false);\n  };\n\n  if (!data) {\n    return (\n      <>\n        <LoadingSpinner />\n      </>\n    );\n  }\n\n  return (\n    <div className=\"px-4 py-3 text-gray-300\">\n      <div className=\"flex items-center justify-between\">\n        <div className=\"mr-6 min-w-0 flex-1 flex-col items-center text-sm leading-5\">\n          <div className=\"white mb-1 flex flex-nowrap\">\n            {data.user ? (\n              <>\n                <Tooltip content={intl.formatMessage(messages.blocklistedby)}>\n                  <UserIcon className=\"mr-1.5 h-5 w-5 min-w-0 flex-shrink-0\" />\n                </Tooltip>\n                <span className=\"w-40 truncate md:w-auto\">\n                  <Link\n                    href={\n                      data.user.id === user?.id\n                        ? '/profile'\n                        : `/users/${data.user.id}`\n                    }\n                  >\n                    <span className=\"font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline\">\n                      {data.user.displayName}\n                    </span>\n                  </Link>\n                </span>\n              </>\n            ) : data.blocklistedTags ? (\n              <>\n                <span className=\"w-40 truncate md:w-auto\">\n                  {intl.formatMessage(messages.blocklistedby)}:&nbsp;\n                </span>\n                <BlocklistedTagsBadge data={data} />\n              </>\n            ) : null}\n          </div>\n        </div>\n        <div className=\"ml-2 flex flex-shrink-0 flex-wrap\">\n          <Tooltip\n            content={intl.formatMessage(globalMessages.removefromBlocklist)}\n          >\n            <Button\n              buttonType=\"danger\"\n              onClick={() => removeFromBlocklist(data.tmdbId, data.title)}\n              disabled={isUpdating}\n            >\n              <TrashIcon className=\"icon-sm\" />\n            </Button>\n          </Tooltip>\n        </div>\n      </div>\n      <div className=\"mt-2 sm:flex sm:justify-between\">\n        <div className=\"sm:flex\">\n          <div className=\"mr-6 flex items-center text-sm leading-5\">\n            <Badge badgeType=\"danger\">\n              {intl.formatMessage(globalMessages.blocklisted)}\n            </Badge>\n          </div>\n        </div>\n        <div className=\"mt-2 flex items-center text-sm leading-5 sm:mt-0\">\n          <Tooltip content={intl.formatMessage(messages.blocklistdate)}>\n            <CalendarIcon className=\"mr-1.5 h-5 w-5 flex-shrink-0\" />\n          </Tooltip>\n          <span>\n            {intl.formatDate(data.createdAt, {\n              year: 'numeric',\n              month: 'long',\n              day: 'numeric',\n            })}\n          </span>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default BlocklistBlock;\n"
  },
  {
    "path": "src/components/BlocklistModal/index.tsx",
    "content": "import Modal from '@app/components/Common/Modal';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport axios from 'axios';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\ninterface BlocklistModalProps {\n  tmdbId: number;\n  type: 'movie' | 'tv' | 'collection';\n  show: boolean;\n  onComplete?: () => void;\n  onCancel?: () => void;\n  isUpdating?: boolean;\n}\n\nconst messages = defineMessages('component.BlocklistModal', {\n  blocklisting: 'Blocklisting',\n});\n\nconst isMovie = (\n  movie: MovieDetails | TvDetails | null\n): movie is MovieDetails => {\n  if (!movie) return false;\n  return (movie as MovieDetails).title !== undefined;\n};\n\nconst BlocklistModal = ({\n  tmdbId,\n  type,\n  show,\n  onComplete,\n  onCancel,\n  isUpdating,\n}: BlocklistModalProps) => {\n  const intl = useIntl();\n  const [data, setData] = useState<TvDetails | MovieDetails | null>(null);\n  const [error, setError] = useState(null);\n\n  useEffect(() => {\n    (async () => {\n      if (!show) return;\n      try {\n        setError(null);\n        const response = await axios.get(`/api/v1/${type}/${tmdbId}`);\n        setData(response.data);\n      } catch (err) {\n        setError(err);\n      }\n    })();\n  }, [show, tmdbId, type]);\n\n  return (\n    <Transition\n      as=\"div\"\n      enter=\"transition-opacity duration-300\"\n      enterFrom=\"opacity-0\"\n      enterTo=\"opacity-100\"\n      leave=\"transition-opacity duration-300\"\n      leaveFrom=\"opacity-100\"\n      leaveTo=\"opacity-0\"\n      show={show}\n    >\n      <Modal\n        loading={!data && !error}\n        backgroundClickable\n        title={`${intl.formatMessage(globalMessages.blocklist)} ${\n          isMovie(data)\n            ? intl.formatMessage(globalMessages.movie)\n            : intl.formatMessage(globalMessages.tvshow)\n        }`}\n        subTitle={`${isMovie(data) ? data.title : data?.name}`}\n        onCancel={onCancel}\n        onOk={onComplete}\n        okText={\n          isUpdating\n            ? intl.formatMessage(messages.blocklisting)\n            : intl.formatMessage(globalMessages.blocklist)\n        }\n        okButtonType=\"danger\"\n        okDisabled={isUpdating}\n        backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}\n      />\n    </Transition>\n  );\n};\n\nexport default BlocklistModal;\n"
  },
  {
    "path": "src/components/BlocklistedTagsBadge/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport defineMessages from '@app/utils/defineMessages';\nimport { TagIcon } from '@heroicons/react/20/solid';\nimport type { BlocklistItem } from '@server/interfaces/api/blocklistInterfaces';\nimport type { Keyword } from '@server/models/common';\nimport axios from 'axios';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Settings', {\n  blocklistedTagsText: 'Blocklisted Tags',\n});\n\ninterface BlocklistedTagsBadgeProps {\n  data: BlocklistItem;\n}\n\nconst BlocklistedTagsBadge = ({ data }: BlocklistedTagsBadgeProps) => {\n  const [tagNamesBlocklistedFor, setTagNamesBlocklistedFor] =\n    useState<string>('Loading...');\n  const intl = useIntl();\n\n  useEffect(() => {\n    if (!data.blocklistedTags) {\n      return;\n    }\n\n    const keywordIds = data.blocklistedTags.slice(1, -1).split(',');\n    Promise.all(\n      keywordIds.map(async (keywordId) => {\n        const { data } = await axios.get<Keyword | null>(\n          `/api/v1/keyword/${keywordId}`\n        );\n        return data?.name || `[Invalid: ${keywordId}]`;\n      })\n    ).then((keywords) => {\n      setTagNamesBlocklistedFor(keywords.join(', '));\n    });\n  }, [data.blocklistedTags]);\n\n  return (\n    <Tooltip\n      content={tagNamesBlocklistedFor}\n      tooltipConfig={{ followCursor: false }}\n    >\n      <Badge\n        badgeType=\"dark\"\n        className=\"items-center border border-red-500 !text-red-400\"\n      >\n        <TagIcon className=\"mr-1 h-4\" />\n        {intl.formatMessage(messages.blocklistedTagsText)}\n      </Badge>\n    </Tooltip>\n  );\n};\n\nexport default BlocklistedTagsBadge;\n"
  },
  {
    "path": "src/components/BlocklistedTagsSelector/index.tsx",
    "content": "import Modal from '@app/components/Common/Modal';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport CopyButton from '@app/components/Settings/CopyButton';\nimport { encodeURIExtraParams } from '@app/hooks/useDiscover';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport { ArrowDownIcon } from '@heroicons/react/24/solid';\nimport type {\n  TmdbKeyword,\n  TmdbKeywordSearchResponse,\n} from '@server/api/themoviedb/interfaces';\nimport type { Keyword } from '@server/models/common';\nimport axios from 'axios';\nimport { useFormikContext } from 'formik';\nimport {\n  forwardRef,\n  useCallback,\n  useEffect,\n  useImperativeHandle,\n  useRef,\n  useState,\n} from 'react';\nimport { useIntl } from 'react-intl';\nimport type { ClearIndicatorProps, GroupBase, MultiValue } from 'react-select';\nimport { components } from 'react-select';\nimport AsyncSelect from 'react-select/async';\n\nconst messages = defineMessages('components.Settings', {\n  copyBlocklistedTags: 'Copied blocklisted tags to clipboard.',\n  copyBlocklistedTagsTip: 'Copy blocklisted tag configuration',\n  copyBlocklistedTagsEmpty: 'Nothing to copy',\n  importBlocklistedTagsTip: 'Import blocklisted tag configuration',\n  clearBlocklistedTagsConfirm:\n    'Are you sure you want to clear the blocklisted tags?',\n  yes: 'Yes',\n  no: 'No',\n  searchKeywords: 'Search keywords…',\n  starttyping: 'Starting typing to search.',\n  nooptions: 'No results.',\n  blocklistedTagImportTitle: 'Import Blocklisted Tag Configuration',\n  blocklistedTagImportInstructions: 'Paste blocklist tag configuration below.',\n  valueRequired: 'You must provide a value.',\n  noSpecialCharacters:\n    'Configuration must be a comma delimited list of TMDB keyword ids, and must not start or end with a comma.',\n  invalidKeyword: '{keywordId} is not a TMDB keyword.',\n});\n\ntype SingleVal = {\n  label: string;\n  value: number;\n};\n\ntype BlocklistedTagsSelectorProps = {\n  defaultValue?: string;\n};\n\nconst BlocklistedTagsSelector = ({\n  defaultValue,\n}: BlocklistedTagsSelectorProps) => {\n  const { setFieldValue } = useFormikContext();\n  const [value, setValue] = useState<string | undefined>(defaultValue);\n  const intl = useIntl();\n  const [selectorValue, setSelectorValue] =\n    useState<MultiValue<SingleVal> | null>(null);\n\n  const update = useCallback(\n    (value: MultiValue<SingleVal> | null) => {\n      const strVal = value?.map((v) => v.value).join(',');\n      setSelectorValue(value);\n      setValue(strVal);\n      setFieldValue('blocklistedTags', strVal);\n    },\n    [setSelectorValue, setValue, setFieldValue]\n  );\n\n  const copyDisabled = value === null || value?.length === 0;\n\n  return (\n    <>\n      <ControlledKeywordSelector\n        value={selectorValue}\n        onChange={update}\n        defaultValue={defaultValue}\n        components={{\n          DropdownIndicator: undefined,\n          IndicatorSeparator: undefined,\n          ClearIndicator: VerifyClearIndicator,\n        }}\n      />\n\n      <CopyButton\n        textToCopy={value ?? ''}\n        disabled={copyDisabled}\n        toastMessage={intl.formatMessage(messages.copyBlocklistedTags)}\n        tooltipContent={intl.formatMessage(\n          copyDisabled\n            ? messages.copyBlocklistedTagsEmpty\n            : messages.copyBlocklistedTagsTip\n        )}\n        tooltipConfig={{ followCursor: false }}\n      />\n      <BlocklistedTagsImportButton setSelector={update} />\n    </>\n  );\n};\n\ntype BaseSelectorMultiProps = {\n  defaultValue?: string;\n  value: MultiValue<SingleVal> | null;\n  onChange: (value: MultiValue<SingleVal> | null) => void;\n  components?: Partial<typeof components>;\n};\n\nconst ControlledKeywordSelector = ({\n  defaultValue,\n  onChange,\n  components,\n  value,\n}: BaseSelectorMultiProps) => {\n  const intl = useIntl();\n\n  useEffect(() => {\n    const loadDefaultKeywords = async (): Promise<void> => {\n      if (!defaultValue) {\n        return;\n      }\n\n      const keywords = await Promise.all(\n        defaultValue.split(',').map(async (keywordId) => {\n          const { data } = await axios.get<Keyword | null>(\n            `/api/v1/keyword/${keywordId}`\n          );\n          return data;\n        })\n      );\n\n      const validKeywords: TmdbKeyword[] = keywords.filter(\n        (keyword): keyword is TmdbKeyword => keyword !== null\n      );\n\n      onChange(\n        validKeywords.map((keyword) => ({\n          label: keyword.name,\n          value: keyword.id,\n        }))\n      );\n    };\n\n    loadDefaultKeywords();\n  }, [defaultValue, onChange]);\n\n  const loadKeywordOptions = async (inputValue: string) => {\n    const { data } = await axios.get<TmdbKeywordSearchResponse>(\n      `/api/v1/search/keyword?query=${encodeURIExtraParams(inputValue)}`\n    );\n\n    return data.results.map((result) => ({\n      label: result.name,\n      value: result.id,\n    }));\n  };\n\n  return (\n    <AsyncSelect\n      key={`keyword-select-blocklistedTags`}\n      inputId=\"data\"\n      isMulti\n      className=\"react-select-container\"\n      classNamePrefix=\"react-select\"\n      noOptionsMessage={({ inputValue }) =>\n        inputValue === ''\n          ? intl.formatMessage(messages.starttyping)\n          : intl.formatMessage(messages.nooptions)\n      }\n      value={value}\n      loadOptions={loadKeywordOptions}\n      placeholder={intl.formatMessage(messages.searchKeywords)}\n      onChange={onChange}\n      components={components}\n    />\n  );\n};\n\ntype BlocklistedTagsImportButtonProps = {\n  setSelector: (value: MultiValue<SingleVal>) => void;\n};\n\nconst BlocklistedTagsImportButton = ({\n  setSelector,\n}: BlocklistedTagsImportButtonProps) => {\n  const [show, setShow] = useState(false);\n  const formRef = useRef<HTMLFormElement>(null);\n  const intl = useIntl();\n\n  const onConfirm = useCallback(async () => {\n    if (formRef.current) {\n      if (await formRef.current.submitForm()) {\n        setShow(false);\n      }\n    }\n  }, []);\n\n  const onClick = useCallback((event: React.MouseEvent) => {\n    event.stopPropagation();\n    setShow(true);\n  }, []);\n\n  return (\n    <>\n      <Transition\n        as=\"div\"\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={show}\n      >\n        <Modal\n          title={intl.formatMessage(messages.blocklistedTagImportTitle)}\n          okText=\"Confirm\"\n          onOk={onConfirm}\n          onCancel={() => setShow(false)}\n        >\n          <BlocklistedTagImportForm ref={formRef} setSelector={setSelector} />\n        </Modal>\n      </Transition>\n\n      <Tooltip\n        content={intl.formatMessage(messages.importBlocklistedTagsTip)}\n        tooltipConfig={{ followCursor: false }}\n      >\n        <button className=\"input-action\" onClick={onClick} type=\"button\">\n          <ArrowDownIcon />\n        </button>\n      </Tooltip>\n    </>\n  );\n};\n\ntype BlocklistedTagImportFormProps = BlocklistedTagsImportButtonProps;\n\nconst BlocklistedTagImportForm = forwardRef<\n  Partial<HTMLFormElement>,\n  BlocklistedTagImportFormProps\n>((props, ref) => {\n  const { setSelector } = props;\n  const intl = useIntl();\n  const [formValue, setFormValue] = useState('');\n  const [errors, setErrors] = useState<string[]>([]);\n\n  useImperativeHandle(ref, () => ({\n    submitForm: handleSubmit,\n    formValue,\n  }));\n\n  const validate = async () => {\n    if (formValue.length === 0) {\n      setErrors([intl.formatMessage(messages.valueRequired)]);\n      return false;\n    }\n\n    if (!/^(?:\\d+,)*\\d+$/.test(formValue)) {\n      setErrors([intl.formatMessage(messages.noSpecialCharacters)]);\n      return false;\n    }\n\n    const keywords = await Promise.allSettled(\n      formValue.split(',').map(async (keywordId) => {\n        try {\n          const { data } = await axios.get<Keyword>(\n            `/api/v1/keyword/${keywordId}`\n          );\n          return {\n            label: data.name,\n            value: data.id,\n          };\n        } catch {\n          throw intl.formatMessage(messages.invalidKeyword, { keywordId });\n        }\n      })\n    );\n\n    const failures = keywords.filter(\n      (res) => res.status === 'rejected'\n    ) as PromiseRejectedResult[];\n    if (failures.length > 0) {\n      setErrors(failures.map((failure) => `${failure.reason}`));\n      return false;\n    }\n\n    setSelector(\n      (keywords as PromiseFulfilledResult<SingleVal>[]).map(\n        (keyword) => keyword.value\n      )\n    );\n\n    setErrors([]);\n    return true;\n  };\n\n  const handleSubmit = validate;\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <div>\n        <label htmlFor=\"value\">\n          {intl.formatMessage(messages.blocklistedTagImportInstructions)}\n        </label>\n        <textarea\n          id=\"value\"\n          value={formValue}\n          onChange={(e) => setFormValue(e.target.value)}\n          className=\"h-20\"\n        />\n        {errors.length > 0 && (\n          <div className=\"error\">\n            {errors.map((error) => (\n              <div key={error}>{error}</div>\n            ))}\n          </div>\n        )}\n      </div>\n    </form>\n  );\n});\n\nconst VerifyClearIndicator = <\n  Option,\n  IsMuti extends boolean,\n  Group extends GroupBase<Option>,\n>(\n  props: ClearIndicatorProps<Option, IsMuti, Group>\n) => {\n  const { clearValue } = props;\n  const [show, setShow] = useState(false);\n  const intl = useIntl();\n\n  const openForm = useCallback(() => {\n    setShow(true);\n  }, [setShow]);\n\n  const openFormKey = useCallback(\n    (event: React.KeyboardEvent) => {\n      if (show) return;\n\n      if (event.key === 'Enter' || event.key === 'Space') {\n        setShow(true);\n      }\n    },\n    [setShow, show]\n  );\n\n  const acceptForm = useCallback(\n    (event: KeyboardEvent) => {\n      if (event.key === 'Enter') {\n        event.stopPropagation();\n        event.preventDefault();\n        clearValue();\n      }\n    },\n    [clearValue]\n  );\n\n  useEffect(() => {\n    if (show) {\n      window.addEventListener('keydown', acceptForm);\n    }\n\n    return () => window.removeEventListener('keydown', acceptForm);\n  }, [show, acceptForm]);\n\n  return (\n    <>\n      <button\n        type=\"button\"\n        onClick={openForm}\n        onKeyDown={openFormKey}\n        className=\"react-select__indicator react-select__clear-indicator css-1xc3v61-indicatorContainer cursor-pointer\"\n      >\n        <components.CrossIcon />\n      </button>\n      <Transition\n        as=\"div\"\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={show}\n      >\n        <Modal\n          subTitle={intl.formatMessage(messages.clearBlocklistedTagsConfirm)}\n          okText={intl.formatMessage(messages.yes)}\n          cancelText={intl.formatMessage(messages.no)}\n          onOk={clearValue}\n          onCancel={() => setShow(false)}\n        >\n          <form />{' '}\n          {/* Form prevents accidentally saving settings when pressing enter */}\n        </Modal>\n      </Transition>\n    </>\n  );\n};\n\nexport default BlocklistedTagsSelector;\n"
  },
  {
    "path": "src/components/CollectionDetails/index.tsx",
    "content": "import ButtonWithDropdown from '@app/components/Common/ButtonWithDropdown';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport RequestModal from '@app/components/RequestModal';\nimport Slider from '@app/components/Slider';\nimport StatusBadge from '@app/components/StatusBadge';\nimport TitleCard from '@app/components/TitleCard';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { refreshIntervalHelper } from '@app/utils/refreshIntervalHelper';\nimport { ArrowDownTrayIcon } from '@heroicons/react/24/outline';\nimport { MediaStatus } from '@server/constants/media';\nimport type { Collection } from '@server/models/Collection';\nimport { uniq } from 'lodash';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.CollectionDetails', {\n  overview: 'Overview',\n  numberofmovies: '{count} Movies',\n  requestcollection: 'Request Collection',\n  requestcollection4k: 'Request Collection in 4K',\n});\n\ninterface CollectionDetailsProps {\n  collection?: Collection;\n}\n\nconst CollectionDetails = ({ collection }: CollectionDetailsProps) => {\n  const intl = useIntl();\n  const router = useRouter();\n  const settings = useSettings();\n  const { hasPermission } = useUser();\n  const [requestModal, setRequestModal] = useState(false);\n  const [is4k, setIs4k] = useState(false);\n\n  const returnCollectionDownloadItems = (data: Collection | undefined) => {\n    const [downloadStatus, downloadStatus4k] = [\n      data?.parts.flatMap((item) =>\n        item.mediaInfo?.downloadStatus ? item.mediaInfo?.downloadStatus : []\n      ),\n      data?.parts.flatMap((item) =>\n        item.mediaInfo?.downloadStatus4k ? item.mediaInfo?.downloadStatus4k : []\n      ),\n    ];\n\n    return { downloadStatus, downloadStatus4k };\n  };\n\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<Collection>(`/api/v1/collection/${router.query.collectionId}`, {\n    fallbackData: collection,\n    revalidateOnMount: true,\n    refreshInterval: refreshIntervalHelper(\n      returnCollectionDownloadItems(collection),\n      15000\n    ),\n  });\n\n  const { data: genres } =\n    useSWR<{ id: number; name: string }[]>(`/api/v1/genres/movie`);\n\n  const [downloadStatus, downloadStatus4k] = useMemo(() => {\n    const downloadItems = returnCollectionDownloadItems(data);\n    return [downloadItems.downloadStatus, downloadItems.downloadStatus4k];\n  }, [data]);\n\n  const [titles, titles4k] = useMemo(() => {\n    return [\n      data?.parts\n        .filter((media) => (media.mediaInfo?.downloadStatus ?? []).length > 0)\n        .map((title) => title.title),\n      data?.parts\n        .filter((media) => (media.mediaInfo?.downloadStatus4k ?? []).length > 0)\n        .map((title) => title.title),\n    ];\n  }, [data?.parts]);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  let collectionStatus = MediaStatus.UNKNOWN;\n  let collectionStatus4k = MediaStatus.UNKNOWN;\n\n  if (\n    data.parts.every(\n      (part) =>\n        part.mediaInfo && part.mediaInfo.status === MediaStatus.AVAILABLE\n    )\n  ) {\n    collectionStatus = MediaStatus.AVAILABLE;\n  } else if (\n    data.parts.some(\n      (part) =>\n        part.mediaInfo && part.mediaInfo.status === MediaStatus.AVAILABLE\n    )\n  ) {\n    collectionStatus = MediaStatus.PARTIALLY_AVAILABLE;\n  }\n\n  if (\n    data.parts.every(\n      (part) =>\n        part.mediaInfo && part.mediaInfo.status4k === MediaStatus.AVAILABLE\n    )\n  ) {\n    collectionStatus4k = MediaStatus.AVAILABLE;\n  } else if (\n    data.parts.some(\n      (part) =>\n        part.mediaInfo && part.mediaInfo.status4k === MediaStatus.AVAILABLE\n    )\n  ) {\n    collectionStatus4k = MediaStatus.PARTIALLY_AVAILABLE;\n  }\n\n  const hasRequestable =\n    hasPermission([Permission.REQUEST, Permission.REQUEST_MOVIE], {\n      type: 'or',\n    }) &&\n    data.parts.filter(\n      (part) =>\n        !part.mediaInfo ||\n        part.mediaInfo.status === MediaStatus.DELETED ||\n        part.mediaInfo.status === MediaStatus.UNKNOWN\n    ).length > 0;\n\n  const hasRequestable4k =\n    settings.currentSettings.movie4kEnabled &&\n    hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE], {\n      type: 'or',\n    }) &&\n    data.parts.filter(\n      (part) =>\n        !part.mediaInfo ||\n        part.mediaInfo.status4k === MediaStatus.DELETED ||\n        part.mediaInfo.status4k === MediaStatus.UNKNOWN\n    ).length > 0;\n\n  const collectionAttributes: React.ReactNode[] = [];\n\n  collectionAttributes.push(\n    intl.formatMessage(messages.numberofmovies, {\n      count: data.parts.length,\n    })\n  );\n\n  if (genres && data.parts.some((part) => part.genreIds.length)) {\n    collectionAttributes.push(\n      uniq(\n        data.parts.reduce(\n          (genresList: number[], curr) => genresList.concat(curr.genreIds),\n          []\n        )\n      )\n        .map((genreId) => (\n          <Link\n            href={`/discover/movies/genre/${genreId}`}\n            key={`genre-${genreId}`}\n            className=\"hover:underline\"\n          >\n            {genres.find((g) => g.id === genreId)?.name}\n          </Link>\n        ))\n        .reduce((prev, curr) => (\n          <>\n            {intl.formatMessage(globalMessages.delimitedlist, {\n              a: prev,\n              b: curr,\n            })}\n          </>\n        ))\n    );\n  }\n\n  const blocklistVisibility = hasPermission(\n    [Permission.MANAGE_BLOCKLIST, Permission.VIEW_BLOCKLIST],\n    { type: 'or' }\n  );\n\n  return (\n    <div\n      className=\"media-page\"\n      style={{\n        height: 493,\n      }}\n    >\n      {data.backdropPath && (\n        <div className=\"media-page-bg-image\">\n          <CachedImage\n            type=\"tmdb\"\n            alt=\"\"\n            src={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data.backdropPath}`}\n            style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n            fill\n            priority\n          />\n          <div\n            className=\"absolute inset-0\"\n            style={{\n              backgroundImage:\n                'linear-gradient(180deg, rgba(17, 24, 39, 0.47) 0%, rgba(17, 24, 39, 1) 100%)',\n            }}\n          />\n        </div>\n      )}\n      <PageTitle title={data.name} />\n      <RequestModal\n        tmdbId={data.id}\n        show={requestModal}\n        type=\"collection\"\n        is4k={is4k}\n        onComplete={() => {\n          revalidate();\n          setRequestModal(false);\n        }}\n        onCancel={() => setRequestModal(false)}\n      />\n      <div className=\"media-header\">\n        <div className=\"media-poster\">\n          <CachedImage\n            type=\"tmdb\"\n            src={\n              data.posterPath\n                ? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${data.posterPath}`\n                : '/images/seerr_poster_not_found.png'\n            }\n            alt=\"\"\n            sizes=\"100vw\"\n            style={{ width: '100%', height: 'auto' }}\n            width={600}\n            height={900}\n            priority\n          />\n        </div>\n        <div className=\"media-title\">\n          <div className=\"media-status\">\n            <StatusBadge\n              status={collectionStatus}\n              downloadItem={downloadStatus}\n              title={titles}\n              inProgress={data.parts.some(\n                (part) => (part.mediaInfo?.downloadStatus ?? []).length > 0\n              )}\n            />\n            {settings.currentSettings.movie4kEnabled &&\n              hasPermission(\n                [Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE],\n                {\n                  type: 'or',\n                }\n              ) && (\n                <StatusBadge\n                  status={collectionStatus4k}\n                  downloadItem={downloadStatus4k}\n                  title={titles4k}\n                  is4k\n                  inProgress={data.parts.some(\n                    (part) =>\n                      (part.mediaInfo?.downloadStatus4k ?? []).length > 0\n                  )}\n                />\n              )}\n          </div>\n          <h1>{data.name}</h1>\n          <span className=\"media-attributes\">\n            {collectionAttributes.length > 0 &&\n              collectionAttributes\n                .map((t, k) => <span key={k}>{t}</span>)\n                .reduce((prev, curr) => (\n                  <>\n                    {prev}\n                    <span>|</span>\n                    {curr}\n                  </>\n                ))}\n          </span>\n        </div>\n        <div className=\"media-actions\">\n          {(hasRequestable || hasRequestable4k) && (\n            <ButtonWithDropdown\n              buttonType=\"primary\"\n              onClick={() => {\n                setRequestModal(true);\n                setIs4k(!hasRequestable);\n              }}\n              text={\n                <>\n                  <ArrowDownTrayIcon />\n                  <span>\n                    {intl.formatMessage(\n                      hasRequestable\n                        ? messages.requestcollection\n                        : messages.requestcollection4k\n                    )}\n                  </span>\n                </>\n              }\n            >\n              {hasRequestable && hasRequestable4k && (\n                <ButtonWithDropdown.Item\n                  buttonType=\"primary\"\n                  onClick={() => {\n                    setRequestModal(true);\n                    setIs4k(true);\n                  }}\n                >\n                  <ArrowDownTrayIcon />\n                  <span>\n                    {intl.formatMessage(messages.requestcollection4k)}\n                  </span>\n                </ButtonWithDropdown.Item>\n              )}\n            </ButtonWithDropdown>\n          )}\n        </div>\n      </div>\n      {data.overview && (\n        <div className=\"media-overview\">\n          <div className=\"flex-1\">\n            <h2>{intl.formatMessage(messages.overview)}</h2>\n            <p>{data.overview}</p>\n          </div>\n        </div>\n      )}\n      <div className=\"slider-header\">\n        <div className=\"slider-title\">\n          <span>{intl.formatMessage(globalMessages.movies)}</span>\n        </div>\n      </div>\n      <Slider\n        sliderKey=\"collection-movies\"\n        isLoading={false}\n        isEmpty={data.parts.length === 0}\n        items={data.parts\n          .filter((title) => {\n            if (!blocklistVisibility)\n              return title.mediaInfo?.status !== MediaStatus.BLOCKLISTED;\n            return title;\n          })\n          .map((title) => (\n            <TitleCard\n              key={`collection-movie-${title.id}`}\n              id={title.id}\n              isAddedToWatchlist={title.mediaInfo?.watchlists?.length ?? 0}\n              image={title.posterPath}\n              status={title.mediaInfo?.status}\n              summary={title.overview}\n              title={title.title}\n              userScore={title.voteAverage}\n              year={title.releaseDate}\n              mediaType={title.mediaType}\n            />\n          ))}\n      />\n      <div className=\"extra-bottom-space relative\" />\n    </div>\n  );\n};\n\nexport default CollectionDetails;\n"
  },
  {
    "path": "src/components/Common/Accordion/index.tsx",
    "content": "import { useState } from 'react';\nimport AnimateHeight from 'react-animate-height';\n\nexport interface AccordionProps {\n  children: (args: AccordionChildProps) => JSX.Element;\n  /** If true, only one accordion item can be open at any time */\n  single?: boolean;\n  /** If true, at least one accordion item will always be open */\n  atLeastOne?: boolean;\n  initialOpenIndexes?: number[];\n}\nexport interface AccordionChildProps {\n  openIndexes: number[];\n  handleClick(index: number): void;\n  AccordionContent: typeof AccordionContent;\n}\n\ntype AccordionContentProps = {\n  isOpen: boolean;\n  children: React.ReactNode;\n};\n\nexport const AccordionContent = ({\n  isOpen,\n  children,\n}: AccordionContentProps) => {\n  return <AnimateHeight height={isOpen ? 'auto' : 0}>{children}</AnimateHeight>;\n};\n\nconst Accordion = ({\n  single,\n  atLeastOne,\n  initialOpenIndexes,\n  children,\n}: AccordionProps) => {\n  const initialState = initialOpenIndexes || (atLeastOne && [0]) || [];\n  const [openIndexes, setOpenIndexes] = useState<number[]>(initialState);\n\n  const close = (index: number) => {\n    const openCount = openIndexes.length;\n    const newListOfIndexes =\n      atLeastOne && openCount === 1 && openIndexes.includes(index)\n        ? openIndexes\n        : openIndexes.filter((i) => i !== index);\n\n    setOpenIndexes(newListOfIndexes);\n  };\n\n  const open = (index: number) => {\n    const newListOfIndexes = single ? [index] : [...openIndexes, index];\n    setOpenIndexes(newListOfIndexes);\n  };\n\n  const handleItemClick = (index: number) => {\n    const action = openIndexes.includes(index) ? 'closing' : 'opening';\n\n    if (action === 'closing') {\n      close(index);\n    } else {\n      open(index);\n    }\n  };\n\n  return children({\n    openIndexes: openIndexes,\n    handleClick: handleItemClick,\n    AccordionContent,\n  });\n};\n\nexport default Accordion;\n"
  },
  {
    "path": "src/components/Common/Alert/index.tsx",
    "content": "import {\n  ExclamationTriangleIcon,\n  InformationCircleIcon,\n  XCircleIcon,\n} from '@heroicons/react/24/solid';\n\ninterface AlertProps {\n  title?: React.ReactNode;\n  type?: 'warning' | 'info' | 'error';\n  children?: React.ReactNode;\n}\n\nconst Alert = ({ title, children, type }: AlertProps) => {\n  let design = {\n    bgColor: 'border border-yellow-500 backdrop-blur bg-yellow-400/20',\n    titleColor: 'text-yellow-100',\n    textColor: 'text-yellow-300',\n    svg: <ExclamationTriangleIcon className=\"h-5 w-5\" />,\n  };\n\n  switch (type) {\n    case 'info':\n      design = {\n        bgColor: 'border border-indigo-500 backdrop-blur bg-indigo-400/20',\n        titleColor: 'text-gray-100',\n        textColor: 'text-gray-300',\n        svg: <InformationCircleIcon className=\"h-5 w-5\" />,\n      };\n      break;\n    case 'error':\n      design = {\n        bgColor: 'bg-red-600',\n        titleColor: 'text-red-100',\n        textColor: 'text-red-300',\n        svg: <XCircleIcon className=\"h-5 w-5\" />,\n      };\n      break;\n  }\n\n  return (\n    <div className={`mb-4 rounded-md p-4 ${design.bgColor}`}>\n      <div className=\"flex\">\n        <div className={`flex-shrink-0 ${design.titleColor}`}>{design.svg}</div>\n        <div className=\"ml-3\">\n          {title && (\n            <div className={`text-sm font-medium ${design.titleColor}`}>\n              {title}\n            </div>\n          )}\n          {children && (\n            <div className={`mt-2 text-sm first:mt-0 ${design.textColor}`}>\n              {children}\n            </div>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default Alert;\n"
  },
  {
    "path": "src/components/Common/Badge/index.tsx",
    "content": "import Link from 'next/link';\nimport React from 'react';\n\ninterface BadgeProps {\n  badgeType?:\n    | 'default'\n    | 'primary'\n    | 'danger'\n    | 'warning'\n    | 'success'\n    | 'dark'\n    | 'light';\n  className?: string;\n  href?: string;\n  children: React.ReactNode;\n}\n\nconst Badge = (\n  { badgeType = 'default', className, href, children }: BadgeProps,\n  ref?: React.Ref<HTMLElement>\n) => {\n  const badgeStyle = [\n    'px-2 inline-flex text-xs leading-5 font-semibold rounded-full whitespace-nowrap',\n  ];\n\n  if (href) {\n    badgeStyle.push('transition cursor-pointer !no-underline');\n  } else {\n    badgeStyle.push('cursor-default');\n  }\n\n  switch (badgeType) {\n    case 'danger':\n      badgeStyle.push('bg-red-600/80 border-red-500 border !text-red-100');\n      if (href) {\n        badgeStyle.push('hover:bg-red-500');\n      }\n      break;\n    case 'warning':\n      badgeStyle.push(\n        'bg-yellow-500/80 border-yellow-500 border !text-yellow-100'\n      );\n      if (href) {\n        badgeStyle.push('hover:bg-yellow-500');\n      }\n      break;\n    case 'success':\n      badgeStyle.push(\n        'bg-green-500/80 border border-green-500 !text-green-100'\n      );\n      if (href) {\n        badgeStyle.push('hover:bg-green-500');\n      }\n      break;\n    case 'dark':\n      badgeStyle.push('bg-gray-900 !text-gray-400');\n      if (href) {\n        badgeStyle.push('hover:bg-gray-800');\n      }\n      break;\n    case 'light':\n      badgeStyle.push('bg-gray-700 !text-gray-300');\n      if (href) {\n        badgeStyle.push('hover:bg-gray-600');\n      }\n      break;\n    default:\n      badgeStyle.push(\n        'bg-indigo-500/80 border border-indigo-500 !text-indigo-100'\n      );\n      if (href) {\n        badgeStyle.push('hover:bg-indigo-500');\n      }\n  }\n\n  if (className) {\n    badgeStyle.push(className);\n  }\n\n  if (href?.includes('://')) {\n    return (\n      <a\n        href={href}\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n        className={badgeStyle.join(' ')}\n        ref={ref as React.Ref<HTMLAnchorElement>}\n      >\n        {children}\n      </a>\n    );\n  } else if (href) {\n    return (\n      <Link\n        href={href}\n        className={badgeStyle.join(' ')}\n        ref={ref as React.Ref<HTMLAnchorElement>}\n      >\n        {children}\n      </Link>\n    );\n  } else {\n    return (\n      <span\n        className={badgeStyle.join(' ')}\n        ref={ref as React.Ref<HTMLSpanElement>}\n      >\n        {children}\n      </span>\n    );\n  }\n};\n\nexport default React.forwardRef(Badge) as typeof Badge;\n"
  },
  {
    "path": "src/components/Common/Button/index.tsx",
    "content": "import type { ForwardedRef } from 'react';\nimport React from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport type ButtonType =\n  | 'default'\n  | 'primary'\n  | 'danger'\n  | 'warning'\n  | 'success'\n  | 'ghost';\n\n// Helper type to override types (overrides onClick)\ntype MergeElementProps<\n  T extends React.ElementType,\n  P extends Record<string, unknown>,\n> = Omit<React.ComponentProps<T>, keyof P> & P;\n\ntype ElementTypes = 'button' | 'a';\n\ntype Element<P extends ElementTypes = 'button'> = P extends 'a'\n  ? HTMLAnchorElement\n  : HTMLButtonElement;\n\ntype BaseProps<P> = {\n  buttonType?: ButtonType;\n  buttonSize?: 'default' | 'lg' | 'md' | 'sm';\n  // Had to do declare this manually as typescript would assume e was of type any otherwise\n  onClick?: (\n    e: React.MouseEvent<P extends 'a' ? HTMLAnchorElement : HTMLButtonElement>\n  ) => void;\n};\n\ntype ButtonProps<P extends React.ElementType> = {\n  as?: P;\n} & MergeElementProps<P, BaseProps<P>>;\n\nfunction Button<P extends ElementTypes = 'button'>(\n  {\n    buttonType = 'default',\n    buttonSize = 'default',\n    as,\n    children,\n    className,\n    ...props\n  }: ButtonProps<P>,\n  ref?: React.Ref<Element<P>>\n): JSX.Element {\n  const buttonStyle = [\n    'inline-flex items-center justify-center border leading-5 font-medium rounded-md focus:outline-none transition ease-in-out duration-150 cursor-pointer disabled:opacity-50 whitespace-nowrap',\n  ];\n  switch (buttonType) {\n    case 'primary':\n      buttonStyle.push(\n        'text-white border border-indigo-500 bg-indigo-600/80 hover:bg-indigo-600 hover:border-indigo-500 focus:border-indigo-700 focus:ring-indigo active:bg-indigo-600 active:border-indigo-700'\n      );\n      break;\n    case 'danger':\n      buttonStyle.push(\n        'text-white bg-red-600/80 border-red-500 hover:bg-red-600 hover:border-red-500 focus:border-red-700 focus:ring-red active:bg-red-700 active:border-red-700'\n      );\n      break;\n    case 'warning':\n      buttonStyle.push(\n        'text-white border border-yellow-500 bg-yellow-500/80 hover:bg-yellow-500 hover:border-yellow-400 focus:border-yellow-700 focus:ring-yellow active:bg-yellow-500 active:border-yellow-700'\n      );\n      break;\n    case 'success':\n      buttonStyle.push(\n        'text-white bg-green-500/80 border-green-500 hover:bg-green-500 hover:border-green-400 focus:border-green-700 focus:ring-green active:bg-green-500 active:border-green-700'\n      );\n      break;\n    case 'ghost':\n      buttonStyle.push(\n        'text-white bg-transparent border-gray-600 hover:border-gray-200 focus:border-gray-100 active:border-gray-100'\n      );\n      break;\n    default:\n      buttonStyle.push(\n        'text-gray-200 bg-gray-800/80 border-gray-600 hover:text-white hover:bg-gray-700 hover:border-gray-600 group-hover:text-white group-hover:bg-gray-700 group-hover:border-gray-600 focus:border-blue-300 focus:ring-blue active:text-gray-200 active:bg-gray-700 active:border-gray-600'\n      );\n  }\n\n  switch (buttonSize) {\n    case 'sm':\n      buttonStyle.push('px-2.5 py-1.5 text-xs button-sm');\n      break;\n    case 'lg':\n      buttonStyle.push('px-6 py-3 text-base button-lg');\n      break;\n    case 'md':\n    default:\n      buttonStyle.push('px-4 py-2 text-sm button-md');\n  }\n\n  buttonStyle.push(className ?? '');\n\n  if (as === 'a') {\n    return (\n      <a\n        className={twMerge(buttonStyle)}\n        {...(props as React.ComponentProps<'a'>)}\n        ref={ref as ForwardedRef<HTMLAnchorElement>}\n      >\n        <span className=\"flex items-center\">{children}</span>\n      </a>\n    );\n  } else {\n    return (\n      <button\n        className={twMerge(buttonStyle)}\n        {...(props as React.ComponentProps<'button'>)}\n        ref={ref as ForwardedRef<HTMLButtonElement>}\n      >\n        <span className=\"flex items-center\">{children}</span>\n      </button>\n    );\n  }\n}\n\nexport default React.forwardRef(Button) as typeof Button;\n"
  },
  {
    "path": "src/components/Common/ButtonWithDropdown/index.tsx",
    "content": "import Dropdown from '@app/components/Common/Dropdown';\nimport { withProperties } from '@app/utils/typeHelpers';\nimport { Menu } from '@headlessui/react';\nimport { ChevronDownIcon } from '@heroicons/react/24/solid';\nimport type { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react';\n\ntype ButtonWithDropdownProps = {\n  text: React.ReactNode;\n  dropdownIcon?: React.ReactNode;\n  buttonType?: 'primary' | 'ghost';\n} & (\n  | ({ as?: 'button' } & ButtonHTMLAttributes<HTMLButtonElement>)\n  | ({ as: 'a' } & AnchorHTMLAttributes<HTMLAnchorElement>)\n);\n\nconst ButtonWithDropdown = ({\n  text,\n  children,\n  dropdownIcon,\n  className,\n  buttonType = 'primary',\n  ...props\n}: ButtonWithDropdownProps) => {\n  const styleClasses = {\n    mainButtonClasses: 'button-md text-white border',\n    dropdownSideButtonClasses: 'button-md border',\n  };\n\n  switch (buttonType) {\n    case 'ghost':\n      styleClasses.mainButtonClasses +=\n        ' bg-transparent border-gray-600 hover:border-gray-200 focus:border-gray-100 active:border-gray-100';\n      styleClasses.dropdownSideButtonClasses = styleClasses.mainButtonClasses;\n      break;\n    default:\n      styleClasses.mainButtonClasses +=\n        ' bg-indigo-600/80 border-indigo-500 hover:bg-indigo-600 hover:border-indigo-500 active:bg-indigo-700 active:border-indigo-700 focus:ring-blue';\n      styleClasses.dropdownSideButtonClasses +=\n        ' bg-indigo-600/80 border-indigo-500 hover:bg-indigo-600 active:bg-indigo-600 focus:ring-blue';\n  }\n\n  const TriggerElement = props.as ?? 'button';\n\n  return (\n    <Menu as=\"div\" className=\"relative z-10 inline-flex\">\n      <TriggerElement\n        type=\"button\"\n        className={`relative z-10 inline-flex h-full items-center px-4 py-2 text-sm font-medium leading-5 transition duration-150 ease-in-out hover:z-20 focus:z-20 focus:outline-none ${\n          styleClasses.mainButtonClasses\n        } ${children ? 'rounded-l-md' : 'rounded-md'} ${className}`}\n        {...(props as Record<string, string>)}\n      >\n        {text}\n      </TriggerElement>\n      {children && (\n        <span className=\"relative -ml-px block\">\n          <Menu.Button\n            type=\"button\"\n            className={`relative z-10 inline-flex h-full items-center rounded-r-md px-2 py-2 text-sm font-medium leading-5 text-white transition duration-150 ease-in-out hover:z-20 focus:z-20 ${styleClasses.dropdownSideButtonClasses}`}\n            aria-label=\"Expand\"\n          >\n            {dropdownIcon ? dropdownIcon : <ChevronDownIcon />}\n          </Menu.Button>\n          <Dropdown.Items dropdownType={buttonType}>{children}</Dropdown.Items>\n        </span>\n      )}\n    </Menu>\n  );\n};\nexport default withProperties(ButtonWithDropdown, { Item: Dropdown.Item });\n"
  },
  {
    "path": "src/components/Common/CachedImage/index.tsx",
    "content": "import useSettings from '@app/hooks/useSettings';\nimport type { ImageLoader, ImageProps } from 'next/image';\nimport Image from 'next/image';\n\nconst imageLoader: ImageLoader = ({ src }) => src;\n\nexport type CachedImageProps = ImageProps & {\n  src: string;\n  type: 'tmdb' | 'avatar' | 'tvdb';\n};\n\n/**\n * The CachedImage component should be used wherever\n * we want to offer the option to locally cache images.\n **/\nconst CachedImage = ({ src, type, ...props }: CachedImageProps) => {\n  const { currentSettings } = useSettings();\n\n  let imageUrl: string;\n\n  if (type === 'tmdb') {\n    // tmdb stuff\n    imageUrl =\n      currentSettings.cacheImages && !src.startsWith('/')\n        ? src.replace(/^https:\\/\\/image\\.tmdb\\.org\\//, '/imageproxy/tmdb/')\n        : src;\n  } else if (type === 'tvdb') {\n    imageUrl =\n      currentSettings.cacheImages && !src.startsWith('/')\n        ? src.replace(\n            /^https:\\/\\/artworks\\.thetvdb\\.com\\//,\n            '/imageproxy/tvdb/'\n          )\n        : src;\n  } else if (type === 'avatar') {\n    // jellyfin avatar (if any)\n    imageUrl = src;\n  } else {\n    return null;\n  }\n\n  return <Image unoptimized loader={imageLoader} src={imageUrl} {...props} />;\n};\n\nexport default CachedImage;\n"
  },
  {
    "path": "src/components/Common/ConfirmButton/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport useClickOutside from '@app/hooks/useClickOutside';\nimport { forwardRef, useRef, useState } from 'react';\n\ninterface ConfirmButtonProps {\n  onClick: () => void;\n  confirmText: React.ReactNode;\n  className?: string;\n  children: React.ReactNode;\n}\n\nconst ConfirmButton = forwardRef<HTMLButtonElement, ConfirmButtonProps>(\n  ({ onClick, children, confirmText, className }, parentRef) => {\n    const ref = useRef(null);\n    useClickOutside(ref, () => setIsClicked(false));\n    const [isClicked, setIsClicked] = useState(false);\n    return (\n      <Button\n        ref={parentRef}\n        buttonType=\"danger\"\n        className={`relative overflow-hidden ${className}`}\n        onClick={(e) => {\n          e.preventDefault();\n\n          if (!isClicked) {\n            setIsClicked(true);\n          } else {\n            onClick();\n          }\n        }}\n      >\n        <div\n          ref={ref}\n          className={`relative inset-0 flex h-full w-full transform-gpu items-center justify-center transition duration-300 ${\n            isClicked\n              ? '-translate-y-full opacity-0'\n              : 'translate-y-0 opacity-100'\n          }`}\n        >\n          {children}\n        </div>\n        <div\n          ref={ref}\n          className={`absolute inset-0 flex h-full w-full transform-gpu items-center justify-center transition duration-300 ${\n            isClicked\n              ? 'translate-y-0 opacity-100'\n              : 'translate-y-full opacity-0'\n          }`}\n        >\n          {confirmText}\n        </div>\n      </Button>\n    );\n  }\n);\n\nConfirmButton.displayName = 'ConfirmButton';\n\nexport default ConfirmButton;\n"
  },
  {
    "path": "src/components/Common/Dropdown/index.tsx",
    "content": "import { withProperties } from '@app/utils/typeHelpers';\nimport { Menu, Transition } from '@headlessui/react';\nimport { ChevronDownIcon } from '@heroicons/react/24/solid';\nimport {\n  Fragment,\n  useRef,\n  type AnchorHTMLAttributes,\n  type ButtonHTMLAttributes,\n  type HTMLAttributes,\n} from 'react';\n\ninterface DropdownItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n  buttonType?: 'primary' | 'ghost';\n}\n\nconst DropdownItem = ({\n  children,\n  buttonType = 'primary',\n  ...props\n}: DropdownItemProps) => {\n  return (\n    <Menu.Item>\n      <a\n        className={[\n          'button-md flex cursor-pointer items-center rounded px-4 py-2 text-sm leading-5 text-white focus:text-white focus:outline-none',\n          buttonType === 'ghost'\n            ? 'bg-transparent from-indigo-600 to-purple-600 hover:bg-gradient-to-br focus:border-gray-500'\n            : 'bg-indigo-600 hover:bg-indigo-500 focus:border-indigo-700',\n        ].join(' ')}\n        {...props}\n      >\n        {children}\n      </a>\n    </Menu.Item>\n  );\n};\n\ntype DropdownItemsProps = HTMLAttributes<HTMLDivElement> & {\n  dropdownType: 'primary' | 'ghost';\n};\n\nconst DropdownItems = ({\n  children,\n  className,\n  dropdownType,\n  ...props\n}: DropdownItemsProps) => {\n  return (\n    <Transition\n      as={Fragment}\n      enter=\"transition ease-out duration-100\"\n      enterFrom=\"opacity-0 scale-95\"\n      enterTo=\"opacity-100 scale-100\"\n      leave=\"transition ease-in duration-75\"\n      leaveFrom=\"opacity-100 scale-100\"\n      leaveTo=\"opacity-0 scale-95\"\n    >\n      <Menu.Items\n        className={[\n          'absolute right-0 z-40 -mr-1 mt-2 w-56 origin-top-right rounded-md p-1 shadow-lg',\n          dropdownType === 'ghost'\n            ? 'border border-gray-700 bg-gray-800/80 backdrop-blur'\n            : 'bg-indigo-600',\n          className,\n        ].join(' ')}\n        {...props}\n      >\n        <div className=\"py-1\">{children}</div>\n      </Menu.Items>\n    </Transition>\n  );\n};\n\ninterface DropdownProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n  text: React.ReactNode;\n  dropdownIcon?: React.ReactNode;\n  buttonType?: 'primary' | 'ghost';\n}\n\nconst Dropdown = ({\n  text,\n  children,\n  dropdownIcon,\n  className,\n  buttonType = 'primary',\n  ...props\n}: DropdownProps) => {\n  const buttonRef = useRef<HTMLButtonElement>(null);\n\n  return (\n    <Menu as=\"div\" className=\"relative z-10\">\n      <Menu.Button\n        type=\"button\"\n        className={[\n          'button-md inline-flex h-full items-center space-x-2 rounded-md border px-4 py-2 text-sm font-medium leading-5 text-white transition duration-150 ease-in-out hover:z-20 focus:z-20 focus:outline-none',\n          buttonType === 'ghost'\n            ? 'border-gray-600 bg-transparent hover:border-gray-200 focus:border-gray-100 active:border-gray-100'\n            : `focus:ring-blue border-indigo-500 bg-indigo-600/80 hover:border-indigo-500 hover:bg-indigo-600 active:border-indigo-700 active:bg-indigo-700`,\n          className,\n        ].join(' ')}\n        ref={buttonRef}\n        disabled={!children}\n        {...props}\n      >\n        <span>{text}</span>\n        {children && (dropdownIcon ? dropdownIcon : <ChevronDownIcon />)}\n      </Menu.Button>\n      {children && (\n        <DropdownItems dropdownType={buttonType}>{children}</DropdownItems>\n      )}\n    </Menu>\n  );\n};\nexport default withProperties(Dropdown, {\n  Item: DropdownItem,\n  Items: DropdownItems,\n});\n"
  },
  {
    "path": "src/components/Common/Header/index.tsx",
    "content": "interface HeaderProps {\n  extraMargin?: number;\n  subtext?: React.ReactNode;\n  children: React.ReactNode;\n}\n\nconst Header = ({ children, extraMargin = 0, subtext }: HeaderProps) => {\n  return (\n    <div className=\"mt-8 md:flex md:items-center md:justify-between\">\n      <div className={`min-w-0 flex-1 mx-${extraMargin}`}>\n        <h2\n          className=\"mb-4 truncate text-2xl font-bold leading-7 text-gray-100 sm:overflow-visible sm:text-4xl sm:leading-9 md:mb-0\"\n          data-testid=\"page-header\"\n        >\n          <span className=\"text-overseerr\">{children}</span>\n        </h2>\n        {subtext && <div className=\"mt-2 text-gray-400\">{subtext}</div>}\n      </div>\n    </div>\n  );\n};\n\nexport default Header;\n"
  },
  {
    "path": "src/components/Common/ImageFader/index.tsx",
    "content": "import CachedImage from '@app/components/Common/CachedImage';\nimport type { ForwardRefRenderFunction, HTMLAttributes } from 'react';\nimport React, { useEffect, useState } from 'react';\n\ninterface ImageFaderProps extends HTMLAttributes<HTMLDivElement> {\n  backgroundImages: string[];\n  rotationSpeed?: number;\n  isDarker?: boolean;\n  forceOptimize?: boolean;\n}\n\nconst DEFAULT_ROTATION_SPEED = 6000;\n\nconst ImageFader: ForwardRefRenderFunction<HTMLDivElement, ImageFaderProps> = (\n  {\n    backgroundImages,\n    rotationSpeed = DEFAULT_ROTATION_SPEED,\n    isDarker,\n    forceOptimize,\n    ...props\n  },\n  ref\n) => {\n  const [activeIndex, setIndex] = useState(0);\n\n  useEffect(() => {\n    const interval = setInterval(\n      () => setIndex((ai) => (ai + 1) % backgroundImages.length),\n      rotationSpeed\n    );\n\n    return () => {\n      clearInterval(interval);\n    };\n  }, [backgroundImages, rotationSpeed]);\n\n  let gradient =\n    'linear-gradient(180deg, rgba(45, 55, 72, 0.47) 0%, #1A202E 100%)';\n\n  if (isDarker) {\n    gradient =\n      'linear-gradient(180deg, rgba(17, 24, 39, 0.47) 0%, rgba(17, 24, 39, 1) 100%)';\n  }\n\n  let overrides = {};\n\n  if (forceOptimize) {\n    overrides = {\n      unoptimized: false,\n    };\n  }\n\n  return (\n    <div ref={ref}>\n      {backgroundImages.map((imageUrl, i) => (\n        <div\n          key={`banner-image-${i}`}\n          className={`absolute-top-shift absolute inset-0 bg-cover bg-center transition-opacity duration-300 ease-in ${\n            i === activeIndex ? 'opacity-100' : 'opacity-0'\n          }`}\n          {...props}\n        >\n          <CachedImage\n            type=\"tmdb\"\n            className=\"absolute inset-0 h-full w-full\"\n            alt=\"\"\n            src={imageUrl}\n            style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n            fill\n            {...overrides}\n          />\n          <div\n            className=\"absolute inset-0\"\n            style={{ backgroundImage: gradient }}\n          />\n        </div>\n      ))}\n    </div>\n  );\n};\n\nexport default React.forwardRef<HTMLDivElement, ImageFaderProps>(ImageFader);\n"
  },
  {
    "path": "src/components/Common/LabeledCheckbox/index.tsx",
    "content": "import { Field } from 'formik';\nimport { twMerge } from 'tailwind-merge';\n\ninterface LabeledCheckboxProps {\n  id: string;\n  className?: string;\n  label: string;\n  description: string;\n  onChange: () => void;\n  children?: React.ReactNode;\n}\n\nconst LabeledCheckbox: React.FC<LabeledCheckboxProps> = ({\n  id,\n  className,\n  label,\n  description,\n  onChange,\n  children,\n}) => {\n  return (\n    <>\n      <div className={twMerge('relative flex items-start', className)}>\n        <div className=\"flex h-6 items-center\">\n          <Field type=\"checkbox\" id={id} name={id} onChange={onChange} />\n        </div>\n        <div className=\"ml-3 text-sm leading-6\">\n          <label htmlFor=\"localLogin\" className=\"block\" aria-label={label}>\n            <div className=\"flex flex-col\">\n              <span className=\"font-medium text-white\">{label}</span>\n              <span className=\"font-normal text-gray-400\">{description}</span>\n            </div>\n          </label>\n        </div>\n      </div>\n      {\n        /* can hold child checkboxes */\n        children && <div className=\"mt-4 pl-10\">{children}</div>\n      }\n    </>\n  );\n};\n\nexport default LabeledCheckbox;\n"
  },
  {
    "path": "src/components/Common/List/index.tsx",
    "content": "import { withProperties } from '@app/utils/typeHelpers';\n\ninterface ListItemProps {\n  title: string;\n  className?: string;\n  children: React.ReactNode;\n}\n\nconst ListItem = ({ title, className, children }: ListItemProps) => {\n  return (\n    <div>\n      <div className=\"max-w-6xl py-4 sm:grid sm:grid-cols-3 sm:gap-4\">\n        <dt className=\"block text-sm font-bold text-gray-400\">{title}</dt>\n        <dd className=\"flex text-sm text-white sm:col-span-2 sm:mt-0\">\n          <span className={`flex-grow ${className}`}>{children}</span>\n        </dd>\n      </div>\n    </div>\n  );\n};\n\ninterface ListProps {\n  title: string;\n  subTitle?: string;\n  children: React.ReactNode;\n}\n\nconst List = ({ title, subTitle, children }: ListProps) => {\n  return (\n    <>\n      <div>\n        <h3 className=\"heading\">{title}</h3>\n        {subTitle && <p className=\"description\">{subTitle}</p>}\n      </div>\n      <div className=\"section border-t border-gray-800\">\n        <dl className=\"divide-y divide-gray-800\">{children}</dl>\n      </div>\n    </>\n  );\n};\n\nexport default withProperties(List, { Item: ListItem });\n"
  },
  {
    "path": "src/components/Common/ListView/index.tsx",
    "content": "import PersonCard from '@app/components/PersonCard';\nimport TitleCard from '@app/components/TitleCard';\nimport TmdbTitleCard from '@app/components/TitleCard/TmdbTitleCard';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport useVerticalScroll from '@app/hooks/useVerticalScroll';\nimport globalMessages from '@app/i18n/globalMessages';\nimport { MediaStatus } from '@server/constants/media';\nimport type { WatchlistItem } from '@server/interfaces/api/discoverInterfaces';\nimport type {\n  CollectionResult,\n  MovieResult,\n  PersonResult,\n  TvResult,\n} from '@server/models/Search';\nimport { useIntl } from 'react-intl';\n\ntype ListViewProps = {\n  items?: (TvResult | MovieResult | PersonResult | CollectionResult)[];\n  plexItems?: WatchlistItem[];\n  isEmpty?: boolean;\n  isLoading?: boolean;\n  isReachingEnd?: boolean;\n  onScrollBottom: () => void;\n  mutateParent?: () => void;\n};\n\nconst ListView = ({\n  items,\n  isEmpty,\n  isLoading,\n  onScrollBottom,\n  isReachingEnd,\n  plexItems,\n  mutateParent,\n}: ListViewProps) => {\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n  useVerticalScroll(onScrollBottom, !isLoading && !isEmpty && !isReachingEnd);\n\n  const blocklistVisibility = hasPermission(\n    [Permission.MANAGE_BLOCKLIST, Permission.VIEW_BLOCKLIST],\n    { type: 'or' }\n  );\n\n  return (\n    <>\n      {isEmpty && (\n        <div className=\"mt-64 w-full text-center text-2xl text-gray-400\">\n          {intl.formatMessage(globalMessages.noresults)}\n        </div>\n      )}\n      <ul className=\"cards-vertical\">\n        {plexItems?.map((title, index) => {\n          return (\n            <li key={`${title.ratingKey}-${index}`}>\n              <TmdbTitleCard\n                id={title.tmdbId}\n                tmdbId={title.tmdbId}\n                type={title.mediaType}\n                isAddedToWatchlist={true}\n                canExpand\n                mutateParent={mutateParent}\n              />\n            </li>\n          );\n        })}\n        {items\n          ?.filter((title) => {\n            if (!blocklistVisibility)\n              return (\n                (title as TvResult | MovieResult).mediaInfo?.status !==\n                MediaStatus.BLOCKLISTED\n              );\n            return title;\n          })\n          .map((title, index) => {\n            let titleCard: React.ReactNode;\n\n            switch (title.mediaType) {\n              case 'movie':\n                titleCard = (\n                  <TitleCard\n                    key={title.id}\n                    id={title.id}\n                    isAddedToWatchlist={\n                      title.mediaInfo?.watchlists?.length ?? 0\n                    }\n                    image={title.posterPath}\n                    status={title.mediaInfo?.status}\n                    summary={title.overview}\n                    title={title.title}\n                    userScore={title.voteAverage}\n                    year={title.releaseDate}\n                    mediaType={title.mediaType}\n                    inProgress={\n                      (title.mediaInfo?.downloadStatus ?? []).length > 0\n                    }\n                    canExpand\n                  />\n                );\n                break;\n              case 'tv':\n                titleCard = (\n                  <TitleCard\n                    key={title.id}\n                    id={title.id}\n                    isAddedToWatchlist={\n                      title.mediaInfo?.watchlists?.length ?? 0\n                    }\n                    image={title.posterPath}\n                    status={title.mediaInfo?.status}\n                    summary={title.overview}\n                    title={title.name}\n                    userScore={title.voteAverage}\n                    year={title.firstAirDate}\n                    mediaType={title.mediaType}\n                    inProgress={\n                      (title.mediaInfo?.downloadStatus ?? []).length > 0\n                    }\n                    canExpand\n                  />\n                );\n                break;\n              case 'collection':\n                titleCard = (\n                  <TitleCard\n                    id={title.id}\n                    image={title.posterPath}\n                    summary={title.overview}\n                    title={title.title}\n                    mediaType={title.mediaType}\n                    canExpand\n                  />\n                );\n                break;\n              case 'person':\n                titleCard = (\n                  <PersonCard\n                    personId={title.id}\n                    name={title.name}\n                    profilePath={title.profilePath}\n                    canExpand\n                  />\n                );\n                break;\n            }\n\n            return <li key={`${title.id}-${index}`}>{titleCard}</li>;\n          })}\n        {isLoading &&\n          !isReachingEnd &&\n          [...Array(20)].map((_item, i) => (\n            <li key={`placeholder-${i}`}>\n              <TitleCard.Placeholder canExpand />\n            </li>\n          ))}\n      </ul>\n    </>\n  );\n};\n\nexport default ListView;\n"
  },
  {
    "path": "src/components/Common/LoadingSpinner/index.tsx",
    "content": "export const SmallLoadingSpinner = () => {\n  return (\n    <div className=\"inset-0 flex h-full w-full items-center justify-center text-gray-200\">\n      <svg\n        className=\"h-10 w-10\"\n        viewBox=\"0 0 38 38\"\n        xmlns=\"http://www.w3.org/2000/svg\"\n        stroke=\"currentColor\"\n      >\n        <g fill=\"none\" fillRule=\"evenodd\">\n          <g transform=\"translate(1 1)\" strokeWidth=\"2\">\n            <circle strokeOpacity=\".5\" cx=\"18\" cy=\"18\" r=\"18\" />\n            <path d=\"M36 18c0-9.94-8.06-18-18-18\">\n              <animateTransform\n                attributeName=\"transform\"\n                type=\"rotate\"\n                from=\"0 18 18\"\n                to=\"360 18 18\"\n                dur=\"1s\"\n                repeatCount=\"indefinite\"\n              />\n            </path>\n          </g>\n        </g>\n      </svg>\n    </div>\n  );\n};\n\nconst LoadingSpinner = () => {\n  return (\n    <div className=\"inset-0 flex h-64 items-center justify-center text-gray-200\">\n      <svg\n        className=\"h-16 w-16\"\n        viewBox=\"0 0 38 38\"\n        xmlns=\"http://www.w3.org/2000/svg\"\n        stroke=\"currentColor\"\n      >\n        <g fill=\"none\" fillRule=\"evenodd\">\n          <g transform=\"translate(1 1)\" strokeWidth=\"2\">\n            <circle strokeOpacity=\".5\" cx=\"18\" cy=\"18\" r=\"18\" />\n            <path d=\"M36 18c0-9.94-8.06-18-18-18\">\n              <animateTransform\n                attributeName=\"transform\"\n                type=\"rotate\"\n                from=\"0 18 18\"\n                to=\"360 18 18\"\n                dur=\"1s\"\n                repeatCount=\"indefinite\"\n              />\n            </path>\n          </g>\n        </g>\n      </svg>\n    </div>\n  );\n};\n\nexport default LoadingSpinner;\n"
  },
  {
    "path": "src/components/Common/Modal/index.tsx",
    "content": "import type { ButtonType } from '@app/components/Common/Button';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport useClickOutside from '@app/hooks/useClickOutside';\nimport { useLockBodyScroll } from '@app/hooks/useLockBodyScroll';\nimport globalMessages from '@app/i18n/globalMessages';\nimport { Transition } from '@headlessui/react';\nimport type { MouseEvent } from 'react';\nimport React, { Fragment, useEffect, useRef } from 'react';\nimport ReactDOM from 'react-dom';\nimport { useIntl } from 'react-intl';\n\ninterface ModalProps {\n  title?: string;\n  subTitle?: string;\n  onCancel?: (e?: MouseEvent<HTMLElement>) => void;\n  onOk?: (e?: MouseEvent<HTMLButtonElement>) => void;\n  onSecondary?: (e?: MouseEvent<HTMLButtonElement>) => void;\n  onTertiary?: (e?: MouseEvent<HTMLButtonElement>) => void;\n  cancelText?: string;\n  okText?: string;\n  secondaryText?: string;\n  tertiaryText?: string;\n  okDisabled?: boolean;\n  cancelButtonType?: ButtonType;\n  okButtonType?: ButtonType;\n  secondaryButtonType?: ButtonType;\n  secondaryDisabled?: boolean;\n  tertiaryDisabled?: boolean;\n  tertiaryButtonType?: ButtonType;\n  okButtonProps?: React.ButtonHTMLAttributes<HTMLButtonElement>;\n  cancelButtonProps?: React.ButtonHTMLAttributes<HTMLButtonElement>;\n  secondaryButtonProps?: React.ButtonHTMLAttributes<HTMLButtonElement>;\n  tertiaryButtonProps?: React.ButtonHTMLAttributes<HTMLButtonElement>;\n  disableScrollLock?: boolean;\n  backgroundClickable?: boolean;\n  loading?: boolean;\n  backdrop?: string;\n  children?: React.ReactNode;\n  dialogClass?: string;\n}\n\nconst Modal = React.forwardRef<HTMLDivElement, ModalProps>(\n  (\n    {\n      title,\n      subTitle,\n      onCancel,\n      onOk,\n      cancelText,\n      okText,\n      okDisabled = false,\n      cancelButtonType = 'default',\n      okButtonType = 'primary',\n      children,\n      disableScrollLock,\n      backgroundClickable = true,\n      secondaryButtonType = 'default',\n      secondaryDisabled = false,\n      onSecondary,\n      secondaryText,\n      tertiaryButtonType = 'default',\n      tertiaryDisabled = false,\n      tertiaryText,\n      loading = false,\n      onTertiary,\n      backdrop,\n      dialogClass,\n      okButtonProps,\n      cancelButtonProps,\n      secondaryButtonProps,\n      tertiaryButtonProps,\n    },\n    parentRef\n  ) => {\n    const intl = useIntl();\n    const modalRef = useRef<HTMLDivElement>(null);\n    const backgroundClickableRef = useRef(backgroundClickable); // This ref is used to detect state change inside the useClickOutside hook\n    useEffect(() => {\n      backgroundClickableRef.current = backgroundClickable;\n    }, [backgroundClickable]);\n    useClickOutside(modalRef, () => {\n      if (onCancel && backgroundClickableRef.current) {\n        onCancel();\n      }\n    });\n    useLockBodyScroll(true, disableScrollLock);\n\n    return ReactDOM.createPortal(\n      <Transition.Child\n        appear\n        as=\"div\"\n        className=\"fixed bottom-0 left-0 right-0 top-0 z-50 flex h-full w-full items-center justify-center bg-gray-800/70\"\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        ref={parentRef}\n      >\n        <Transition\n          appear\n          as={Fragment}\n          enter=\"transition duration-300\"\n          enterFrom=\"opacity-0 scale-75\"\n          enterTo=\"opacity-100 scale-100\"\n          leave=\"transition-opacity duration-300\"\n          leaveFrom=\"opacity-100\"\n          leaveTo=\"opacity-0\"\n          show={loading}\n        >\n          <div style={{ position: 'absolute' }}>\n            <LoadingSpinner />\n          </div>\n        </Transition>\n        <Transition\n          className={`hide-scrollbar relative inline-block w-full overflow-auto bg-gray-800 px-4 pb-4 pt-4 text-left align-bottom shadow-xl ring-1 ring-gray-700 transition-all sm:my-8 sm:max-w-3xl sm:rounded-lg sm:align-middle ${dialogClass}`}\n          role=\"dialog\"\n          aria-modal=\"true\"\n          aria-labelledby=\"modal-headline\"\n          style={{\n            maxHeight: 'calc(100% - env(safe-area-inset-top) * 2)',\n          }}\n          appear\n          as=\"div\"\n          enter=\"transition duration-300\"\n          enterFrom=\"opacity-0 scale-75\"\n          enterTo=\"opacity-100 scale-100\"\n          leave=\"transition-opacity duration-300\"\n          leaveFrom=\"opacity-100\"\n          leaveTo=\"opacity-0\"\n          show={!loading}\n          ref={modalRef}\n        >\n          {backdrop && (\n            <div className=\"absolute left-0 right-0 top-0 z-0 h-64 max-h-full w-full\">\n              <CachedImage\n                type=\"tmdb\"\n                alt=\"\"\n                src={backdrop}\n                style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n                fill\n                priority\n              />\n              <div\n                className=\"absolute inset-0\"\n                style={{\n                  backgroundImage:\n                    'linear-gradient(180deg, rgba(31, 41, 55, 0.75) 0%, rgba(31, 41, 55, 1) 100%)',\n                }}\n              />\n            </div>\n          )}\n          <div className=\"relative -mx-4 overflow-x-hidden px-4 pt-0.5 sm:flex sm:items-center\">\n            <div\n              className={`mt-3 truncate text-center text-white sm:mt-0 sm:text-left`}\n            >\n              {(title || subTitle) && (\n                <div className=\"flex flex-col space-y-1\">\n                  {title && (\n                    <span\n                      className=\"text-overseerr truncate pb-0.5 text-2xl font-bold leading-6\"\n                      id=\"modal-headline\"\n                      data-testid=\"modal-title\"\n                    >\n                      {title}\n                    </span>\n                  )}\n                  {subTitle && (\n                    <span\n                      className=\"truncate text-lg font-semibold leading-6 text-gray-200\"\n                      id=\"modal-headline\"\n                      data-testid=\"modal-title\"\n                    >\n                      {subTitle}\n                    </span>\n                  )}\n                </div>\n              )}\n            </div>\n          </div>\n          {children && (\n            <div\n              className={`relative mt-4 text-sm leading-5 text-gray-300 ${\n                !(onCancel || onOk || onSecondary || onTertiary) ? 'mb-3' : ''\n              }`}\n            >\n              {children}\n            </div>\n          )}\n          {(onCancel || onOk || onSecondary || onTertiary) && (\n            <div className=\"relative mt-5 flex flex-row-reverse justify-center sm:mt-4 sm:justify-start\">\n              {typeof onOk === 'function' && (\n                <Button\n                  buttonType={okButtonType}\n                  onClick={onOk}\n                  className=\"ml-3\"\n                  disabled={okDisabled}\n                  data-testid=\"modal-ok-button\"\n                  {...okButtonProps}\n                >\n                  {okText ? okText : 'Ok'}\n                </Button>\n              )}\n              {typeof onSecondary === 'function' && secondaryText && (\n                <Button\n                  buttonType={secondaryButtonType}\n                  onClick={onSecondary}\n                  className=\"ml-3\"\n                  disabled={secondaryDisabled}\n                  data-testid=\"modal-secondary-button\"\n                  {...secondaryButtonProps}\n                >\n                  {secondaryText}\n                </Button>\n              )}\n              {typeof onTertiary === 'function' && tertiaryText && (\n                <Button\n                  buttonType={tertiaryButtonType}\n                  onClick={onTertiary}\n                  className=\"ml-3\"\n                  disabled={tertiaryDisabled}\n                  {...tertiaryButtonProps}\n                >\n                  {tertiaryText}\n                </Button>\n              )}\n              {typeof onCancel === 'function' && (\n                <Button\n                  buttonType={cancelButtonType}\n                  onClick={onCancel}\n                  className=\"ml-3 sm:ml-0\"\n                  data-testid=\"modal-cancel-button\"\n                  {...cancelButtonProps}\n                >\n                  {cancelText\n                    ? cancelText\n                    : intl.formatMessage(globalMessages.cancel)}\n                </Button>\n              )}\n            </div>\n          )}\n        </Transition>\n      </Transition.Child>,\n      document.body\n    );\n  }\n);\n\nModal.displayName = 'Modal';\n\nexport default Modal;\n"
  },
  {
    "path": "src/components/Common/MultiRangeSlider/index.tsx",
    "content": "import Tooltip from '@app/components/Common/Tooltip';\nimport useDebouncedState from '@app/hooks/useDebouncedState';\nimport { useEffect, useRef } from 'react';\n\ntype MultiRangeSliderProps = {\n  min: number;\n  max: number;\n  defaultMinValue?: number;\n  defaultMaxValue?: number;\n  subText?: string;\n  onUpdateMin: (min: number) => void;\n  onUpdateMax: (max: number) => void;\n};\n\nconst MultiRangeSlider = ({\n  min,\n  max,\n  defaultMinValue,\n  defaultMaxValue,\n  subText,\n  onUpdateMin,\n  onUpdateMax,\n}: MultiRangeSliderProps) => {\n  const touched = useRef(false);\n  const [valueMin, finalValueMin, setValueMin] = useDebouncedState(\n    defaultMinValue ?? min\n  );\n  const [valueMax, finalValueMax, setValueMax] = useDebouncedState(\n    defaultMaxValue ?? max\n  );\n\n  const minThumb = ((valueMin - min) / (max - min)) * 100;\n  const maxThumb = ((valueMax - min) / (max - min)) * 100;\n\n  useEffect(() => {\n    if (touched.current) {\n      onUpdateMin(finalValueMin);\n    }\n  }, [finalValueMin, onUpdateMin]);\n\n  useEffect(() => {\n    if (touched.current) {\n      onUpdateMax(finalValueMax);\n    }\n  }, [finalValueMax, onUpdateMax]);\n\n  useEffect(() => {\n    touched.current = false;\n    setValueMax(defaultMaxValue ?? max);\n    setValueMin(defaultMinValue ?? min);\n  }, [defaultMinValue, defaultMaxValue, setValueMax, setValueMin, min, max]);\n\n  return (\n    <div className={`relative ${subText ? 'h-8' : 'h-4'} w-full`}>\n      <Tooltip\n        content={valueMin.toString()}\n        tooltipConfig={{\n          placement: 'top',\n        }}\n      >\n        <input\n          type=\"range\"\n          min={min}\n          max={max}\n          value={valueMin}\n          className={`pointer-events-none absolute h-2 w-full cursor-pointer appearance-none rounded-lg bg-gray-700 ${\n            valueMin >= valueMax && valueMin !== min ? 'z-30' : 'z-10'\n          }`}\n          onChange={(e) => {\n            const value = Number(e.target.value);\n\n            if (value <= valueMax) {\n              touched.current = true;\n              setValueMin(value);\n            }\n          }}\n        />\n      </Tooltip>\n      <Tooltip content={valueMax}>\n        <input\n          type=\"range\"\n          min={min}\n          max={max}\n          value={valueMax}\n          step=\"1\"\n          className={`pointer-events-none absolute left-0 right-0 top-0 z-20 h-2 w-full cursor-pointer appearance-none rounded-lg bg-transparent`}\n          onChange={(e) => {\n            const value = Number(e.target.value);\n\n            if (value >= valueMin) {\n              touched.current = true;\n              setValueMax(value);\n            }\n          }}\n        />\n      </Tooltip>\n      <div\n        className=\"pointer-events-none absolute top-0 z-30 ml-1 mr-1 h-2 bg-indigo-500\"\n        style={{\n          left: `${minThumb}%`,\n          right: `${100 - maxThumb}%`,\n        }}\n      />\n      {subText && (\n        <div className=\"relative top-4 z-30 flex w-full justify-center text-sm text-gray-400\">\n          <span>{subText}</span>\n        </div>\n      )}\n    </div>\n  );\n};\n\nexport default MultiRangeSlider;\n"
  },
  {
    "path": "src/components/Common/PageTitle/index.tsx",
    "content": "import useSettings from '@app/hooks/useSettings';\nimport Head from 'next/head';\n\ninterface PageTitleProps {\n  title: string | (string | undefined)[];\n}\n\nconst PageTitle = ({ title }: PageTitleProps) => {\n  const settings = useSettings();\n\n  const titleText = `${\n    Array.isArray(title) ? title.filter(Boolean).join(' - ') : title\n  } - ${settings.currentSettings.applicationTitle}`;\n\n  return (\n    <Head>\n      <title>{titleText}</title>\n    </Head>\n  );\n};\n\nexport default PageTitle;\n"
  },
  {
    "path": "src/components/Common/PlayButton/index.tsx",
    "content": "import ButtonWithDropdown from '@app/components/Common/ButtonWithDropdown';\n\ninterface PlayButtonProps {\n  links: PlayButtonLink[];\n}\n\nexport interface PlayButtonLink {\n  text: string;\n  url: string;\n  svg: React.ReactNode;\n}\n\nconst PlayButton = ({ links }: PlayButtonProps) => {\n  if (!links || !links.length) {\n    return null;\n  }\n\n  return (\n    <ButtonWithDropdown\n      as=\"a\"\n      buttonType=\"ghost\"\n      text={\n        <>\n          {links[0].svg}\n          <span>{links[0].text}</span>\n        </>\n      }\n      href={links[0].url}\n      target=\"_blank\"\n    >\n      {links.length > 1 &&\n        links.slice(1).map((link, i) => {\n          return (\n            <ButtonWithDropdown.Item\n              key={`play-button-dropdown-item-${i}`}\n              buttonType=\"ghost\"\n              href={link.url}\n              target=\"_blank\"\n            >\n              {link.svg}\n              <span>{link.text}</span>\n            </ButtonWithDropdown.Item>\n          );\n        })}\n    </ButtonWithDropdown>\n  );\n};\n\nexport default PlayButton;\n"
  },
  {
    "path": "src/components/Common/ProgressCircle/index.tsx",
    "content": "import { useEffect, useRef } from 'react';\n\ninterface ProgressCircleProps {\n  className?: string;\n  progress?: number;\n  useHeatLevel?: boolean;\n}\n\nconst ProgressCircle = ({\n  className,\n  progress = 0,\n  useHeatLevel,\n}: ProgressCircleProps) => {\n  const ref = useRef<SVGCircleElement>(null);\n\n  let color = '';\n  let emptyColor = 'text-gray-300';\n\n  if (useHeatLevel) {\n    color = 'text-green-500';\n\n    if (progress <= 50) {\n      color = 'text-yellow-500';\n    }\n\n    if (progress <= 10) {\n      color = 'text-red-500';\n    }\n\n    if (progress === 0) {\n      emptyColor = 'text-red-600';\n    }\n  }\n\n  useEffect(() => {\n    if (ref && ref.current) {\n      const radius = ref.current?.r.baseVal.value;\n      const circumference = (radius ?? 0) * 2 * Math.PI;\n      const offset = circumference - (progress / 100) * circumference;\n      ref.current.style.strokeDashoffset = `${offset}`;\n      ref.current.style.strokeDasharray = `${circumference} ${circumference}`;\n    }\n  });\n\n  return (\n    <svg className={`${className} ${color}`} viewBox=\"0 0 24 24\">\n      <circle\n        className={`${emptyColor} opacity-30`}\n        stroke=\"currentColor\"\n        strokeWidth=\"3\"\n        fill=\"transparent\"\n        r=\"10\"\n        cx=\"12\"\n        cy=\"12\"\n      />\n      <circle\n        style={{\n          transition: '0.35s stroke-dashoffset',\n          transform: 'rotate(-90deg)',\n          transformOrigin: '50% 50%',\n        }}\n        ref={ref}\n        stroke=\"currentColor\"\n        strokeWidth=\"3\"\n        fill=\"transparent\"\n        r=\"10\"\n        cx=\"12\"\n        cy=\"12\"\n      />\n    </svg>\n  );\n};\n\nexport default ProgressCircle;\n"
  },
  {
    "path": "src/components/Common/SensitiveInput/index.tsx",
    "content": "import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/solid';\nimport { Field } from 'formik';\nimport { useState } from 'react';\n\ninterface CustomInputProps extends React.ComponentProps<'input'> {\n  as?: 'input';\n}\n\ninterface CustomFieldProps extends React.ComponentProps<typeof Field> {\n  as?: 'field';\n}\n\ntype SensitiveInputProps = CustomInputProps | CustomFieldProps;\n\nconst SensitiveInput = ({ as = 'input', ...props }: SensitiveInputProps) => {\n  const [isHidden, setHidden] = useState(true);\n  const Component = as === 'input' ? 'input' : Field;\n  const componentProps =\n    as === 'input'\n      ? props\n      : {\n          ...props,\n          as: props.type === 'textarea' ? 'textarea' : undefined,\n        };\n  return (\n    <>\n      <Component\n        autoComplete=\"off\"\n        data-form-type=\"other\"\n        data-1pignore=\"true\"\n        data-lpignore=\"true\"\n        {...componentProps}\n        className={`rounded-l-only ${componentProps.className ?? ''}`}\n        type={\n          props.type === 'textarea'\n            ? undefined\n            : isHidden\n              ? 'password'\n              : props.type !== 'password'\n                ? (props.type ?? 'text')\n                : 'text'\n        }\n        style={\n          props.type === 'textarea' && isHidden\n            ? { WebkitTextSecurity: 'disc', ...props.style }\n            : props.style\n        }\n      />\n      <button\n        onClick={(e) => {\n          e.preventDefault();\n          setHidden(!isHidden);\n        }}\n        type=\"button\"\n        className=\"input-action\"\n      >\n        {isHidden ? <EyeSlashIcon /> : <EyeIcon />}\n      </button>\n    </>\n  );\n};\n\nexport default SensitiveInput;\n"
  },
  {
    "path": "src/components/Common/SettingsTabs/index.tsx",
    "content": "import { useUser } from '@app/hooks/useUser';\nimport type { Permission } from '@server/lib/permissions';\nimport { hasPermission } from '@server/lib/permissions';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\n\nexport interface SettingsRoute {\n  text: string;\n  content?: React.ReactNode;\n  route: string;\n  regex: RegExp;\n  requiredPermission?: Permission | Permission[];\n  permissionType?: { type: 'and' | 'or' };\n  hidden?: boolean;\n}\n\ntype SettingsLinkProps = {\n  tabType: 'default' | 'button';\n  currentPath: string;\n  route: string;\n  regex: RegExp;\n  hidden?: boolean;\n  isMobile?: boolean;\n  children: React.ReactNode;\n};\n\nconst SettingsLink = ({\n  children,\n  tabType,\n  currentPath,\n  route,\n  regex,\n  hidden = false,\n  isMobile = false,\n}: SettingsLinkProps) => {\n  if (hidden) {\n    return null;\n  }\n\n  if (isMobile) {\n    return <option value={route}>{children}</option>;\n  }\n\n  let linkClasses =\n    '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';\n  let activeLinkColor = 'text-indigo-500 border-indigo-600';\n  let inactiveLinkColor =\n    'text-gray-500 border-transparent hover:text-gray-300 hover:border-gray-400 focus:text-gray-300 focus:border-gray-400';\n\n  if (tabType === 'button') {\n    linkClasses =\n      'px-3 py-2 text-sm font-medium transition duration-300 rounded-md whitespace-nowrap mx-2 my-1';\n    activeLinkColor = 'bg-indigo-700';\n    inactiveLinkColor = 'bg-gray-800 hover:bg-gray-700 focus:bg-gray-700';\n  }\n\n  return (\n    <Link\n      href={route}\n      className={`${linkClasses} ${\n        currentPath.match(regex) ? activeLinkColor : inactiveLinkColor\n      }`}\n      aria-current=\"page\"\n    >\n      {children}\n    </Link>\n  );\n};\n\nconst SettingsTabs = ({\n  tabType = 'default',\n  settingsRoutes,\n}: {\n  tabType?: 'default' | 'button';\n  settingsRoutes: SettingsRoute[];\n}) => {\n  const router = useRouter();\n  const { user: currentUser } = useUser();\n\n  return (\n    <>\n      <div className=\"sm:hidden\">\n        <label htmlFor=\"tabs\" className=\"sr-only\">\n          Select a Tab\n        </label>\n        <select\n          id=\"tabs\"\n          onChange={(e) => {\n            router.push(e.target.value);\n          }}\n          onBlur={(e) => {\n            router.push(e.target.value);\n          }}\n          defaultValue={\n            settingsRoutes.find((route) => !!router.pathname.match(route.regex))\n              ?.route\n          }\n          aria-label=\"Selected Tab\"\n        >\n          {settingsRoutes\n            .filter(\n              (route) =>\n                !route.hidden &&\n                (route.requiredPermission\n                  ? hasPermission(\n                      route.requiredPermission,\n                      currentUser?.permissions ?? 0,\n                      route.permissionType\n                    )\n                  : true)\n            )\n            .map((route, index) => (\n              <SettingsLink\n                tabType={tabType}\n                currentPath={router.pathname}\n                route={route.route}\n                regex={route.regex}\n                hidden={route.hidden ?? false}\n                isMobile\n                key={`mobile-settings-link-${index}`}\n              >\n                {route.text}\n              </SettingsLink>\n            ))}\n        </select>\n      </div>\n      {tabType === 'button' ? (\n        <div className=\"hidden sm:block\">\n          <nav className=\"-mx-2 -my-1 flex flex-wrap\" aria-label=\"Tabs\">\n            {settingsRoutes.map((route, index) => (\n              <SettingsLink\n                tabType={tabType}\n                currentPath={router.pathname}\n                route={route.route}\n                regex={route.regex}\n                hidden={route.hidden ?? false}\n                key={`button-settings-link-${index}`}\n              >\n                {route.content ?? route.text}\n              </SettingsLink>\n            ))}\n          </nav>\n        </div>\n      ) : (\n        <div className=\"hide-scrollbar hidden overflow-x-scroll border-b border-gray-600 sm:block\">\n          <nav className=\"flex\" data-testid=\"settings-nav-desktop\">\n            {settingsRoutes\n              .filter(\n                (route) =>\n                  !route.hidden &&\n                  (route.requiredPermission\n                    ? hasPermission(\n                        route.requiredPermission,\n                        currentUser?.permissions ?? 0,\n                        route.permissionType\n                      )\n                    : true)\n              )\n              .map((route, index) => (\n                <SettingsLink\n                  tabType={tabType}\n                  currentPath={router.pathname}\n                  route={route.route}\n                  regex={route.regex}\n                  key={`standard-settings-link-${index}`}\n                >\n                  {route.text}\n                </SettingsLink>\n              ))}\n          </nav>\n        </div>\n      )}\n    </>\n  );\n};\n\nexport default SettingsTabs;\n"
  },
  {
    "path": "src/components/Common/SlideCheckbox/index.tsx",
    "content": "type SlideCheckboxProps = {\n  onClick: () => void;\n  checked?: boolean;\n};\n\nconst SlideCheckbox = ({ onClick, checked = false }: SlideCheckboxProps) => {\n  return (\n    <span\n      role=\"checkbox\"\n      tabIndex={0}\n      aria-checked={false}\n      onClick={() => {\n        onClick();\n      }}\n      onKeyDown={(e) => {\n        if (e.key === 'Enter' || e.key === 'Space') {\n          onClick();\n        }\n      }}\n      className={`relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center pt-2 focus:outline-none`}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={`${\n          checked ? 'bg-indigo-500' : 'bg-gray-700'\n        } absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}\n      />\n      <span\n        aria-hidden=\"true\"\n        className={`${\n          checked ? 'translate-x-5' : 'translate-x-0'\n        } absolute left-0 inline-block h-5 w-5 rounded-full border border-gray-200 bg-white shadow transition-transform duration-200 ease-in-out group-focus:border-blue-300 group-focus:ring`}\n      />\n    </span>\n  );\n};\n\nexport default SlideCheckbox;\n"
  },
  {
    "path": "src/components/Common/SlideOver/index.tsx",
    "content": "/* eslint-disable jsx-a11y/click-events-have-key-events */\nimport { useLockBodyScroll } from '@app/hooks/useLockBodyScroll';\nimport { Transition } from '@headlessui/react';\nimport { XMarkIcon } from '@heroicons/react/24/outline';\nimport { Fragment, useEffect, useRef, useState } from 'react';\nimport ReactDOM from 'react-dom';\n\ninterface SlideOverProps {\n  show?: boolean;\n  title: React.ReactNode;\n  subText?: string;\n  onClose: () => void;\n  children: React.ReactNode;\n}\n\nconst SlideOver = ({\n  show = false,\n  title,\n  subText,\n  onClose,\n  children,\n}: SlideOverProps) => {\n  const [isMounted, setIsMounted] = useState(false);\n  const slideoverRef = useRef(null);\n  useLockBodyScroll(show);\n\n  useEffect(() => {\n    setIsMounted(true);\n  }, []);\n\n  if (!isMounted) {\n    return null;\n  }\n\n  return ReactDOM.createPortal(\n    <Transition\n      as={Fragment}\n      show={show}\n      appear\n      enter=\"transition-opacity ease-in-out duration-300\"\n      enterFrom=\"opacity-0\"\n      enterTo=\"opacity-100\"\n      leave=\"transition-opacity ease-in-out duration-300\"\n      leaveFrom=\"opacity-100\"\n      leaveTo=\"opacity-0\"\n    >\n      {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}\n      <div\n        className={`fixed inset-0 z-50 overflow-hidden bg-gray-800/70`}\n        onClick={() => onClose()}\n        onKeyDown={(e) => {\n          if (e.key === 'Escape') {\n            onClose();\n          }\n        }}\n      >\n        <div className=\"absolute inset-0 overflow-hidden\">\n          <section className=\"absolute inset-y-0 right-0 flex max-w-full\">\n            <Transition.Child\n              appear\n              enter=\"transition-transform ease-in-out duration-500 sm:duration-700\"\n              enterFrom=\"translate-x-full\"\n              enterTo=\"translate-x-0\"\n              leave=\"transition-transform ease-in-out duration-500 sm:duration-700\"\n              leaveFrom=\"translate-x-0\"\n              leaveTo=\"translate-x-full\"\n            >\n              {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}\n              <div\n                className=\"slideover relative h-full w-screen max-w-md p-2 sm:p-3\"\n                ref={slideoverRef}\n                onClick={(e) => e.stopPropagation()}\n              >\n                <div className=\"flex h-full flex-col rounded-lg bg-gray-800/80 shadow-xl ring-1 ring-gray-700 backdrop-blur\">\n                  <header className=\"space-y-1 border-b border-gray-700 px-4 py-4\">\n                    <div className=\"flex items-center justify-between space-x-3\">\n                      <h2 className=\"text-overseerr text-2xl font-bold leading-7\">\n                        {title}\n                      </h2>\n                      <div className=\"flex h-7 items-center\">\n                        <button\n                          aria-label=\"Close panel\"\n                          className=\"text-gray-200 transition duration-150 ease-in-out hover:text-white\"\n                          onClick={() => onClose()}\n                        >\n                          <XMarkIcon className=\"h-6 w-6\" />\n                        </button>\n                      </div>\n                    </div>\n                    {subText && (\n                      <div>\n                        <p className=\"font-semibold leading-5 text-gray-300\">\n                          {subText}\n                        </p>\n                      </div>\n                    )}\n                  </header>\n                  <div className=\"hide-scrollbar flex flex-1 flex-col overflow-y-auto\">\n                    <div className=\"flex-1 px-4 py-6 text-white\">\n                      {children}\n                    </div>\n                  </div>\n                </div>\n              </div>\n            </Transition.Child>\n          </section>\n        </div>\n      </div>\n    </Transition>,\n    document.body\n  );\n};\n\nexport default SlideOver;\n"
  },
  {
    "path": "src/components/Common/StatusBadgeMini/index.tsx",
    "content": "import Spinner from '@app/assets/spinner.svg';\nimport { CheckCircleIcon } from '@heroicons/react/20/solid';\nimport {\n  BellIcon,\n  ClockIcon,\n  EyeSlashIcon,\n  MinusSmallIcon,\n  TrashIcon,\n} from '@heroicons/react/24/solid';\nimport { MediaStatus } from '@server/constants/media';\n\ninterface StatusBadgeMiniProps {\n  status: MediaStatus;\n  is4k?: boolean;\n  inProgress?: boolean;\n  // Should the badge shrink on mobile to a smaller size? (TitleCard)\n  shrink?: boolean;\n}\n\nconst StatusBadgeMini = ({\n  status,\n  is4k = false,\n  inProgress = false,\n  shrink = false,\n}: StatusBadgeMiniProps) => {\n  const badgeStyle = [\n    `rounded-full shadow-md ${\n      shrink ? 'w-4 sm:w-5 border p-0' : 'w-5 ring-1 p-0.5'\n    }`,\n  ];\n\n  let indicatorIcon: React.ReactNode;\n\n  switch (status) {\n    case MediaStatus.PROCESSING:\n      badgeStyle.push(\n        'bg-indigo-500/80 border-indigo-400 ring-indigo-400 text-indigo-100'\n      );\n      indicatorIcon = <ClockIcon />;\n      break;\n    case MediaStatus.AVAILABLE:\n      badgeStyle.push(\n        'bg-green-500/80 border-green-400 ring-green-400 text-green-100'\n      );\n      indicatorIcon = <CheckCircleIcon />;\n      break;\n    case MediaStatus.PENDING:\n      badgeStyle.push(\n        'bg-yellow-500/80 border-yellow-400 ring-yellow-400 text-yellow-100'\n      );\n      indicatorIcon = <BellIcon />;\n      break;\n    case MediaStatus.BLOCKLISTED:\n      badgeStyle.push('bg-red-500/80 border-white ring-white text-white');\n      indicatorIcon = <EyeSlashIcon />;\n      break;\n    case MediaStatus.PARTIALLY_AVAILABLE:\n      badgeStyle.push(\n        'bg-green-500/80 border-green-400 ring-green-400 text-green-100'\n      );\n      indicatorIcon = <MinusSmallIcon />;\n      break;\n    case MediaStatus.DELETED:\n      badgeStyle.push('bg-red-500/80 border-red-400 ring-red-400 text-red-100');\n      indicatorIcon = <TrashIcon />;\n      break;\n  }\n\n  if (inProgress) {\n    indicatorIcon = <Spinner />;\n  }\n\n  return (\n    <div\n      className={`relative inline-flex whitespace-nowrap rounded-full border-gray-700 text-xs font-semibold leading-5 ring-gray-700 ${\n        shrink ? '' : 'ring-1'\n      }`}\n    >\n      <div className={badgeStyle.join(' ')}>{indicatorIcon}</div>\n      {is4k && <span className=\"pl-1 pr-2 text-gray-200\">4K</span>}\n    </div>\n  );\n};\n\nexport default StatusBadgeMini;\n"
  },
  {
    "path": "src/components/Common/Table/index.tsx",
    "content": "import { withProperties } from '@app/utils/typeHelpers';\n\ntype TBodyProps = {\n  children: React.ReactNode;\n};\n\nconst TBody = ({ children }: TBodyProps) => {\n  return (\n    <tbody className=\"divide-y divide-gray-700 bg-gray-800\">{children}</tbody>\n  );\n};\n\nconst TH = ({\n  children,\n  className,\n  ...props\n}: React.ComponentPropsWithoutRef<'th'>) => {\n  const style = [\n    'px-4 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider truncate',\n  ];\n\n  if (className) {\n    style.push(className);\n  }\n\n  return (\n    <th className={style.join(' ')} {...props}>\n      {children}\n    </th>\n  );\n};\n\ntype TDProps = {\n  alignText?: 'left' | 'center' | 'right';\n  noPadding?: boolean;\n};\n\nconst TD = ({\n  children,\n  alignText = 'left',\n  noPadding,\n  className,\n  ...props\n}: TDProps & React.ComponentPropsWithoutRef<'td'>) => {\n  const style = ['text-sm leading-5 text-white'];\n\n  switch (alignText) {\n    case 'left':\n      style.push('text-left');\n      break;\n    case 'center':\n      style.push('text-center');\n      break;\n    case 'right':\n      style.push('text-right');\n      break;\n  }\n\n  if (!noPadding) {\n    style.push('px-4 py-4');\n  }\n\n  if (className) {\n    style.push(className);\n  }\n\n  return (\n    <td className={style.join(' ')} {...props}>\n      {children}\n    </td>\n  );\n};\n\ntype TableProps = {\n  children: React.ReactNode;\n};\n\nconst Table = ({ children }: TableProps) => {\n  return (\n    <div className=\"flex flex-col\">\n      <div className=\"-mx-4 my-2 overflow-x-auto md:mx-0 lg:mx-0\">\n        <div className=\"inline-block min-w-full py-2 align-middle\">\n          <div className=\"overflow-hidden rounded-lg shadow md:mx-0 lg:mx-0\">\n            <table className=\"min-w-full\">{children}</table>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default withProperties(Table, { TH, TBody, TD });\n"
  },
  {
    "path": "src/components/Common/Tag/index.tsx",
    "content": "import { TagIcon } from '@heroicons/react/24/outline';\nimport React from 'react';\n\ntype TagProps = {\n  children: React.ReactNode;\n  iconSvg?: JSX.Element;\n};\n\nconst Tag = ({ children, iconSvg }: TagProps) => {\n  return (\n    <div className=\"inline-flex cursor-pointer items-center rounded-full bg-gray-800 px-2 py-1 text-sm text-gray-200 ring-1 ring-gray-600 transition hover:bg-gray-700\">\n      {iconSvg ? (\n        React.cloneElement(iconSvg, {\n          className: 'mr-1 h-4 w-4',\n        })\n      ) : (\n        <TagIcon className=\"mr-1 h-4 w-4\" />\n      )}\n      <span>{children}</span>\n    </div>\n  );\n};\n\nexport default Tag;\n"
  },
  {
    "path": "src/components/Common/Tooltip/index.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport type { Config } from 'react-popper-tooltip';\nimport { usePopperTooltip } from 'react-popper-tooltip';\n\ntype TooltipProps = {\n  content: React.ReactNode;\n  children: React.ReactElement;\n  tooltipConfig?: Partial<Config>;\n  className?: string;\n};\n\nconst Tooltip = ({\n  children,\n  content,\n  tooltipConfig,\n  className,\n}: TooltipProps) => {\n  const { getTooltipProps, setTooltipRef, setTriggerRef, visible } =\n    usePopperTooltip({\n      followCursor: true,\n      offset: [-28, 6],\n      placement: 'auto-end',\n      ...tooltipConfig,\n    });\n\n  const tooltipStyle = [\n    'z-50 text-sm absolute font-normal bg-gray-800 px-2 py-1 rounded border border-gray-600 shadow text-gray-100',\n  ];\n\n  if (className) {\n    tooltipStyle.push(className);\n  }\n\n  return (\n    <>\n      {React.cloneElement(children, { ref: setTriggerRef })}\n      {visible &&\n        content &&\n        ReactDOM.createPortal(\n          <div\n            ref={setTooltipRef}\n            {...getTooltipProps({\n              className: tooltipStyle.join(' '),\n            })}\n          >\n            {content}\n          </div>,\n          document.body\n        )}\n    </>\n  );\n};\n\nexport default Tooltip;\n"
  },
  {
    "path": "src/components/CompanyCard/index.tsx",
    "content": "import CachedImage from '@app/components/Common/CachedImage';\nimport Link from 'next/link';\nimport { useState } from 'react';\n\ninterface CompanyCardProps {\n  name: string;\n  image: string;\n  url: string;\n}\n\nconst CompanyCard = ({ image, url, name }: CompanyCardProps) => {\n  const [isHovered, setHovered] = useState(false);\n\n  return (\n    <Link\n      href={url}\n      className={`relative flex h-32 w-56 transform-gpu cursor-pointer items-center justify-center p-8 shadow ring-1 transition duration-300 ease-in-out sm:h-36 sm:w-72 ${\n        isHovered\n          ? 'scale-105 bg-gray-700 ring-gray-500'\n          : 'scale-100 bg-gray-800 ring-gray-700'\n      } rounded-xl`}\n      onMouseEnter={() => {\n        setHovered(true);\n      }}\n      onMouseLeave={() => setHovered(false)}\n      onKeyDown={(e) => {\n        if (e.key === 'Enter') {\n          setHovered(true);\n        }\n      }}\n      role=\"link\"\n      tabIndex={0}\n    >\n      <div className=\"relative h-full w-full\">\n        <CachedImage\n          type=\"tmdb\"\n          src={image}\n          alt={name}\n          className=\"relative z-40 h-full w-full\"\n          style={{ width: '100%', height: '100%', objectFit: 'contain' }}\n          fill\n        />\n      </div>\n      <div\n        className={`absolute bottom-0 left-0 right-0 z-0 h-12 rounded-b-xl bg-gradient-to-t ${\n          isHovered ? 'from-gray-800' : 'from-gray-900'\n        }`}\n      />\n    </Link>\n  );\n};\n\nexport default CompanyCard;\n"
  },
  {
    "path": "src/components/CompanyTag/index.tsx",
    "content": "import Spinner from '@app/assets/spinner.svg';\nimport Tag from '@app/components/Common/Tag';\nimport { BuildingOffice2Icon } from '@heroicons/react/24/outline';\nimport type { ProductionCompany, TvNetwork } from '@server/models/common';\nimport useSWR from 'swr';\n\ntype CompanyTagProps = {\n  type: 'studio' | 'network';\n  companyId: number;\n};\n\nconst CompanyTag = ({ companyId, type }: CompanyTagProps) => {\n  const { data, error } = useSWR<TvNetwork | ProductionCompany>(\n    `/api/v1/${type}/${companyId}`\n  );\n\n  if (!data && !error) {\n    return (\n      <Tag>\n        <Spinner className=\"h-4 w-4\" />\n      </Tag>\n    );\n  }\n\n  return <Tag iconSvg={<BuildingOffice2Icon />}>{data?.name}</Tag>;\n};\n\nexport default CompanyTag;\n"
  },
  {
    "path": "src/components/Discover/CreateSlider/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport { sliderTitles } from '@app/components/Discover/constants';\nimport MediaSlider from '@app/components/MediaSlider';\nimport { WatchProviderSelector } from '@app/components/Selector';\nimport { encodeURIExtraParams } from '@app/hooks/useDiscover';\nimport defineMessages from '@app/utils/defineMessages';\nimport type {\n  TmdbCompanySearchResponse,\n  TmdbGenre,\n  TmdbKeywordSearchResponse,\n} from '@server/api/themoviedb/interfaces';\nimport { DiscoverSliderType } from '@server/constants/discover';\nimport type DiscoverSlider from '@server/entity/DiscoverSlider';\nimport type { GenreSliderItem } from '@server/interfaces/api/discoverInterfaces';\nimport type { Keyword, ProductionCompany } from '@server/models/common';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport AsyncSelect from 'react-select/async';\nimport { useToasts } from 'react-toast-notifications';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Discover.CreateSlider', {\n  addSlider: 'Add Slider',\n  editSlider: 'Edit Slider',\n  slidernameplaceholder: 'Slider Name',\n  providetmdbkeywordid: 'Provide a TMDB Keyword ID',\n  providetmdbgenreid: 'Provide a TMDB Genre ID',\n  providetmdbsearch: 'Provide a search query',\n  providetmdbstudio: 'Provide TMDB Studio ID',\n  providetmdbnetwork: 'Provide TMDB Network ID',\n  addsuccess: 'Created new slider and saved discover customization settings.',\n  addfail: 'Failed to create new slider.',\n  editsuccess: 'Edited slider and saved discover customization settings.',\n  editfail: 'Failed to edit slider.',\n  needresults: 'You need to have at least 1 result.',\n  validationDatarequired: 'You must provide a data value.',\n  validationTitlerequired: 'You must provide a title.',\n  addcustomslider: 'Create Custom Slider',\n  searchKeywords: 'Search keywords…',\n  searchGenres: 'Search genres…',\n  searchStudios: 'Search studios…',\n  starttyping: 'Starting typing to search.',\n  nooptions: 'No results.',\n});\n\ntype CreateSliderProps = {\n  onCreate: () => void;\n  slider?: Partial<DiscoverSlider>;\n};\n\ntype CreateOption = {\n  type: DiscoverSliderType;\n  title: string;\n  dataUrl: string;\n  params?: string;\n  titlePlaceholderText: string;\n  dataPlaceholderText?: string;\n};\n\nconst CreateSlider = ({ onCreate, slider }: CreateSliderProps) => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const [resultCount, setResultCount] = useState(0);\n  const [defaultDataValue, setDefaultDataValue] = useState<\n    { label: string; value: number }[] | null\n  >(null);\n\n  useEffect(() => {\n    if (slider) {\n      const loadDefaultKeywords = async (): Promise<void> => {\n        if (!slider.data) {\n          return;\n        }\n\n        const keywords = await Promise.all(\n          slider.data.split(',').map(async (keywordId) => {\n            const keyword = await axios.get<Keyword | null>(\n              `/api/v1/keyword/${keywordId}`\n            );\n            return keyword.data;\n          })\n        );\n\n        const validKeywords: Keyword[] = keywords.filter(\n          (keyword): keyword is Keyword => keyword !== null\n        );\n\n        setDefaultDataValue(\n          validKeywords.map((keyword) => ({\n            label: keyword.name,\n            value: keyword.id,\n          }))\n        );\n      };\n\n      const loadDefaultGenre = async (): Promise<void> => {\n        if (!slider.data) {\n          return;\n        }\n\n        const response = await axios.get<TmdbGenre[]>(\n          `/api/v1/genres/${\n            slider.type === DiscoverSliderType.TMDB_MOVIE_GENRE ? 'movie' : 'tv'\n          }`\n        );\n\n        const genre = response.data.find(\n          (genre) => genre.id === Number(slider.data)\n        );\n\n        setDefaultDataValue([\n          {\n            label: genre?.name ?? '',\n            value: genre?.id ?? 0,\n          },\n        ]);\n      };\n\n      const loadDefaultCompany = async (): Promise<void> => {\n        if (!slider.data) {\n          return;\n        }\n\n        const response = await axios.get<ProductionCompany>(\n          `/api/v1/studio/${slider.data}`\n        );\n\n        const studio = response.data;\n\n        setDefaultDataValue([\n          {\n            label: studio.name ?? '',\n            value: studio.id ?? 0,\n          },\n        ]);\n      };\n\n      switch (slider.type) {\n        case DiscoverSliderType.TMDB_MOVIE_KEYWORD:\n        case DiscoverSliderType.TMDB_TV_KEYWORD:\n          loadDefaultKeywords();\n          break;\n        case DiscoverSliderType.TMDB_MOVIE_GENRE:\n        case DiscoverSliderType.TMDB_TV_GENRE:\n          loadDefaultGenre();\n          break;\n        case DiscoverSliderType.TMDB_STUDIO:\n          loadDefaultCompany();\n          break;\n      }\n    }\n  }, [slider]);\n\n  const CreateSliderSchema = Yup.object().shape({\n    title: Yup.string().required(\n      intl.formatMessage(messages.validationTitlerequired)\n    ),\n    data: Yup.string().required(\n      intl.formatMessage(messages.validationDatarequired)\n    ),\n  });\n\n  const updateResultCount = useCallback(\n    (count: number) => {\n      setResultCount(count);\n    },\n    [setResultCount]\n  );\n\n  const loadKeywordOptions = async (inputValue: string) => {\n    const results = await axios.get<TmdbKeywordSearchResponse>(\n      '/api/v1/search/keyword',\n      {\n        params: {\n          query: encodeURIExtraParams(inputValue),\n        },\n      }\n    );\n\n    return results.data.results.map((result) => ({\n      label: result.name,\n      value: result.id,\n    }));\n  };\n\n  const loadCompanyOptions = async (inputValue: string) => {\n    if (inputValue === '') {\n      return [];\n    }\n\n    const results = await axios.get<TmdbCompanySearchResponse>(\n      '/api/v1/search/company',\n      {\n        params: {\n          query: encodeURIExtraParams(inputValue),\n        },\n      }\n    );\n\n    return results.data.results.map((result) => ({\n      label: result.name,\n      value: result.id,\n    }));\n  };\n\n  const loadMovieGenreOptions = async () => {\n    const results = await axios.get<GenreSliderItem[]>(\n      '/api/v1/discover/genreslider/movie'\n    );\n\n    return results.data.map((result) => ({\n      label: result.name,\n      value: result.id,\n    }));\n  };\n\n  const loadTvGenreOptions = async () => {\n    const results = await axios.get<GenreSliderItem[]>(\n      '/api/v1/discover/genreslider/tv'\n    );\n\n    return results.data.map((result) => ({\n      label: result.name,\n      value: result.id,\n    }));\n  };\n\n  const options: CreateOption[] = [\n    {\n      type: DiscoverSliderType.TMDB_MOVIE_KEYWORD,\n      title: intl.formatMessage(sliderTitles.tmdbmoviekeyword),\n      dataUrl: '/api/v1/discover/movies',\n      params: 'keywords=$value',\n      titlePlaceholderText: intl.formatMessage(messages.slidernameplaceholder),\n      dataPlaceholderText: intl.formatMessage(messages.providetmdbkeywordid),\n    },\n    {\n      type: DiscoverSliderType.TMDB_TV_KEYWORD,\n      title: intl.formatMessage(sliderTitles.tmdbtvkeyword),\n      dataUrl: '/api/v1/discover/tv',\n      params: 'keywords=$value',\n      titlePlaceholderText: intl.formatMessage(messages.slidernameplaceholder),\n      dataPlaceholderText: intl.formatMessage(messages.providetmdbkeywordid),\n    },\n    {\n      type: DiscoverSliderType.TMDB_MOVIE_GENRE,\n      title: intl.formatMessage(sliderTitles.tmdbmoviegenre),\n      dataUrl: '/api/v1/discover/movies/genre/$value',\n      titlePlaceholderText: intl.formatMessage(messages.slidernameplaceholder),\n      dataPlaceholderText: intl.formatMessage(messages.providetmdbgenreid),\n    },\n    {\n      type: DiscoverSliderType.TMDB_TV_GENRE,\n      title: intl.formatMessage(sliderTitles.tmdbtvgenre),\n      dataUrl: '/api/v1/discover/tv/genre/$value',\n      titlePlaceholderText: intl.formatMessage(messages.slidernameplaceholder),\n      dataPlaceholderText: intl.formatMessage(messages.providetmdbgenreid),\n    },\n    {\n      type: DiscoverSliderType.TMDB_STUDIO,\n      title: intl.formatMessage(sliderTitles.tmdbstudio),\n      dataUrl: '/api/v1/discover/movies/studio/$value',\n      titlePlaceholderText: intl.formatMessage(messages.slidernameplaceholder),\n      dataPlaceholderText: intl.formatMessage(messages.providetmdbstudio),\n    },\n    {\n      type: DiscoverSliderType.TMDB_NETWORK,\n      title: intl.formatMessage(sliderTitles.tmdbnetwork),\n      dataUrl: '/api/v1/discover/tv/network/$value',\n      titlePlaceholderText: intl.formatMessage(messages.slidernameplaceholder),\n      dataPlaceholderText: intl.formatMessage(messages.providetmdbnetwork),\n    },\n    {\n      type: DiscoverSliderType.TMDB_SEARCH,\n      title: intl.formatMessage(sliderTitles.tmdbsearch),\n      dataUrl: '/api/v1/search',\n      params: 'query=$value',\n      titlePlaceholderText: intl.formatMessage(messages.slidernameplaceholder),\n      dataPlaceholderText: intl.formatMessage(messages.providetmdbsearch),\n    },\n    {\n      type: DiscoverSliderType.TMDB_MOVIE_STREAMING_SERVICES,\n      title: intl.formatMessage(sliderTitles.tmdbmoviestreamingservices),\n      dataUrl: '/api/v1/discover/movies',\n      params: 'watchRegion=$regionValue&watchProviders=$providersValue',\n      titlePlaceholderText: intl.formatMessage(messages.slidernameplaceholder),\n    },\n    {\n      type: DiscoverSliderType.TMDB_TV_STREAMING_SERVICES,\n      title: intl.formatMessage(sliderTitles.tmdbtvstreamingservices),\n      dataUrl: '/api/v1/discover/tv',\n      params: 'watchRegion=$regionValue&watchProviders=$providersValue',\n      titlePlaceholderText: intl.formatMessage(messages.slidernameplaceholder),\n    },\n  ];\n\n  return (\n    <Formik\n      initialValues={\n        slider\n          ? {\n              sliderType: slider.type,\n              title: slider.title,\n              data: slider.data,\n            }\n          : {\n              sliderType: DiscoverSliderType.TMDB_MOVIE_KEYWORD,\n              title: '',\n              data: '',\n            }\n      }\n      validationSchema={CreateSliderSchema}\n      enableReinitialize\n      onSubmit={async (values, { resetForm }) => {\n        try {\n          if (slider) {\n            await axios.put(`/api/v1/settings/discover/${slider.id}`, {\n              type: Number(values.sliderType),\n              title: values.title,\n              data: values.data,\n            });\n          } else {\n            await axios.post('/api/v1/settings/discover/add', {\n              type: Number(values.sliderType),\n              title: values.title,\n              data: values.data,\n            });\n          }\n\n          addToast(\n            intl.formatMessage(\n              slider ? messages.editsuccess : messages.addsuccess\n            ),\n            {\n              appearance: 'success',\n              autoDismiss: true,\n            }\n          );\n          onCreate();\n          resetForm();\n        } catch {\n          addToast(\n            intl.formatMessage(slider ? messages.editfail : messages.addfail),\n            {\n              appearance: 'error',\n              autoDismiss: true,\n            }\n          );\n        }\n      }}\n    >\n      {({ values, isValid, isSubmitting, errors, touched, setFieldValue }) => {\n        const activeOption = options.find(\n          (option) => option.type === Number(values.sliderType)\n        );\n\n        let dataInput: React.ReactNode;\n\n        switch (activeOption?.type) {\n          case DiscoverSliderType.TMDB_MOVIE_KEYWORD:\n          case DiscoverSliderType.TMDB_TV_KEYWORD:\n            dataInput = (\n              <AsyncSelect\n                key={`keyword-select-${defaultDataValue}`}\n                inputId=\"data\"\n                isMulti\n                className=\"react-select-container\"\n                classNamePrefix=\"react-select\"\n                noOptionsMessage={({ inputValue }) =>\n                  inputValue === ''\n                    ? intl.formatMessage(messages.starttyping)\n                    : intl.formatMessage(messages.nooptions)\n                }\n                defaultValue={defaultDataValue}\n                loadOptions={loadKeywordOptions}\n                placeholder={intl.formatMessage(messages.searchKeywords)}\n                onChange={(value) => {\n                  const keywords = value.map((item) => item.value).join(',');\n\n                  setFieldValue('data', keywords);\n                }}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_MOVIE_GENRE:\n            dataInput = (\n              <AsyncSelect\n                key={`movie-genre-select-${defaultDataValue}`}\n                className=\"react-select-container\"\n                classNamePrefix=\"react-select\"\n                defaultValue={defaultDataValue?.[0]}\n                defaultOptions\n                cacheOptions\n                loadOptions={loadMovieGenreOptions}\n                placeholder={intl.formatMessage(messages.searchGenres)}\n                onChange={(value) => {\n                  setFieldValue('data', value?.value.toString());\n                }}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_TV_GENRE:\n            dataInput = (\n              <AsyncSelect\n                key={`tv-genre-select-${defaultDataValue}}`}\n                className=\"react-select-container\"\n                classNamePrefix=\"react-select\"\n                defaultValue={defaultDataValue?.[0]}\n                defaultOptions\n                cacheOptions\n                loadOptions={loadTvGenreOptions}\n                placeholder={intl.formatMessage(messages.searchGenres)}\n                onChange={(value) => {\n                  setFieldValue('data', value?.value.toString());\n                }}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_STUDIO:\n            dataInput = (\n              <AsyncSelect\n                key={`studio-select-${defaultDataValue}`}\n                className=\"react-select-container\"\n                classNamePrefix=\"react-select\"\n                defaultValue={defaultDataValue?.[0]}\n                defaultOptions\n                cacheOptions\n                loadOptions={loadCompanyOptions}\n                placeholder={intl.formatMessage(messages.searchStudios)}\n                onChange={(value) => {\n                  setFieldValue('data', value?.value.toString());\n                }}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_MOVIE_STREAMING_SERVICES:\n            dataInput = (\n              <WatchProviderSelector\n                type={'movie'}\n                region={slider?.data?.split(',')[0]}\n                activeProviders={\n                  slider?.data\n                    ?.split(',')[1]\n                    .split('|')\n                    .map((v) => Number(v)) ?? []\n                }\n                onChange={(region, providers) => {\n                  setFieldValue('data', `${region},${providers.join('|')}`);\n                }}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_TV_STREAMING_SERVICES:\n            dataInput = (\n              <WatchProviderSelector\n                type={'tv'}\n                region={slider?.data?.split(',')[0]}\n                activeProviders={\n                  slider?.data\n                    ?.split(',')[1]\n                    .split('|')\n                    .map((v) => Number(v)) ?? []\n                }\n                onChange={(region, providers) => {\n                  setFieldValue('data', `${region},${providers.join('|')}`);\n                }}\n              />\n            );\n            break;\n          default:\n            dataInput = (\n              <Field\n                type=\"text\"\n                name=\"data\"\n                id=\"data\"\n                placeholder={activeOption?.dataPlaceholderText}\n              />\n            );\n        }\n\n        return (\n          <Form data-testid=\"create-discover-option-form\">\n            <div className=\"flex flex-col space-y-2 text-gray-100\">\n              <Field as=\"select\" id=\"sliderType\" name=\"sliderType\">\n                {options.map((option) => (\n                  <option value={option.type} key={`type-${option.type}`}>\n                    {option.title}\n                  </option>\n                ))}\n              </Field>\n              <Field\n                type=\"text\"\n                name=\"title\"\n                id=\"title\"\n                placeholder={activeOption?.titlePlaceholderText}\n              />\n              {errors.title &&\n                touched.title &&\n                typeof errors.title === 'string' && (\n                  <div className=\"error\">{errors.title}</div>\n                )}\n              {dataInput}\n              {errors.data &&\n                touched.data &&\n                typeof errors.data === 'string' && (\n                  <div className=\"error\">{errors.data}</div>\n                )}\n              <div className=\"flex-1\" />\n              {resultCount === 0 ? (\n                <Tooltip content={intl.formatMessage(messages.needresults)}>\n                  <div>\n                    <Button buttonType=\"primary\" buttonSize=\"sm\" disabled>\n                      {intl.formatMessage(messages.addSlider)}\n                    </Button>\n                  </div>\n                </Tooltip>\n              ) : (\n                <div>\n                  <Button\n                    buttonType=\"primary\"\n                    buttonSize=\"sm\"\n                    disabled={isSubmitting || !isValid}\n                  >\n                    {intl.formatMessage(\n                      slider ? messages.editSlider : messages.addSlider\n                    )}\n                  </Button>\n                </div>\n              )}\n            </div>\n\n            {activeOption && values.title && values.data && (\n              <div className=\"relative py-4\">\n                <MediaSlider\n                  sliderKey={`preview-${values.title}`}\n                  title={values.title}\n                  url={activeOption?.dataUrl.replace(\n                    '$value',\n                    encodeURIExtraParams(values.data)\n                  )}\n                  extraParams={\n                    activeOption.type ===\n                      DiscoverSliderType.TMDB_MOVIE_STREAMING_SERVICES ||\n                    activeOption.type ===\n                      DiscoverSliderType.TMDB_TV_STREAMING_SERVICES\n                      ? activeOption.params\n                          ?.replace(\n                            '$regionValue',\n                            encodeURIExtraParams(values?.data.split(',')[0])\n                          )\n                          .replace(\n                            '$providersValue',\n                            encodeURIExtraParams(values?.data.split(',')[1])\n                          )\n                      : activeOption.params?.replace(\n                          '$value',\n                          encodeURIExtraParams(values.data)\n                        )\n                  }\n                  onNewTitles={updateResultCount}\n                />\n              </div>\n            )}\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default CreateSlider;\n"
  },
  {
    "path": "src/components/Discover/DiscoverMovieGenre/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { MovieResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverMovieGenre', {\n  genreMovies: '{genre} Movies',\n});\n\nconst DiscoverMovieGenre = () => {\n  const router = useRouter();\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n    firstResultData,\n  } = useDiscover<MovieResult, { genre: { id: number; name: string } }>(\n    `/api/v1/discover/movies/genre/${router.query.genreId}`\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = isLoadingInitialData\n    ? intl.formatMessage(globalMessages.loading)\n    : intl.formatMessage(messages.genreMovies, {\n        genre: firstResultData?.genre.name,\n      });\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{title}</Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverMovieGenre;\n"
  },
  {
    "path": "src/components/Discover/DiscoverMovieKeyword/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover, { encodeURIExtraParams } from '@app/hooks/useDiscover';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TmdbKeyword } from '@server/api/themoviedb/interfaces';\nimport type { MovieResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverMovieKeyword', {\n  keywordMovies: '{keywordTitle} Movies',\n});\n\nconst DiscoverMovieKeyword = () => {\n  const router = useRouter();\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n    firstResultData,\n  } = useDiscover<MovieResult, { keywords: TmdbKeyword[] }>(\n    `/api/v1/discover/movies`,\n    {\n      keywords: encodeURIExtraParams(router.query.keywords as string),\n    }\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = isLoadingInitialData\n    ? intl.formatMessage(globalMessages.loading)\n    : intl.formatMessage(messages.keywordMovies, {\n        keywordTitle: firstResultData?.keywords\n          .map((k) => `${k.name[0].toUpperCase()}${k.name.substring(1)}`)\n          .join(', '),\n      });\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{title}</Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverMovieKeyword;\n"
  },
  {
    "path": "src/components/Discover/DiscoverMovieLanguage/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { MovieResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverMovieLanguage', {\n  languageMovies: '{language} Movies',\n});\n\nconst DiscoverMovieLanguage = () => {\n  const router = useRouter();\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<\n    MovieResult,\n    {\n      originalLanguage: {\n        iso_639_1: string;\n        english_name: string;\n        name: string;\n      };\n    }\n  >(`/api/v1/discover/movies/language/${router.query.language}`);\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = isLoadingInitialData\n    ? intl.formatMessage(globalMessages.loading)\n    : intl.formatMessage(messages.languageMovies, {\n        language: intl.formatDisplayName(router.query.language as string, {\n          type: 'language',\n          fallback: 'none',\n        }),\n      });\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{title}</Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverMovieLanguage;\n"
  },
  {
    "path": "src/components/Discover/DiscoverMovies/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport type { FilterOptions } from '@app/components/Discover/constants';\nimport {\n  countActiveFilters,\n  prepareFilterValues,\n} from '@app/components/Discover/constants';\nimport FilterSlideover from '@app/components/Discover/FilterSlideover';\nimport useDiscover from '@app/hooks/useDiscover';\nimport { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { BarsArrowDownIcon, FunnelIcon } from '@heroicons/react/24/solid';\nimport type { SortOptions as TMDBSortOptions } from '@server/api/themoviedb';\nimport type { MovieResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverMovies', {\n  discovermovies: 'Movies',\n  activefilters:\n    '{count, plural, one {# Active Filter} other {# Active Filters}}',\n  sortPopularityAsc: 'Popularity Ascending',\n  sortPopularityDesc: 'Popularity Descending',\n  sortReleaseDateAsc: 'Release Date Ascending',\n  sortReleaseDateDesc: 'Release Date Descending',\n  sortTmdbRatingAsc: 'TMDB Rating Ascending',\n  sortTmdbRatingDesc: 'TMDB Rating Descending',\n  sortTitleAsc: 'Title (A-Z) Ascending',\n  sortTitleDesc: 'Title (Z-A) Descending',\n});\n\nconst SortOptions: Record<string, TMDBSortOptions> = {\n  PopularityAsc: 'popularity.asc',\n  PopularityDesc: 'popularity.desc',\n  ReleaseDateAsc: 'release_date.asc',\n  ReleaseDateDesc: 'release_date.desc',\n  TmdbRatingAsc: 'vote_average.asc',\n  TmdbRatingDesc: 'vote_average.desc',\n  TitleAsc: 'original_title.asc',\n  TitleDesc: 'original_title.desc',\n} as const;\n\nconst DiscoverMovies = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const updateQueryParams = useUpdateQueryParams({});\n\n  const preparedFilters = prepareFilterValues(router.query);\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<MovieResult, unknown, FilterOptions>(\n    '/api/v1/discover/movies',\n    preparedFilters\n  );\n  const [showFilters, setShowFilters] = useState(false);\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = intl.formatMessage(messages.discovermovies);\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-4 flex flex-col justify-between lg:flex-row lg:items-end\">\n        <Header>{title}</Header>\n        <div className=\"mt-2 flex flex-grow flex-col sm:flex-row lg:flex-grow-0\">\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-gray-100 sm:text-sm\">\n              <BarsArrowDownIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"sortBy\"\n              name=\"sortBy\"\n              className=\"rounded-r-only\"\n              value={preparedFilters.sortBy || SortOptions.PopularityDesc}\n              onChange={(e) => updateQueryParams('sortBy', e.target.value)}\n            >\n              <option value={SortOptions.PopularityDesc}>\n                {intl.formatMessage(messages.sortPopularityDesc)}\n              </option>\n              <option value={SortOptions.PopularityAsc}>\n                {intl.formatMessage(messages.sortPopularityAsc)}\n              </option>\n              <option value={SortOptions.ReleaseDateDesc}>\n                {intl.formatMessage(messages.sortReleaseDateDesc)}\n              </option>\n              <option value={SortOptions.ReleaseDateAsc}>\n                {intl.formatMessage(messages.sortReleaseDateAsc)}\n              </option>\n              <option value={SortOptions.TmdbRatingDesc}>\n                {intl.formatMessage(messages.sortTmdbRatingDesc)}\n              </option>\n              <option value={SortOptions.TmdbRatingAsc}>\n                {intl.formatMessage(messages.sortTmdbRatingAsc)}\n              </option>\n              <option value={SortOptions.TitleAsc}>\n                {intl.formatMessage(messages.sortTitleAsc)}\n              </option>\n              <option value={SortOptions.TitleDesc}>\n                {intl.formatMessage(messages.sortTitleDesc)}\n              </option>\n            </select>\n          </div>\n          <FilterSlideover\n            type=\"movie\"\n            currentFilters={preparedFilters}\n            onClose={() => setShowFilters(false)}\n            show={showFilters}\n          />\n          <div className=\"mb-2 flex flex-grow sm:mb-0 lg:flex-grow-0\">\n            <Button onClick={() => setShowFilters(true)} className=\"w-full\">\n              <FunnelIcon />\n              <span>\n                {intl.formatMessage(messages.activefilters, {\n                  count: countActiveFilters(preparedFilters),\n                })}\n              </span>\n            </Button>\n          </div>\n        </div>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverMovies;\n"
  },
  {
    "path": "src/components/Discover/DiscoverNetwork/index.tsx",
    "content": "import CachedImage from '@app/components/Common/CachedImage';\nimport Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TvNetwork } from '@server/models/common';\nimport type { TvResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverNetwork', {\n  networkSeries: '{network} Series',\n});\n\nconst DiscoverTvNetwork = () => {\n  const router = useRouter();\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n    firstResultData,\n  } = useDiscover<TvResult, { network: TvNetwork }>(\n    `/api/v1/discover/tv/network/${router.query.networkId}`\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = isLoadingInitialData\n    ? intl.formatMessage(globalMessages.loading)\n    : intl.formatMessage(messages.networkSeries, {\n        network: firstResultData?.network.name,\n      });\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-5 mt-1\">\n        <Header>\n          {firstResultData?.network.logoPath ? (\n            <div className=\"relative mb-6 flex h-24 justify-center sm:h-32\">\n              <CachedImage\n                type=\"tmdb\"\n                src={`https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)${firstResultData.network.logoPath}`}\n                alt={firstResultData.network.name}\n                className=\"object-contain\"\n                fill\n              />\n            </div>\n          ) : (\n            title\n          )}\n        </Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverTvNetwork;\n"
  },
  {
    "path": "src/components/Discover/DiscoverSliderEdit/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport SlideCheckbox from '@app/components/Common/SlideCheckbox';\nimport Tag from '@app/components/Common/Tag';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport CompanyTag from '@app/components/CompanyTag';\nimport { sliderTitles } from '@app/components/Discover/constants';\nimport CreateSlider from '@app/components/Discover/CreateSlider';\nimport GenreTag from '@app/components/GenreTag';\nimport KeywordTag from '@app/components/KeywordTag';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { MagnifyingGlassIcon } from '@heroicons/react/24/outline';\nimport {\n  ArrowUturnLeftIcon,\n  Bars3Icon,\n  ChevronDownIcon,\n  ChevronUpIcon,\n  PencilIcon,\n  XMarkIcon,\n} from '@heroicons/react/24/solid';\nimport { DiscoverSliderType } from '@server/constants/discover';\nimport type DiscoverSlider from '@server/entity/DiscoverSlider';\nimport axios from 'axios';\nimport { useRef, useState } from 'react';\nimport { useDrag, useDrop } from 'react-aria';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\n\nconst messages = defineMessages('components.Discover.DiscoverSliderEdit', {\n  deletesuccess: 'Sucessfully deleted slider.',\n  deletefail: 'Failed to delete slider.',\n  remove: 'Remove',\n  enable: 'Toggle Visibility',\n});\n\nconst Position = {\n  None: 'None',\n  Above: 'Above',\n  Below: 'Below',\n} as const;\n\ntype DiscoverSliderEditProps = {\n  slider: Partial<DiscoverSlider>;\n  onEnable: () => void;\n  onDelete: () => void;\n  onPositionUpdate: (\n    updatedItemId: number,\n    position: keyof typeof Position,\n    isClickable: boolean\n  ) => void;\n  children: React.ReactNode;\n  disableUpButton: boolean;\n  disableDownButton: boolean;\n};\n\nconst DiscoverSliderEdit = ({\n  slider,\n  children,\n  onEnable,\n  onDelete,\n  onPositionUpdate,\n  disableUpButton,\n  disableDownButton,\n}: DiscoverSliderEditProps) => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const [isEditing, setIsEditing] = useState(false);\n  const ref = useRef<HTMLDivElement>(null);\n  const [hoverPosition, setHoverPosition] = useState<keyof typeof Position>(\n    Position.None\n  );\n\n  const { dragProps, isDragging } = useDrag({\n    getItems() {\n      return [{ id: (slider.id ?? -1).toString(), title: slider.title ?? '' }];\n    },\n  });\n\n  const deleteSlider = async () => {\n    try {\n      await axios.delete(`/api/v1/settings/discover/${slider.id}`);\n      addToast(intl.formatMessage(messages.deletesuccess), {\n        appearance: 'success',\n        autoDismiss: true,\n      });\n      onDelete();\n    } catch {\n      addToast(intl.formatMessage(messages.deletefail), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n  };\n\n  const { dropProps } = useDrop({\n    ref,\n    onDropMove: (e) => {\n      if (ref.current) {\n        const middlePoint = ref.current.offsetHeight / 2;\n\n        if (e.y < middlePoint) {\n          setHoverPosition(Position.Above);\n        } else {\n          setHoverPosition(Position.Below);\n        }\n      }\n    },\n    onDropExit: () => {\n      setHoverPosition(Position.None);\n    },\n    onDrop: async (e) => {\n      const items = await Promise.all(\n        e.items\n          .filter((item) => item.kind === 'text' && item.types.has('id'))\n          .map(async (item) => {\n            if (item.kind === 'text') {\n              return item.getText('id');\n            }\n          })\n      );\n      if (items?.[0]) {\n        const dropped = Number(items[0]);\n        onPositionUpdate(dropped, hoverPosition, false);\n      }\n    },\n  });\n\n  const getSliderTitle = (slider: Partial<DiscoverSlider>): string => {\n    switch (slider.type) {\n      case DiscoverSliderType.RECENTLY_ADDED:\n        return intl.formatMessage(sliderTitles.recentlyAdded);\n      case DiscoverSliderType.RECENT_REQUESTS:\n        return intl.formatMessage(sliderTitles.recentrequests);\n      case DiscoverSliderType.PLEX_WATCHLIST:\n        return intl.formatMessage(sliderTitles.plexwatchlist);\n      case DiscoverSliderType.TRENDING:\n        return intl.formatMessage(sliderTitles.trending);\n      case DiscoverSliderType.POPULAR_MOVIES:\n        return intl.formatMessage(sliderTitles.popularmovies);\n      case DiscoverSliderType.MOVIE_GENRES:\n        return intl.formatMessage(sliderTitles.moviegenres);\n      case DiscoverSliderType.UPCOMING_MOVIES:\n        return intl.formatMessage(sliderTitles.upcoming);\n      case DiscoverSliderType.STUDIOS:\n        return intl.formatMessage(sliderTitles.studios);\n      case DiscoverSliderType.POPULAR_TV:\n        return intl.formatMessage(sliderTitles.populartv);\n      case DiscoverSliderType.TV_GENRES:\n        return intl.formatMessage(sliderTitles.tvgenres);\n      case DiscoverSliderType.UPCOMING_TV:\n        return intl.formatMessage(sliderTitles.upcomingtv);\n      case DiscoverSliderType.NETWORKS:\n        return intl.formatMessage(sliderTitles.networks);\n      case DiscoverSliderType.TMDB_MOVIE_KEYWORD:\n        return intl.formatMessage(sliderTitles.tmdbmoviekeyword);\n      case DiscoverSliderType.TMDB_TV_KEYWORD:\n        return intl.formatMessage(sliderTitles.tmdbtvkeyword);\n      case DiscoverSliderType.TMDB_MOVIE_GENRE:\n        return intl.formatMessage(sliderTitles.tmdbmoviegenre);\n      case DiscoverSliderType.TMDB_TV_GENRE:\n        return intl.formatMessage(sliderTitles.tmdbtvgenre);\n      case DiscoverSliderType.TMDB_STUDIO:\n        return intl.formatMessage(sliderTitles.tmdbstudio);\n      case DiscoverSliderType.TMDB_NETWORK:\n        return intl.formatMessage(sliderTitles.tmdbnetwork);\n      case DiscoverSliderType.TMDB_SEARCH:\n        return intl.formatMessage(sliderTitles.tmdbsearch);\n      case DiscoverSliderType.TMDB_MOVIE_STREAMING_SERVICES:\n        return intl.formatMessage(sliderTitles.tmdbmoviestreamingservices);\n      case DiscoverSliderType.TMDB_TV_STREAMING_SERVICES:\n        return intl.formatMessage(sliderTitles.tmdbtvstreamingservices);\n      default:\n        return 'Unknown Slider';\n    }\n  };\n\n  return (\n    <div\n      key={`discover-slider-${slider.id}-editing`}\n      data-testid=\"discover-slider-edit-mode\"\n      className={`relative mb-4 rounded-lg bg-gray-800 shadow-md ${\n        isDragging ? 'opacity-0' : 'opacity-100'\n      }`}\n      {...dragProps}\n      {...dropProps}\n      ref={ref}\n    >\n      {hoverPosition === Position.Above && (\n        <div\n          className={`absolute -top-3 left-0 w-full border-t-4 border-indigo-500`}\n        />\n      )}\n      {hoverPosition === Position.Below && (\n        <div\n          className={`absolute -bottom-2 left-0 w-full border-t-4 border-indigo-500`}\n        />\n      )}\n      <div className=\"flex w-full flex-col rounded-t-lg border-l border-r border-t border-gray-800 bg-gray-900 p-4 text-gray-400 md:flex-row md:items-center md:space-x-2\">\n        <div\n          className={`${slider.data ? 'mb-4' : 'mb-0'} flex space-x-2 md:mb-0`}\n        >\n          <Bars3Icon className=\"h-6 w-6\" />\n          <div className=\"w-7/12 truncate md:w-full\">\n            {getSliderTitle(slider)}\n          </div>\n        </div>\n        <div\n          className={`pointer-events-none ${\n            slider.data ? 'mb-4' : ''\n          } flex-1 md:mb-0`}\n        >\n          {(slider.type === DiscoverSliderType.TMDB_MOVIE_KEYWORD ||\n            slider.type === DiscoverSliderType.TMDB_TV_KEYWORD) && (\n            <div className=\"flex space-x-2\">\n              {slider.data?.split(',').map((keywordId) => (\n                <KeywordTag\n                  key={`slider-keywords-${slider.id}-${keywordId}`}\n                  keywordId={Number(keywordId)}\n                />\n              ))}\n            </div>\n          )}\n          {(slider.type === DiscoverSliderType.TMDB_NETWORK ||\n            slider.type === DiscoverSliderType.TMDB_STUDIO) && (\n            <CompanyTag\n              type={\n                slider.type === DiscoverSliderType.TMDB_STUDIO\n                  ? 'studio'\n                  : 'network'\n              }\n              companyId={Number(slider.data)}\n            />\n          )}\n          {(slider.type === DiscoverSliderType.TMDB_TV_GENRE ||\n            slider.type === DiscoverSliderType.TMDB_MOVIE_GENRE) && (\n            <GenreTag\n              type={\n                slider.type === DiscoverSliderType.TMDB_MOVIE_GENRE\n                  ? 'movie'\n                  : 'tv'\n              }\n              genreId={Number(slider.data)}\n            />\n          )}\n          {slider.type === DiscoverSliderType.TMDB_SEARCH && (\n            <Tag iconSvg={<MagnifyingGlassIcon />}>{slider.data}</Tag>\n          )}\n        </div>\n        <div className=\"flex items-center space-x-2\">\n          {!slider.isBuiltIn && (\n            <>\n              {!isEditing ? (\n                <Button\n                  buttonType=\"warning\"\n                  buttonSize=\"sm\"\n                  onClick={() => {\n                    setIsEditing(true);\n                  }}\n                >\n                  <PencilIcon />\n                  <span>{intl.formatMessage(globalMessages.edit)}</span>\n                </Button>\n              ) : (\n                <Button\n                  buttonType=\"default\"\n                  buttonSize=\"sm\"\n                  onClick={() => {\n                    setIsEditing(false);\n                  }}\n                >\n                  <ArrowUturnLeftIcon />\n                  <span>{intl.formatMessage(globalMessages.cancel)}</span>\n                </Button>\n              )}\n              <Button\n                data-testid=\"discover-slider-remove-button\"\n                buttonType=\"danger\"\n                buttonSize=\"sm\"\n                onClick={() => {\n                  deleteSlider();\n                }}\n              >\n                <XMarkIcon />\n                <span>{intl.formatMessage(messages.remove)}</span>\n              </Button>\n            </>\n          )}\n          <div className=\"absolute right-14 top-4 flex px-2 md:relative md:right-0 md:top-0\">\n            <button\n              className={'hover:text-white disabled:text-gray-800'}\n              onClick={() =>\n                onPositionUpdate(Number(slider.id), Position.Above, true)\n              }\n              disabled={disableUpButton}\n            >\n              <ChevronUpIcon className=\"h-7 w-7 md:h-6 md:w-6\" />\n            </button>\n            <button\n              className={'hover:text-white disabled:text-gray-800'}\n              onClick={() =>\n                onPositionUpdate(Number(slider.id), Position.Below, true)\n              }\n              disabled={disableDownButton}\n            >\n              <ChevronDownIcon className=\"h-7 w-7 md:h-6 md:w-6\" />\n            </button>\n          </div>\n          <div className=\"absolute right-4 top-4 flex-1 text-right md:relative md:right-0 md:top-0\">\n            <Tooltip content={intl.formatMessage(messages.enable)}>\n              <div>\n                <SlideCheckbox\n                  onClick={() => {\n                    onEnable();\n                  }}\n                  checked={slider.enabled}\n                />\n              </div>\n            </Tooltip>\n          </div>\n        </div>\n      </div>\n      {isEditing ? (\n        <div className=\"p-4\">\n          <CreateSlider\n            onCreate={() => {\n              onDelete();\n              setIsEditing(false);\n            }}\n            slider={slider}\n          />\n        </div>\n      ) : (\n        <div className={`-mt-6 p-4 ${!slider.enabled ? 'opacity-50' : ''}`}>\n          {children}\n        </div>\n      )}\n    </div>\n  );\n};\n\nexport default DiscoverSliderEdit;\n"
  },
  {
    "path": "src/components/Discover/DiscoverStudio/index.tsx",
    "content": "import CachedImage from '@app/components/Common/CachedImage';\nimport Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { ProductionCompany } from '@server/models/common';\nimport type { MovieResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverStudio', {\n  studioMovies: '{studio} Movies',\n});\n\nconst DiscoverMovieStudio = () => {\n  const router = useRouter();\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n    firstResultData,\n  } = useDiscover<MovieResult, { studio: ProductionCompany }>(\n    `/api/v1/discover/movies/studio/${router.query.studioId}`\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = isLoadingInitialData\n    ? intl.formatMessage(globalMessages.loading)\n    : intl.formatMessage(messages.studioMovies, {\n        studio: firstResultData?.studio.name,\n      });\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-5 mt-1\">\n        <Header>\n          {firstResultData?.studio.logoPath ? (\n            <div className=\"relative mb-6 flex h-24 justify-center sm:h-32\">\n              <CachedImage\n                type=\"tmdb\"\n                src={`https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)${firstResultData.studio.logoPath}`}\n                alt={firstResultData.studio.name}\n                className=\"object-contain\"\n                fill\n              />\n            </div>\n          ) : (\n            title\n          )}\n        </Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverMovieStudio;\n"
  },
  {
    "path": "src/components/Discover/DiscoverTv/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport type { FilterOptions } from '@app/components/Discover/constants';\nimport {\n  countActiveFilters,\n  prepareFilterValues,\n} from '@app/components/Discover/constants';\nimport FilterSlideover from '@app/components/Discover/FilterSlideover';\nimport useDiscover from '@app/hooks/useDiscover';\nimport { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { BarsArrowDownIcon, FunnelIcon } from '@heroicons/react/24/solid';\nimport type { SortOptions as TMDBSortOptions } from '@server/api/themoviedb';\nimport type { TvResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverTv', {\n  discovertv: 'Series',\n  activefilters:\n    '{count, plural, one {# Active Filter} other {# Active Filters}}',\n  sortPopularityAsc: 'Popularity Ascending',\n  sortPopularityDesc: 'Popularity Descending',\n  sortFirstAirDateAsc: 'First Air Date Ascending',\n  sortFirstAirDateDesc: 'First Air Date Descending',\n  sortTmdbRatingAsc: 'TMDB Rating Ascending',\n  sortTmdbRatingDesc: 'TMDB Rating Descending',\n  sortTitleAsc: 'Title (A-Z) Ascending',\n  sortTitleDesc: 'Title (Z-A) Descending',\n});\n\nconst SortOptions: Record<string, TMDBSortOptions> = {\n  PopularityAsc: 'popularity.asc',\n  PopularityDesc: 'popularity.desc',\n  FirstAirDateAsc: 'first_air_date.asc',\n  FirstAirDateDesc: 'first_air_date.desc',\n  TmdbRatingAsc: 'vote_average.asc',\n  TmdbRatingDesc: 'vote_average.desc',\n  TitleAsc: 'original_title.asc',\n  TitleDesc: 'original_title.desc',\n} as const;\n\nconst DiscoverTv = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const [showFilters, setShowFilters] = useState(false);\n  const preparedFilters = prepareFilterValues(router.query);\n  const updateQueryParams = useUpdateQueryParams({});\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<TvResult, never, FilterOptions>('/api/v1/discover/tv', {\n    ...preparedFilters,\n  });\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = intl.formatMessage(messages.discovertv);\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-4 flex flex-col justify-between lg:flex-row lg:items-end\">\n        <Header>{title}</Header>\n        <div className=\"mt-2 flex flex-grow flex-col sm:flex-row lg:flex-grow-0\">\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-gray-100 sm:text-sm\">\n              <BarsArrowDownIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"sortBy\"\n              name=\"sortBy\"\n              className=\"rounded-r-only\"\n              value={preparedFilters.sortBy || SortOptions.PopularityDesc}\n              onChange={(e) => updateQueryParams('sortBy', e.target.value)}\n            >\n              <option value={SortOptions.PopularityDesc}>\n                {intl.formatMessage(messages.sortPopularityDesc)}\n              </option>\n              <option value={SortOptions.PopularityAsc}>\n                {intl.formatMessage(messages.sortPopularityAsc)}\n              </option>\n              <option value={SortOptions.FirstAirDateDesc}>\n                {intl.formatMessage(messages.sortFirstAirDateDesc)}\n              </option>\n              <option value={SortOptions.FirstAirDateAsc}>\n                {intl.formatMessage(messages.sortFirstAirDateAsc)}\n              </option>\n              <option value={SortOptions.TmdbRatingDesc}>\n                {intl.formatMessage(messages.sortTmdbRatingDesc)}\n              </option>\n              <option value={SortOptions.TmdbRatingAsc}>\n                {intl.formatMessage(messages.sortTmdbRatingAsc)}\n              </option>\n              <option value={SortOptions.TitleAsc}>\n                {intl.formatMessage(messages.sortTitleAsc)}\n              </option>\n              <option value={SortOptions.TitleDesc}>\n                {intl.formatMessage(messages.sortTitleDesc)}\n              </option>\n            </select>\n          </div>\n          <FilterSlideover\n            type=\"tv\"\n            currentFilters={preparedFilters}\n            onClose={() => setShowFilters(false)}\n            show={showFilters}\n          />\n          <div className=\"mb-2 flex flex-grow sm:mb-0 lg:flex-grow-0\">\n            <Button onClick={() => setShowFilters(true)} className=\"w-full\">\n              <FunnelIcon />\n              <span>\n                {intl.formatMessage(messages.activefilters, {\n                  count: countActiveFilters(preparedFilters),\n                })}\n              </span>\n            </Button>\n          </div>\n        </div>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isReachingEnd={isReachingEnd}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverTv;\n"
  },
  {
    "path": "src/components/Discover/DiscoverTvGenre/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TvResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverTvGenre', {\n  genreSeries: '{genre} Series',\n});\n\nconst DiscoverTvGenre = () => {\n  const router = useRouter();\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n    firstResultData,\n  } = useDiscover<TvResult, { genre: { id: number; name: string } }>(\n    `/api/v1/discover/tv/genre/${router.query.genreId}`\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = isLoadingInitialData\n    ? intl.formatMessage(globalMessages.loading)\n    : intl.formatMessage(messages.genreSeries, {\n        genre: firstResultData?.genre.name,\n      });\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{title}</Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverTvGenre;\n"
  },
  {
    "path": "src/components/Discover/DiscoverTvKeyword/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover, { encodeURIExtraParams } from '@app/hooks/useDiscover';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TmdbKeyword } from '@server/api/themoviedb/interfaces';\nimport type { TvResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverTvKeyword', {\n  keywordSeries: '{keywordTitle} Series',\n});\n\nconst DiscoverTvKeyword = () => {\n  const router = useRouter();\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n    firstResultData,\n  } = useDiscover<TvResult, { keywords: TmdbKeyword[] }>(\n    `/api/v1/discover/tv`,\n    {\n      keywords: encodeURIExtraParams(router.query.keywords as string),\n    }\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = isLoadingInitialData\n    ? intl.formatMessage(globalMessages.loading)\n    : intl.formatMessage(messages.keywordSeries, {\n        keywordTitle: firstResultData?.keywords\n          .map((k) => `${k.name[0].toUpperCase()}${k.name.substring(1)}`)\n          .join(', '),\n      });\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{title}</Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverTvKeyword;\n"
  },
  {
    "path": "src/components/Discover/DiscoverTvLanguage/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TvResult } from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverTvLanguage', {\n  languageSeries: '{language} Series',\n});\n\nconst DiscoverTvLanguage = () => {\n  const router = useRouter();\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<\n    TvResult,\n    {\n      originalLanguage: {\n        iso_639_1: string;\n        english_name: string;\n        name: string;\n      };\n    }\n  >(`/api/v1/discover/tv/language/${router.query.language}`);\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = isLoadingInitialData\n    ? intl.formatMessage(globalMessages.loading)\n    : intl.formatMessage(messages.languageSeries, {\n        language: intl.formatDisplayName(router.query.language as string, {\n          type: 'language',\n          fallback: 'none',\n        }),\n      });\n\n  return (\n    <>\n      <PageTitle title={title} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{title}</Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverTvLanguage;\n"
  },
  {
    "path": "src/components/Discover/DiscoverTvUpcoming.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TvResult } from '@server/models/Search';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.DiscoverTvUpcoming', {\n  upcomingtv: 'Upcoming Series',\n});\n\nconst DiscoverTvUpcoming = () => {\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<TvResult>('/api/v1/discover/tv/upcoming');\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(messages.upcomingtv)} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{intl.formatMessage(messages.upcomingtv)}</Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isReachingEnd={isReachingEnd}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default DiscoverTvUpcoming;\n"
  },
  {
    "path": "src/components/Discover/DiscoverWatchlist/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport { useUser } from '@app/hooks/useUser';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { WatchlistItem } from '@server/interfaces/api/discoverInterfaces';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.DiscoverWatchlist', {\n  discoverwatchlist: 'Your Watchlist',\n  watchlist: 'Plex Watchlist',\n});\n\nconst DiscoverWatchlist = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const { user } = useUser({\n    id: Number(router.query.userId),\n  });\n  const { user: currentUser } = useUser();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n    mutate,\n  } = useDiscover<WatchlistItem>(\n    `/api/v1/${\n      router.pathname.startsWith('/profile')\n        ? `user/${currentUser?.id}`\n        : router.query.userId\n          ? `user/${router.query.userId}`\n          : 'discover'\n    }/watchlist`\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const title = intl.formatMessage(\n    router.query.userId ? messages.watchlist : messages.discoverwatchlist\n  );\n\n  return (\n    <>\n      <PageTitle\n        title={[title, router.query.userId ? user?.displayName : '']}\n      />\n      <div className=\"mb-5 mt-1\">\n        <Header\n          subtext={\n            router.query.userId ? (\n              <Link href={`/users/${user?.id}`} className=\"hover:underline\">\n                {user?.displayName}\n              </Link>\n            ) : (\n              ''\n            )\n          }\n        >\n          {title}\n        </Header>\n      </div>\n      <ListView\n        plexItems={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n        mutateParent={mutate}\n      />\n    </>\n  );\n};\n\nexport default DiscoverWatchlist;\n"
  },
  {
    "path": "src/components/Discover/FilterSlideover/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport MultiRangeSlider from '@app/components/Common/MultiRangeSlider';\nimport SlideOver from '@app/components/Common/SlideOver';\nimport type { FilterOptions } from '@app/components/Discover/constants';\nimport { countActiveFilters } from '@app/components/Discover/constants';\nimport LanguageSelector from '@app/components/LanguageSelector';\nimport {\n  CompanySelector,\n  GenreSelector,\n  KeywordSelector,\n  StatusSelector,\n  USCertificationSelector,\n  WatchProviderSelector,\n} from '@app/components/Selector';\nimport useSettings from '@app/hooks/useSettings';\nimport {\n  useBatchUpdateQueryParams,\n  useUpdateQueryParams,\n} from '@app/hooks/useUpdateQueryParams';\nimport defineMessages from '@app/utils/defineMessages';\nimport { XCircleIcon } from '@heroicons/react/24/outline';\nimport Datepicker from '@seerr-team/react-tailwindcss-datepicker';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.FilterSlideover', {\n  filters: 'Filters',\n  activefilters:\n    '{count, plural, one {# Active Filter} other {# Active Filters}}',\n  releaseDate: 'Release Date',\n  firstAirDate: 'First Air Date',\n  from: 'From',\n  to: 'To',\n  studio: 'Studio',\n  genres: 'Genres',\n  keywords: 'Keywords',\n  excludeKeywords: 'Exclude Keywords',\n  originalLanguage: 'Original Language',\n  runtimeText: '{minValue}-{maxValue} minute runtime',\n  ratingText: 'Ratings between {minValue} and {maxValue}',\n  clearfilters: 'Clear Active Filters',\n  tmdbuserscore: 'TMDB User Score',\n  tmdbuservotecount: 'TMDB User Vote Count',\n  runtime: 'Runtime',\n  streamingservices: 'Streaming Services',\n  voteCount: 'Number of votes between {minValue} and {maxValue}',\n  status: 'Status',\n  certification: 'Content Rating',\n});\n\ntype FilterSlideoverProps = {\n  show: boolean;\n  onClose: () => void;\n  type: 'movie' | 'tv';\n  currentFilters: FilterOptions;\n};\n\nconst FilterSlideover = ({\n  show,\n  onClose,\n  type,\n  currentFilters,\n}: FilterSlideoverProps) => {\n  const intl = useIntl();\n  const { currentSettings } = useSettings();\n  const updateQueryParams = useUpdateQueryParams({});\n  const batchUpdateQueryParams = useBatchUpdateQueryParams({});\n\n  const dateGte =\n    type === 'movie' ? 'primaryReleaseDateGte' : 'firstAirDateGte';\n  const dateLte =\n    type === 'movie' ? 'primaryReleaseDateLte' : 'firstAirDateLte';\n\n  return (\n    <SlideOver\n      show={show}\n      title={intl.formatMessage(messages.filters)}\n      subText={intl.formatMessage(messages.activefilters, {\n        count: countActiveFilters(currentFilters),\n      })}\n      onClose={() => onClose()}\n    >\n      <div className=\"flex flex-col space-y-4\">\n        <div>\n          <div className=\"mb-2 text-lg font-semibold\">\n            {intl.formatMessage(\n              type === 'movie' ? messages.releaseDate : messages.firstAirDate\n            )}\n          </div>\n          <div className=\"relative z-40 flex space-x-2\">\n            <div className=\"flex flex-col\">\n              <div className=\"mb-2\">{intl.formatMessage(messages.from)}</div>\n              <Datepicker\n                primaryColor=\"indigo\"\n                value={{\n                  startDate: currentFilters[dateGte] ?? null,\n                  endDate: currentFilters[dateGte] ?? null,\n                }}\n                onChange={(value) => {\n                  updateQueryParams(\n                    dateGte,\n                    value?.startDate ? (value.startDate as string) : undefined\n                  );\n                }}\n                inputName=\"fromdate\"\n                useRange={false}\n                asSingle\n                containerClassName=\"datepicker-wrapper\"\n                inputClassName=\"pr-1 sm:pr-4 text-base leading-5\"\n              />\n            </div>\n            <div className=\"flex flex-col\">\n              <div className=\"mb-2\">{intl.formatMessage(messages.to)}</div>\n              <Datepicker\n                primaryColor=\"indigo\"\n                value={{\n                  startDate: currentFilters[dateLte] ?? null,\n                  endDate: currentFilters[dateLte] ?? null,\n                }}\n                onChange={(value) => {\n                  updateQueryParams(\n                    dateLte,\n                    value?.startDate ? (value.startDate as string) : undefined\n                  );\n                }}\n                inputName=\"todate\"\n                useRange={false}\n                asSingle\n                containerClassName=\"datepicker-wrapper\"\n                inputClassName=\"pr-1 sm:pr-4 text-base leading-5\"\n              />\n            </div>\n          </div>\n        </div>\n        {type === 'movie' && (\n          <>\n            <span className=\"text-lg font-semibold\">\n              {intl.formatMessage(messages.studio)}\n            </span>\n            <CompanySelector\n              defaultValue={currentFilters.studio}\n              onChange={(value) => {\n                updateQueryParams('studio', value?.value.toString());\n              }}\n            />\n          </>\n        )}\n        <span className=\"text-lg font-semibold\">\n          {intl.formatMessage(messages.genres)}\n        </span>\n        <GenreSelector\n          type={type}\n          defaultValue={currentFilters.genre}\n          isMulti\n          onChange={(value) => {\n            updateQueryParams('genre', value?.map((v) => v.value).join(','));\n          }}\n        />\n        {type === 'tv' && (\n          <>\n            <span className=\"text-lg font-semibold\">\n              {intl.formatMessage(messages.status)}\n            </span>\n            <StatusSelector\n              defaultValue={currentFilters.status}\n              isMulti\n              onChange={(value) => {\n                updateQueryParams(\n                  'status',\n                  value?.map((v) => v.value).join('|')\n                );\n              }}\n            />\n          </>\n        )}\n        <span className=\"text-lg font-semibold\">\n          {intl.formatMessage(messages.keywords)}\n        </span>\n        <KeywordSelector\n          defaultValue={currentFilters.keywords}\n          isMulti\n          onChange={(value) => {\n            updateQueryParams('keywords', value?.map((v) => v.value).join(','));\n          }}\n        />\n        <span className=\"text-lg font-semibold\">\n          {intl.formatMessage(messages.excludeKeywords)}\n        </span>\n        <KeywordSelector\n          defaultValue={currentFilters.excludeKeywords}\n          isMulti\n          onChange={(value) => {\n            updateQueryParams(\n              'excludeKeywords',\n              value?.map((v) => v.value).join(',')\n            );\n          }}\n        />\n        <span className=\"text-lg font-semibold\">\n          {intl.formatMessage(messages.originalLanguage)}\n        </span>\n        <LanguageSelector\n          value={currentFilters.language}\n          serverValue={currentSettings.originalLanguage}\n          isUserSettings\n          setFieldValue={(_key, value) => {\n            updateQueryParams('language', value);\n          }}\n        />\n        <span className=\"text-lg font-semibold\">\n          {intl.formatMessage(messages.certification)}\n        </span>\n        <USCertificationSelector\n          type={type}\n          certification={currentFilters.certification}\n          onChange={(params) => {\n            batchUpdateQueryParams(params);\n          }}\n        />\n        <span className=\"text-lg font-semibold\">\n          {intl.formatMessage(messages.runtime)}\n        </span>\n        <div className=\"relative z-0\">\n          <MultiRangeSlider\n            min={0}\n            max={400}\n            onUpdateMin={(min) => {\n              updateQueryParams(\n                'withRuntimeGte',\n                min !== 0 && Number(currentFilters.withRuntimeLte) !== 400\n                  ? min.toString()\n                  : undefined\n              );\n            }}\n            onUpdateMax={(max) => {\n              updateQueryParams(\n                'withRuntimeLte',\n                max !== 400 && Number(currentFilters.withRuntimeGte) !== 0\n                  ? max.toString()\n                  : undefined\n              );\n            }}\n            defaultMaxValue={\n              currentFilters.withRuntimeLte\n                ? Number(currentFilters.withRuntimeLte)\n                : undefined\n            }\n            defaultMinValue={\n              currentFilters.withRuntimeGte\n                ? Number(currentFilters.withRuntimeGte)\n                : undefined\n            }\n            subText={intl.formatMessage(messages.runtimeText, {\n              minValue: currentFilters.withRuntimeGte ?? 0,\n              maxValue: currentFilters.withRuntimeLte ?? 400,\n            })}\n          />\n        </div>\n        <span className=\"text-lg font-semibold\">\n          {intl.formatMessage(messages.tmdbuserscore)}\n        </span>\n        <div className=\"relative z-0\">\n          <MultiRangeSlider\n            min={1}\n            max={10}\n            defaultMaxValue={\n              currentFilters.voteAverageLte\n                ? Number(currentFilters.voteAverageLte)\n                : undefined\n            }\n            defaultMinValue={\n              currentFilters.voteAverageGte\n                ? Number(currentFilters.voteAverageGte)\n                : undefined\n            }\n            onUpdateMin={(min) => {\n              updateQueryParams(\n                'voteAverageGte',\n                min !== 1 && Number(currentFilters.voteAverageLte) !== 10\n                  ? min.toString()\n                  : undefined\n              );\n            }}\n            onUpdateMax={(max) => {\n              updateQueryParams(\n                'voteAverageLte',\n                max !== 10 && Number(currentFilters.voteAverageGte) !== 1\n                  ? max.toString()\n                  : undefined\n              );\n            }}\n            subText={intl.formatMessage(messages.ratingText, {\n              minValue: currentFilters.voteAverageGte ?? 1,\n              maxValue: currentFilters.voteAverageLte ?? 10,\n            })}\n          />\n        </div>\n        <span className=\"text-lg font-semibold\">\n          {intl.formatMessage(messages.tmdbuservotecount)}\n        </span>\n        <div className=\"relative z-0\">\n          <MultiRangeSlider\n            min={0}\n            max={1000}\n            defaultMaxValue={\n              currentFilters.voteCountLte\n                ? Number(currentFilters.voteCountLte)\n                : undefined\n            }\n            defaultMinValue={\n              currentFilters.voteCountGte\n                ? Number(currentFilters.voteCountGte)\n                : undefined\n            }\n            onUpdateMin={(min) => {\n              updateQueryParams(\n                'voteCountGte',\n                min !== 0 && Number(currentFilters.voteCountLte) !== 1000\n                  ? min.toString()\n                  : undefined\n              );\n            }}\n            onUpdateMax={(max) => {\n              updateQueryParams(\n                'voteCountLte',\n                max !== 1000 && Number(currentFilters.voteCountGte) !== 0\n                  ? max.toString()\n                  : undefined\n              );\n            }}\n            subText={intl.formatMessage(messages.voteCount, {\n              minValue: currentFilters.voteCountGte ?? 0,\n              maxValue: currentFilters.voteCountLte ?? 1000,\n            })}\n          />\n        </div>\n        <span className=\"text-lg font-semibold\">\n          {intl.formatMessage(messages.streamingservices)}\n        </span>\n        <WatchProviderSelector\n          type={type}\n          region={currentFilters.watchRegion}\n          activeProviders={\n            currentFilters.watchProviders?.split('|').map((v) => Number(v)) ??\n            []\n          }\n          onChange={(region, providers) => {\n            if (providers.length) {\n              batchUpdateQueryParams({\n                watchRegion: region,\n                watchProviders: providers.join('|'),\n              });\n            } else {\n              batchUpdateQueryParams({\n                watchRegion: undefined,\n                watchProviders: undefined,\n              });\n            }\n          }}\n        />\n        <div className=\"pt-4\">\n          <Button\n            className=\"w-full\"\n            disabled={Object.keys(currentFilters).length === 0}\n            onClick={() => {\n              const copyCurrent = Object.assign({}, currentFilters);\n              (\n                Object.keys(copyCurrent) as (keyof typeof currentFilters)[]\n              ).forEach((k) => {\n                copyCurrent[k] = undefined;\n              });\n              batchUpdateQueryParams(copyCurrent);\n              onClose();\n            }}\n          >\n            <XCircleIcon />\n            <span>{intl.formatMessage(messages.clearfilters)}</span>\n          </Button>\n        </div>\n      </div>\n    </SlideOver>\n  );\n};\n\nexport default FilterSlideover;\n"
  },
  {
    "path": "src/components/Discover/MovieGenreList/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport { genreColorMap } from '@app/components/Discover/constants';\nimport GenreCard from '@app/components/GenreCard';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { GenreSliderItem } from '@server/interfaces/api/discoverInterfaces';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Discover.MovieGenreList', {\n  moviegenres: 'Movie Genres',\n});\n\nconst MovieGenreList = () => {\n  const intl = useIntl();\n  const { data, error } = useSWR<GenreSliderItem[]>(\n    `/api/v1/discover/genreslider/movie`\n  );\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(messages.moviegenres)} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{intl.formatMessage(messages.moviegenres)}</Header>\n      </div>\n      <ul className=\"cards-horizontal\">\n        {data.map((genre, index) => (\n          <li key={`genre-${genre.id}-${index}`}>\n            <GenreCard\n              name={genre.name}\n              image={`https://image.tmdb.org/t/p/w1280_filter(duotone,${\n                genreColorMap[genre.id] ?? genreColorMap[0]\n              })${genre.backdrops[4]}`}\n              url={`/discover/movies/genre/${genre.id}`}\n              canExpand\n            />\n          </li>\n        ))}\n      </ul>\n    </>\n  );\n};\n\nexport default MovieGenreList;\n"
  },
  {
    "path": "src/components/Discover/MovieGenreSlider/index.tsx",
    "content": "import { genreColorMap } from '@app/components/Discover/constants';\nimport GenreCard from '@app/components/GenreCard';\nimport Slider from '@app/components/Slider';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowRightCircleIcon } from '@heroicons/react/24/outline';\nimport type { GenreSliderItem } from '@server/interfaces/api/discoverInterfaces';\nimport Link from 'next/link';\nimport React from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Discover.MovieGenreSlider', {\n  moviegenres: 'Movie Genres',\n});\n\nconst MovieGenreSlider = () => {\n  const intl = useIntl();\n  const { data, error } = useSWR<GenreSliderItem[]>(\n    `/api/v1/discover/genreslider/movie`,\n    {\n      refreshInterval: 0,\n      revalidateOnFocus: false,\n    }\n  );\n\n  return (\n    <>\n      <div className=\"slider-header\">\n        <Link href=\"/discover/movies/genres\" className=\"slider-title\">\n          <span>{intl.formatMessage(messages.moviegenres)}</span>\n          <ArrowRightCircleIcon />\n        </Link>\n      </div>\n      <Slider\n        sliderKey=\"movie-genres\"\n        isLoading={!data && !error}\n        isEmpty={false}\n        items={(data ?? []).map((genre, index) => (\n          <GenreCard\n            key={`genre-${genre.id}-${index}`}\n            name={genre.name}\n            image={`https://image.tmdb.org/t/p/w1280_filter(duotone,${\n              genreColorMap[genre.id] ?? genreColorMap[0]\n            })${genre.backdrops[4]}`}\n            url={`/discover/movies?genre=${genre.id}`}\n          />\n        ))}\n        placeholder={<GenreCard.Placeholder />}\n        emptyMessage=\"\"\n      />\n    </>\n  );\n};\n\nexport default React.memo(MovieGenreSlider);\n"
  },
  {
    "path": "src/components/Discover/NetworkSlider/index.tsx",
    "content": "import CompanyCard from '@app/components/CompanyCard';\nimport Slider from '@app/components/Slider';\nimport defineMessages from '@app/utils/defineMessages';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.NetworkSlider', {\n  networks: 'Networks',\n});\n\ninterface Network {\n  name: string;\n  image: string;\n  url: string;\n}\n\nconst networks: Network[] = [\n  {\n    name: 'Netflix',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/wwemzKWzjKYJFfCeiB57q3r4Bcm.png',\n    url: '/discover/tv/network/213',\n  },\n  {\n    name: 'Disney+',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/gJ8VX6JSu3ciXHuC2dDGAo2lvwM.png',\n    url: '/discover/tv/network/2739',\n  },\n  {\n    name: 'Prime Video',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ifhbNuuVnlwYy5oXA5VIb2YR8AZ.png',\n    url: '/discover/tv/network/1024',\n  },\n  {\n    name: 'Apple TV+',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/4KAy34EHvRM25Ih8wb82AuGU7zJ.png',\n    url: '/discover/tv/network/2552',\n  },\n  {\n    name: 'Hulu',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/pqUTCleNUiTLAVlelGxUgWn1ELh.png',\n    url: '/discover/tv/network/453',\n  },\n  {\n    name: 'HBO',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/tuomPhY2UtuPTqqFnKMVHvSb724.png',\n    url: '/discover/tv/network/49',\n  },\n  {\n    name: 'Discovery+',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/1D1bS3Dyw4ScYnFWTlBOvJXC3nb.png',\n    url: '/discover/tv/network/4353',\n  },\n  {\n    name: 'ABC',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ndAvF4JLsliGreX87jAc9GdjmJY.png',\n    url: '/discover/tv/network/2',\n  },\n  {\n    name: 'FOX',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/1DSpHrWyOORkL9N2QHX7Adt31mQ.png',\n    url: '/discover/tv/network/19',\n  },\n  {\n    name: 'Cinemax',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/6mSHSquNpfLgDdv6VnOOvC5Uz2h.png',\n    url: '/discover/tv/network/359',\n  },\n  {\n    name: 'AMC',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/pmvRmATOCaDykE6JrVoeYxlFHw3.png',\n    url: '/discover/tv/network/174',\n  },\n  {\n    name: 'Showtime',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/Allse9kbjiP6ExaQrnSpIhkurEi.png',\n    url: '/discover/tv/network/67',\n  },\n  {\n    name: 'Starz',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/8GJjw3HHsAJYwIWKIPBPfqMxlEa.png',\n    url: '/discover/tv/network/318',\n  },\n  {\n    name: 'The CW',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ge9hzeaU7nMtQ4PjkFlc68dGAJ9.png',\n    url: '/discover/tv/network/71',\n  },\n  {\n    name: 'NBC',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/o3OedEP0f9mfZr33jz2BfXOUK5.png',\n    url: '/discover/tv/network/6',\n  },\n  {\n    name: 'CBS',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/nm8d7P7MJNiBLdgIzUK0gkuEA4r.png',\n    url: '/discover/tv/network/16',\n  },\n  {\n    name: 'Paramount+',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/fi83B1oztoS47xxcemFdPMhIzK.png',\n    url: '/discover/tv/network/4330',\n  },\n  {\n    name: 'BBC One',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/mVn7xESaTNmjBUyUtGNvDQd3CT1.png',\n    url: '/discover/tv/network/4',\n  },\n  {\n    name: 'Cartoon Network',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/c5OC6oVCg6QP4eqzW6XIq17CQjI.png',\n    url: '/discover/tv/network/56',\n  },\n  {\n    name: 'Adult Swim',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/9AKyspxVzywuaMuZ1Bvilu8sXly.png',\n    url: '/discover/tv/network/80',\n  },\n  {\n    name: 'Nickelodeon',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ikZXxg6GnwpzqiZbRPhJGaZapqB.png',\n    url: '/discover/tv/network/13',\n  },\n  {\n    name: 'Peacock',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/gIAcGTjKKr0KOHL5s4O36roJ8p7.png',\n    url: '/discover/tv/network/3353',\n  },\n];\n\nconst NetworkSlider = () => {\n  const intl = useIntl();\n\n  return (\n    <>\n      <div className=\"slider-header\">\n        <div className=\"slider-title\">\n          <span>{intl.formatMessage(messages.networks)}</span>\n        </div>\n      </div>\n      <Slider\n        sliderKey=\"networks\"\n        isLoading={false}\n        isEmpty={false}\n        items={networks.map((network, index) => (\n          <CompanyCard\n            key={`network-${index}`}\n            name={network.name}\n            image={network.image}\n            url={network.url}\n          />\n        ))}\n        emptyMessage=\"\"\n      />\n    </>\n  );\n};\n\nexport default NetworkSlider;\n"
  },
  {
    "path": "src/components/Discover/PlexWatchlistSlider/index.tsx",
    "content": "import Slider from '@app/components/Slider';\nimport TmdbTitleCard from '@app/components/TitleCard/TmdbTitleCard';\nimport { useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowRightCircleIcon } from '@heroicons/react/24/outline';\nimport type { WatchlistItem } from '@server/interfaces/api/discoverInterfaces';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Discover.PlexWatchlistSlider', {\n  plexwatchlist: 'Your Watchlist',\n  emptywatchlist:\n    'Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.',\n});\n\nconst PlexWatchlistSlider = () => {\n  const intl = useIntl();\n  const { user } = useUser();\n\n  const { data: watchlistItems, error: watchlistError } = useSWR<{\n    page: number;\n    totalPages: number;\n    totalResults: number;\n    results: WatchlistItem[];\n  }>('/api/v1/discover/watchlist', {\n    revalidateOnMount: true,\n  });\n\n  if (\n    (watchlistItems &&\n      watchlistItems.results.length === 0 &&\n      !user?.settings?.watchlistSyncMovies &&\n      !user?.settings?.watchlistSyncTv) ||\n    watchlistError\n  ) {\n    return null;\n  }\n\n  return (\n    <>\n      <div className=\"slider-header\">\n        <Link href=\"/discover/watchlist\" className=\"slider-title\">\n          <span>{intl.formatMessage(messages.plexwatchlist)}</span>\n          <ArrowRightCircleIcon />\n        </Link>\n      </div>\n      <Slider\n        sliderKey=\"watchlist\"\n        isLoading={!watchlistItems}\n        isEmpty={!!watchlistItems && watchlistItems.results.length === 0}\n        emptyMessage={intl.formatMessage(messages.emptywatchlist, {\n          PlexWatchlistSupportLink: (msg: React.ReactNode) => (\n            <a\n              href=\"https://support.plex.tv/articles/universal-watchlist/\"\n              className=\"text-white transition duration-300 hover:underline\"\n              target=\"_blank\"\n              rel=\"noreferrer\"\n            >\n              {msg}\n            </a>\n          ),\n        })}\n        items={watchlistItems?.results.map((item) => (\n          <TmdbTitleCard\n            id={item.tmdbId}\n            key={`watchlist-slider-item-${item.ratingKey}`}\n            tmdbId={item.tmdbId}\n            type={item.mediaType}\n            isAddedToWatchlist={true}\n          />\n        ))}\n      />\n    </>\n  );\n};\n\nexport default PlexWatchlistSlider;\n"
  },
  {
    "path": "src/components/Discover/RecentRequestsSlider/index.tsx",
    "content": "import { sliderTitles } from '@app/components/Discover/constants';\nimport RequestCard from '@app/components/RequestCard';\nimport Slider from '@app/components/Slider';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport {\n  ArrowRightCircleIcon,\n  ExclamationTriangleIcon,\n} from '@heroicons/react/24/outline';\nimport type { RequestResultsResponse } from '@server/interfaces/api/requestInterfaces';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Discover.RecentRequestsSlider', {\n  unableToConnect:\n    'Unable to connect to {services}. Some information may be unavailable.',\n});\n\nconst RecentRequestsSlider = () => {\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n  const { data: requests, error: requestError } =\n    useSWR<RequestResultsResponse>(\n      '/api/v1/request?filter=all&take=10&sort=modified&skip=0',\n      {\n        revalidateOnMount: true,\n      }\n    );\n\n  if (requests && requests.results.length === 0 && !requestError) {\n    return null;\n  }\n\n  const hasServiceErrors =\n    requests?.serviceErrors &&\n    (requests.serviceErrors.radarr.length > 0 ||\n      requests.serviceErrors.sonarr.length > 0);\n\n  return (\n    <>\n      <div className=\"slider-header\">\n        <Link href=\"/requests?filter=all\" className=\"slider-title\">\n          <span>{intl.formatMessage(sliderTitles.recentrequests)}</span>\n          <ArrowRightCircleIcon />\n        </Link>\n      </div>\n\n      {hasServiceErrors &&\n        (hasPermission(Permission.MANAGE_REQUESTS) ||\n          hasPermission(Permission.REQUEST_ADVANCED)) && (\n          <div className=\"service-error-banner\">\n            <ExclamationTriangleIcon className=\"h-5 w-5 flex-shrink-0\" />\n            <span>\n              {intl.formatMessage(messages.unableToConnect, {\n                services: [\n                  ...requests.serviceErrors.radarr.map((s) => s.name),\n                  ...requests.serviceErrors.sonarr.map((s) => s.name),\n                ].join(', '),\n              })}\n            </span>\n          </div>\n        )}\n\n      <Slider\n        sliderKey=\"requests\"\n        isLoading={!requests}\n        items={(requests?.results ?? []).map((request) => (\n          <RequestCard\n            key={`request-slider-item-${request.id}`}\n            request={request}\n          />\n        ))}\n        placeholder={<RequestCard.Placeholder />}\n      />\n    </>\n  );\n};\n\nexport default RecentRequestsSlider;\n"
  },
  {
    "path": "src/components/Discover/RecentlyAddedSlider/index.tsx",
    "content": "import Slider from '@app/components/Slider';\nimport TmdbTitleCard from '@app/components/TitleCard/TmdbTitleCard';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { MediaResultsResponse } from '@server/interfaces/api/mediaInterfaces';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Discover.RecentlyAddedSlider', {\n  recentlyAdded: 'Recently Added',\n});\n\nconst RecentlyAddedSlider = () => {\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n  const { data: media, error: mediaError } = useSWR<MediaResultsResponse>(\n    '/api/v1/media?filter=allavailable&take=20&sort=mediaAdded',\n    { revalidateOnMount: true }\n  );\n\n  if (\n    (media && !media.results.length && !mediaError) ||\n    !hasPermission([Permission.MANAGE_REQUESTS, Permission.RECENT_VIEW], {\n      type: 'or',\n    })\n  ) {\n    return null;\n  }\n\n  return (\n    <>\n      <div className=\"slider-header\">\n        <div className=\"slider-title\">\n          <span>{intl.formatMessage(messages.recentlyAdded)}</span>\n        </div>\n      </div>\n      <Slider\n        sliderKey=\"media\"\n        isLoading={!media}\n        items={(media?.results ?? []).map((item) => (\n          <TmdbTitleCard\n            key={`media-slider-item-${item.id}`}\n            id={item.id}\n            tmdbId={item.tmdbId}\n            tvdbId={item.tvdbId}\n            type={item.mediaType}\n          />\n        ))}\n      />\n    </>\n  );\n};\n\nexport default RecentlyAddedSlider;\n"
  },
  {
    "path": "src/components/Discover/StudioSlider/index.tsx",
    "content": "import CompanyCard from '@app/components/CompanyCard';\nimport Slider from '@app/components/Slider';\nimport defineMessages from '@app/utils/defineMessages';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover.StudioSlider', {\n  studios: 'Studios',\n});\n\ninterface Studio {\n  name: string;\n  image: string;\n  url: string;\n}\n\nconst studios: Studio[] = [\n  {\n    name: 'Disney',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/wdrCwmRnLFJhEoH8GSfymY85KHT.png',\n    url: '/discover/movies/studio/2',\n  },\n  {\n    name: '20th Century Studios',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/h0rjX5vjW5r8yEnUBStFarjcLT4.png',\n    url: '/discover/movies/studio/127928',\n  },\n  {\n    name: 'Sony Pictures',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/GagSvqWlyPdkFHMfQ3pNq6ix9P.png',\n    url: '/discover/movies/studio/34',\n  },\n  {\n    name: 'Warner Bros. Pictures',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ky0xOc5OrhzkZ1N6KyUxacfQsCk.png',\n    url: '/discover/movies/studio/174',\n  },\n  {\n    name: 'Universal',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/8lvHyhjr8oUKOOy2dKXoALWKdp0.png',\n    url: '/discover/movies/studio/33',\n  },\n  {\n    name: 'Paramount',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/fycMZt242LVjagMByZOLUGbCvv3.png',\n    url: '/discover/movies/studio/4',\n  },\n  {\n    name: 'Pixar',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/1TjvGVDMYsj6JBxOAkUHpPEwLf7.png',\n    url: '/discover/movies/studio/3',\n  },\n  {\n    name: 'Dreamworks',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/kP7t6RwGz2AvvTkvnI1uteEwHet.png',\n    url: '/discover/movies/studio/521',\n  },\n  {\n    name: 'Marvel Studios',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/hUzeosd33nzE5MCNsZxCGEKTXaQ.png',\n    url: '/discover/movies/studio/420',\n  },\n  {\n    name: 'DC',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/2Tc1P3Ac8M479naPp1kYT3izLS5.png',\n    url: '/discover/movies/studio/9993',\n  },\n  {\n    name: 'A24',\n    image:\n      'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/1ZXsGaFPgrgS6ZZGS37AqD5uU12.png',\n    url: '/discover/movies/studio/41077',\n  },\n];\n\nconst StudioSlider = () => {\n  const intl = useIntl();\n\n  return (\n    <>\n      <div className=\"slider-header\">\n        <div className=\"slider-title\">\n          <span>{intl.formatMessage(messages.studios)}</span>\n        </div>\n      </div>\n      <Slider\n        sliderKey=\"studios\"\n        isLoading={false}\n        isEmpty={false}\n        items={studios.map((studio, index) => (\n          <CompanyCard\n            key={`studio-${index}`}\n            name={studio.name}\n            image={studio.image}\n            url={studio.url}\n          />\n        ))}\n        emptyMessage=\"\"\n      />\n    </>\n  );\n};\n\nexport default StudioSlider;\n"
  },
  {
    "path": "src/components/Discover/Trending.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { CircleStackIcon, FunnelIcon } from '@heroicons/react/24/solid';\nimport type {\n  MovieResult,\n  PersonResult,\n  TvResult,\n} from '@server/models/Search';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover', {\n  trending: 'Trending',\n  timeWindowDay: 'Daily',\n  timeWindowWeek: 'Weekly',\n});\n\ntype MediaType = 'all' | 'movie' | 'tv';\n\ntype TimeWindow = 'day' | 'week';\n\nconst Trending = () => {\n  const intl = useIntl();\n  const [currentMediaType, setCurrentMediaType] = useState<MediaType>('all');\n  const [currentTimeWindow, setCurrentTimeWindow] = useState<TimeWindow>('day');\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<MovieResult | TvResult | PersonResult>(\n    '/api/v1/discover/trending',\n    { mediaType: currentMediaType, timeWindow: currentTimeWindow }\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(messages.trending)} />\n      <div className=\"mb-5 mt-1 flex flex-col justify-between lg:flex-row lg:items-end\">\n        <Header>{intl.formatMessage(messages.trending)}</Header>\n        <div className=\"mt-2 flex flex-grow flex-col sm:flex-row lg:flex-grow-0\">\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n              <CircleStackIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"mediaType\"\n              name=\"mediaType\"\n              onChange={(e) => setCurrentMediaType(e.target.value as MediaType)}\n              value={currentMediaType}\n              className=\"rounded-r-only\"\n            >\n              <option value=\"all\">\n                {intl.formatMessage(globalMessages.all)}\n              </option>\n              <option value=\"movie\">\n                {intl.formatMessage(globalMessages.movies)}\n              </option>\n              <option value=\"tv\">\n                {intl.formatMessage(globalMessages.tvshows)}\n              </option>\n            </select>\n          </div>\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n              <FunnelIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"timeWindow\"\n              name=\"timeWindow\"\n              onChange={(e) =>\n                setCurrentTimeWindow(e.target.value as TimeWindow)\n              }\n              value={currentTimeWindow}\n              className=\"rounded-r-only\"\n            >\n              <option value=\"day\">\n                {intl.formatMessage(messages.timeWindowDay)}\n              </option>\n              <option value=\"week\">\n                {intl.formatMessage(messages.timeWindowWeek)}\n              </option>\n            </select>\n          </div>\n        </div>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default Trending;\n"
  },
  {
    "path": "src/components/Discover/TvGenreList/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport { genreColorMap } from '@app/components/Discover/constants';\nimport GenreCard from '@app/components/GenreCard';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { GenreSliderItem } from '@server/interfaces/api/discoverInterfaces';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Discover.TvGenreList', {\n  seriesgenres: 'Series Genres',\n});\n\nconst TvGenreList = () => {\n  const intl = useIntl();\n  const { data, error } = useSWR<GenreSliderItem[]>(\n    `/api/v1/discover/genreslider/tv`\n  );\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(messages.seriesgenres)} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{intl.formatMessage(messages.seriesgenres)}</Header>\n      </div>\n      <ul className=\"cards-horizontal\">\n        {data.map((genre, index) => (\n          <li key={`genre-${genre.id}-${index}`}>\n            <GenreCard\n              name={genre.name}\n              image={`https://image.tmdb.org/t/p/w1280_filter(duotone,${\n                genreColorMap[genre.id] ?? genreColorMap[0]\n              })${genre.backdrops[4]}`}\n              url={`/discover/tv/genre/${genre.id}`}\n              canExpand\n            />\n          </li>\n        ))}\n      </ul>\n    </>\n  );\n};\n\nexport default TvGenreList;\n"
  },
  {
    "path": "src/components/Discover/TvGenreSlider/index.tsx",
    "content": "import { genreColorMap } from '@app/components/Discover/constants';\nimport GenreCard from '@app/components/GenreCard';\nimport Slider from '@app/components/Slider';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowRightCircleIcon } from '@heroicons/react/24/outline';\nimport type { GenreSliderItem } from '@server/interfaces/api/discoverInterfaces';\nimport Link from 'next/link';\nimport React from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Discover.TvGenreSlider', {\n  tvgenres: 'Series Genres',\n});\n\nconst TvGenreSlider = () => {\n  const intl = useIntl();\n  const { data, error } = useSWR<GenreSliderItem[]>(\n    `/api/v1/discover/genreslider/tv`,\n    {\n      refreshInterval: 0,\n      revalidateOnFocus: false,\n    }\n  );\n\n  return (\n    <>\n      <div className=\"slider-header\">\n        <Link href=\"/discover/tv/genres\" className=\"slider-title\">\n          <span>{intl.formatMessage(messages.tvgenres)}</span>\n          <ArrowRightCircleIcon />\n        </Link>\n      </div>\n      <Slider\n        sliderKey=\"tv-genres\"\n        isLoading={!data && !error}\n        isEmpty={false}\n        items={(data ?? []).map((genre, index) => (\n          <GenreCard\n            key={`genre-tv-${genre.id}-${index}`}\n            name={genre.name}\n            image={`https://image.tmdb.org/t/p/w1280_filter(duotone,${\n              genreColorMap[genre.id] ?? genreColorMap[0]\n            })${genre.backdrops[4]}`}\n            url={`/discover/tv?genre=${genre.id}`}\n          />\n        ))}\n        placeholder={<GenreCard.Placeholder />}\n        emptyMessage=\"\"\n      />\n    </>\n  );\n};\n\nexport default React.memo(TvGenreSlider);\n"
  },
  {
    "path": "src/components/Discover/Upcoming.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { MovieResult } from '@server/models/Search';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Discover', {\n  upcomingmovies: 'Upcoming Movies',\n});\n\nconst UpcomingMovies = () => {\n  const intl = useIntl();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<MovieResult>('/api/v1/discover/movies/upcoming');\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(messages.upcomingmovies)} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{intl.formatMessage(messages.upcomingmovies)}</Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default UpcomingMovies;\n"
  },
  {
    "path": "src/components/Discover/constants.ts",
    "content": "import defineMessages from '@app/utils/defineMessages';\nimport type { ParsedUrlQuery } from 'querystring';\nimport { z } from 'zod';\n\ntype AvailableColors =\n  | 'black'\n  | 'red'\n  | 'darkred'\n  | 'blue'\n  | 'lightblue'\n  | 'darkblue'\n  | 'orange'\n  | 'darkorange'\n  | 'green'\n  | 'lightgreen'\n  | 'purple'\n  | 'darkpurple'\n  | 'yellow'\n  | 'pink';\n\nexport const colorTones: Record<AvailableColors, [string, string]> = {\n  red: ['991B1B', 'FCA5A5'],\n  darkred: ['1F2937', 'F87171'],\n  blue: ['032541', '01b4e4'],\n  lightblue: ['1F2937', '60A5FA'],\n  darkblue: ['1F2937', '2864d2'],\n  orange: ['92400E', 'FCD34D'],\n  lightgreen: ['065F46', '6EE7B7'],\n  green: ['087d29', '21cb51'],\n  purple: ['5B21B6', 'C4B5FD'],\n  yellow: ['777e0d', 'e4ed55'],\n  darkorange: ['552c01', 'd47c1d'],\n  black: ['1F2937', 'D1D5DB'],\n  pink: ['9D174D', 'F9A8D4'],\n  darkpurple: ['480c8b', 'a96bef'],\n};\n\nexport const genreColorMap: Record<number, [string, string]> = {\n  0: colorTones.black,\n  28: colorTones.red, // Action\n  12: colorTones.darkpurple, // Adventure\n  16: colorTones.blue, // Animation\n  35: colorTones.orange, // Comedy\n  80: colorTones.darkblue, // Crime\n  99: colorTones.lightgreen, // Documentary\n  18: colorTones.pink, // Drama\n  10751: colorTones.yellow, // Family\n  14: colorTones.lightblue, // Fantasy\n  36: colorTones.orange, // History\n  27: colorTones.black, // Horror\n  10402: colorTones.blue, // Music\n  9648: colorTones.purple, // Mystery\n  10749: colorTones.pink, // Romance\n  878: colorTones.lightblue, // Science Fiction\n  10770: colorTones.red, // TV Movie\n  53: colorTones.black, // Thriller\n  10752: colorTones.darkred, // War\n  37: colorTones.orange, // Western\n  10759: colorTones.darkpurple, // Action & Adventure\n  10762: colorTones.blue, // Kids\n  10763: colorTones.black, // News\n  10764: colorTones.darkorange, // Reality\n  10765: colorTones.lightblue, // Sci-Fi & Fantasy\n  10766: colorTones.pink, // Soap\n  10767: colorTones.lightgreen, // Talk\n  10768: colorTones.darkred, // War & Politics\n};\n\nexport const sliderTitles = defineMessages('components.Discover', {\n  recentrequests: 'Recent Requests',\n  popularmovies: 'Popular Movies',\n  populartv: 'Popular Series',\n  upcomingtv: 'Upcoming Series',\n  recentlyAdded: 'Recently Added',\n  upcoming: 'Upcoming Movies',\n  trending: 'Trending',\n  plexwatchlist: 'Your Watchlist',\n  moviegenres: 'Movie Genres',\n  tvgenres: 'Series Genres',\n  studios: 'Studios',\n  networks: 'Networks',\n  tmdbmoviekeyword: 'TMDB Movie Keyword',\n  tmdbtvkeyword: 'TMDB Series Keyword',\n  tmdbmoviegenre: 'TMDB Movie Genre',\n  tmdbtvgenre: 'TMDB Series Genre',\n  tmdbnetwork: 'TMDB Network',\n  tmdbstudio: 'TMDB Studio',\n  tmdbsearch: 'TMDB Search',\n  tmdbmoviestreamingservices: 'TMDB Movie Streaming Services',\n  tmdbtvstreamingservices: 'TMDB TV Streaming Services',\n});\n\nexport const QueryFilterOptions = z.object({\n  sortBy: z.string().optional(),\n  primaryReleaseDateGte: z.string().optional(),\n  primaryReleaseDateLte: z.string().optional(),\n  firstAirDateGte: z.string().optional(),\n  firstAirDateLte: z.string().optional(),\n  studio: z.string().optional(),\n  genre: z.string().optional(),\n  keywords: z.string().optional(),\n  excludeKeywords: z.string().optional(),\n  language: z.string().optional(),\n  withRuntimeGte: z.string().optional(),\n  withRuntimeLte: z.string().optional(),\n  voteAverageGte: z.string().optional(),\n  voteAverageLte: z.string().optional(),\n  voteCountLte: z.string().optional(),\n  voteCountGte: z.string().optional(),\n  watchRegion: z.string().optional(),\n  watchProviders: z.string().optional(),\n  status: z.string().optional(),\n  certification: z.string().optional(),\n  certificationGte: z.string().optional(),\n  certificationLte: z.string().optional(),\n  certificationCountry: z.string().optional(),\n  certificationMode: z.enum(['exact', 'range']).optional(),\n});\n\nexport type FilterOptions = z.infer<typeof QueryFilterOptions>;\n\nexport const prepareFilterValues = (\n  inputValues: ParsedUrlQuery\n): FilterOptions => {\n  const filterValues: FilterOptions = {};\n\n  const values = QueryFilterOptions.parse(inputValues);\n\n  if (values.sortBy) {\n    filterValues.sortBy = values.sortBy;\n  }\n\n  if (values.primaryReleaseDateGte) {\n    filterValues.primaryReleaseDateGte = values.primaryReleaseDateGte;\n  }\n\n  if (values.primaryReleaseDateLte) {\n    filterValues.primaryReleaseDateLte = values.primaryReleaseDateLte;\n  }\n\n  if (values.firstAirDateGte) {\n    filterValues.firstAirDateGte = values.firstAirDateGte;\n  }\n\n  if (values.firstAirDateLte) {\n    filterValues.firstAirDateLte = values.firstAirDateLte;\n  }\n\n  if (values.studio) {\n    filterValues.studio = values.studio;\n  }\n\n  if (values.genre) {\n    filterValues.genre = values.genre;\n  }\n\n  if (values.status) {\n    filterValues.status = values.status;\n  }\n\n  if (values.keywords) {\n    filterValues.keywords = values.keywords;\n  }\n\n  if (values.excludeKeywords) {\n    filterValues.excludeKeywords = values.excludeKeywords;\n  }\n\n  if (values.language) {\n    filterValues.language = values.language;\n  }\n\n  if (values.withRuntimeGte) {\n    filterValues.withRuntimeGte = values.withRuntimeGte;\n  }\n\n  if (values.withRuntimeLte) {\n    filterValues.withRuntimeLte = values.withRuntimeLte;\n  }\n\n  if (values.voteAverageGte) {\n    filterValues.voteAverageGte = values.voteAverageGte;\n  }\n\n  if (values.voteAverageLte) {\n    filterValues.voteAverageLte = values.voteAverageLte;\n  }\n\n  if (values.voteCountGte) {\n    filterValues.voteCountGte = values.voteCountGte;\n  }\n\n  if (values.voteCountLte) {\n    filterValues.voteCountLte = values.voteCountLte;\n  }\n\n  if (values.watchProviders) {\n    filterValues.watchProviders = values.watchProviders;\n  }\n\n  if (values.watchRegion) {\n    filterValues.watchRegion = values.watchRegion;\n  }\n\n  if (values.certification) {\n    filterValues.certification = values.certification;\n  }\n\n  if (values.certificationGte) {\n    filterValues.certificationGte = values.certificationGte;\n  }\n\n  if (values.certificationLte) {\n    filterValues.certificationLte = values.certificationLte;\n  }\n\n  if (values.certificationCountry) {\n    filterValues.certificationCountry = values.certificationCountry;\n  }\n\n  if (values.certificationMode) {\n    filterValues.certificationMode = values.certificationMode;\n  } else if (values.certification) {\n    filterValues.certificationMode = 'exact';\n  } else if (values.certificationGte || values.certificationLte) {\n    filterValues.certificationMode = 'range';\n  }\n\n  return filterValues;\n};\n\nexport const countActiveFilters = (filterValues: FilterOptions): number => {\n  let totalCount = 0;\n  const clonedFilters = Object.assign({}, filterValues);\n\n  if (clonedFilters.voteAverageGte || filterValues.voteAverageLte) {\n    totalCount += 1;\n    delete clonedFilters.voteAverageGte;\n    delete clonedFilters.voteAverageLte;\n  }\n\n  if (clonedFilters.voteCountGte || filterValues.voteCountLte) {\n    totalCount += 1;\n    delete clonedFilters.voteCountGte;\n    delete clonedFilters.voteCountLte;\n  }\n\n  if (clonedFilters.withRuntimeGte || filterValues.withRuntimeLte) {\n    totalCount += 1;\n    delete clonedFilters.withRuntimeGte;\n    delete clonedFilters.withRuntimeLte;\n  }\n\n  if (clonedFilters.watchProviders) {\n    totalCount += 1;\n    delete clonedFilters.watchProviders;\n    delete clonedFilters.watchRegion;\n  }\n\n  if (\n    clonedFilters.certification ||\n    clonedFilters.certificationGte ||\n    clonedFilters.certificationLte ||\n    clonedFilters.certificationCountry\n  ) {\n    totalCount += 1;\n    delete clonedFilters.certification;\n    delete clonedFilters.certificationGte;\n    delete clonedFilters.certificationLte;\n    delete clonedFilters.certificationCountry;\n  }\n\n  delete clonedFilters.certificationMode;\n  totalCount += Object.keys(clonedFilters).length;\n\n  return totalCount;\n};\n"
  },
  {
    "path": "src/components/Discover/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport ConfirmButton from '@app/components/Common/ConfirmButton';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport { sliderTitles } from '@app/components/Discover/constants';\nimport CreateSlider from '@app/components/Discover/CreateSlider';\nimport DiscoverSliderEdit from '@app/components/Discover/DiscoverSliderEdit';\nimport MovieGenreSlider from '@app/components/Discover/MovieGenreSlider';\nimport NetworkSlider from '@app/components/Discover/NetworkSlider';\nimport PlexWatchlistSlider from '@app/components/Discover/PlexWatchlistSlider';\nimport RecentlyAddedSlider from '@app/components/Discover/RecentlyAddedSlider';\nimport RecentRequestsSlider from '@app/components/Discover/RecentRequestsSlider';\nimport StudioSlider from '@app/components/Discover/StudioSlider';\nimport TvGenreSlider from '@app/components/Discover/TvGenreSlider';\nimport MediaSlider from '@app/components/MediaSlider';\nimport { encodeURIExtraParams } from '@app/hooks/useDiscover';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport {\n  ArrowDownOnSquareIcon,\n  ArrowPathIcon,\n  ArrowUturnLeftIcon,\n  PencilIcon,\n  PlusIcon,\n} from '@heroicons/react/24/solid';\nimport { DiscoverSliderType } from '@server/constants/discover';\nimport type DiscoverSlider from '@server/entity/DiscoverSlider';\nimport axios from 'axios';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Discover', {\n  discover: 'Discover',\n  emptywatchlist:\n    'Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.',\n  resettodefault: 'Reset to Default',\n  resetwarning:\n    'Reset all sliders to default. This will also delete any custom sliders!',\n  updatesuccess: 'Updated discover customization settings.',\n  updatefailed:\n    'Something went wrong updating the discover customization settings.',\n  resetsuccess: 'Sucessfully reset discover customization settings.',\n  resetfailed:\n    'Something went wrong resetting the discover customization settings.',\n  customizediscover: 'Customize Discover',\n  stopediting: 'Stop Editing',\n  createnewslider: 'Create New Slider',\n});\n\nconst Discover = () => {\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n  const { addToast } = useToasts();\n  const {\n    data: discoverData,\n    error: discoverError,\n    mutate,\n  } = useSWR<DiscoverSlider[]>('/api/v1/settings/discover');\n  const [sliders, setSliders] = useState<Partial<DiscoverSlider>[]>([]);\n  const [isEditing, setIsEditing] = useState(false);\n\n  // We need to sync the state here so that we can modify the changes locally without commiting\n  // anything to the server until the user decides to save the changes\n  useEffect(() => {\n    if (discoverData && !isEditing) {\n      setSliders(discoverData);\n    }\n  }, [discoverData, isEditing]);\n\n  const hasChanged = () => !Object.is(discoverData, sliders);\n\n  const updateSliders = async () => {\n    try {\n      await axios.post('/api/v1/settings/discover', sliders);\n\n      addToast(intl.formatMessage(messages.updatesuccess), {\n        appearance: 'success',\n        autoDismiss: true,\n      });\n      setIsEditing(false);\n      mutate();\n    } catch {\n      addToast(intl.formatMessage(messages.updatefailed), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n  };\n\n  const resetSliders = async () => {\n    try {\n      await axios.get('/api/v1/settings/discover/reset');\n\n      addToast(intl.formatMessage(messages.resetsuccess), {\n        appearance: 'success',\n        autoDismiss: true,\n      });\n      setIsEditing(false);\n      mutate();\n    } catch {\n      addToast(intl.formatMessage(messages.resetfailed), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n  };\n\n  const now = new Date();\n  const offset = now.getTimezoneOffset();\n  const upcomingDate = new Date(now.getTime() - offset * 60 * 1000)\n    .toISOString()\n    .split('T')[0];\n\n  if (!discoverData && !discoverError) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(messages.discover)} />\n      {hasPermission(Permission.ADMIN) && (\n        <>\n          {isEditing && (\n            <div className=\"my-6 rounded-lg bg-gray-800\">\n              <div className=\"flex items-center space-x-2 rounded-t-lg border-l border-r border-t border-gray-800 bg-gray-900 p-4 text-lg font-semibold text-gray-400\">\n                <PlusIcon className=\"w-6\" />\n                <span data-testid=\"create-slider-header\">\n                  {intl.formatMessage(messages.createnewslider)}\n                </span>\n              </div>\n              <div className=\"p-4\">\n                <CreateSlider\n                  onCreate={async () => {\n                    const newSliders = await mutate();\n\n                    if (newSliders) {\n                      setSliders(newSliders);\n                    }\n                  }}\n                />\n              </div>\n            </div>\n          )}\n          <Transition\n            show={!isEditing}\n            enter=\"transition-opacity duration-300\"\n            enterFrom=\"opacity-0\"\n            enterTo=\"opacity-100\"\n            leave=\"transition-opacity duration-300\"\n            leaveFrom=\"opacity-100\"\n            leaveTo=\"opacity-0\"\n            className=\"absolute-bottom-shift fixed right-6 z-50 flex items-center sm:bottom-8\"\n          >\n            <button\n              onClick={() => setIsEditing(true)}\n              data-testid=\"discover-start-editing\"\n              className=\"h-12 w-12 rounded-full border-2 border-gray-600 bg-gray-700/90 p-3 text-gray-400 shadow transition-all hover:bg-gray-700\"\n            >\n              <PencilIcon className=\"h-full w-full\" />\n            </button>\n          </Transition>\n          <Transition\n            show={isEditing}\n            enter=\"transition duration-300\"\n            enterFrom=\"opacity-0 translate-y-6\"\n            enterTo=\"opacity-100 translate-y-0\"\n            leave=\"transition duration-300\"\n            leaveFrom=\"opacity-100 translate-y-0\"\n            leaveTo=\"opacity-0 translate-y-6\"\n            className=\"safe-shift-edit-menu fixed left-0 right-0 z-50 flex flex-col items-center justify-end space-x-0 space-y-2 border-t border-gray-700 bg-gray-800/80 p-4 backdrop-blur sm:bottom-0 sm:flex-row sm:space-x-3 sm:space-y-0\"\n          >\n            <Button\n              buttonType=\"default\"\n              onClick={() => setIsEditing(false)}\n              className=\"w-full sm:w-auto\"\n            >\n              <ArrowUturnLeftIcon />\n              <span>{intl.formatMessage(messages.stopediting)}</span>\n            </Button>\n            <Tooltip content={intl.formatMessage(messages.resetwarning)}>\n              <ConfirmButton\n                onClick={() => resetSliders()}\n                confirmText={intl.formatMessage(globalMessages.areyousure)}\n                className=\"w-full sm:w-auto\"\n              >\n                <ArrowPathIcon />\n                <span>{intl.formatMessage(messages.resettodefault)}</span>\n              </ConfirmButton>\n            </Tooltip>\n            <Button\n              buttonType=\"primary\"\n              type=\"submit\"\n              disabled={!hasChanged()}\n              onClick={() => updateSliders()}\n              data-testid=\"discover-customize-submit\"\n              className=\"w-full sm:w-auto\"\n            >\n              <ArrowDownOnSquareIcon />\n              <span>{intl.formatMessage(globalMessages.save)}</span>\n            </Button>\n          </Transition>\n        </>\n      )}\n      {(isEditing ? sliders : discoverData)?.map((slider, index) => {\n        let sliderComponent: React.ReactNode;\n\n        switch (slider.type) {\n          case DiscoverSliderType.RECENTLY_ADDED:\n            sliderComponent = <RecentlyAddedSlider />;\n            break;\n          case DiscoverSliderType.RECENT_REQUESTS:\n            sliderComponent = <RecentRequestsSlider />;\n            break;\n          case DiscoverSliderType.PLEX_WATCHLIST:\n            sliderComponent = <PlexWatchlistSlider />;\n            break;\n          case DiscoverSliderType.TRENDING:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey=\"trending\"\n                title={intl.formatMessage(sliderTitles.trending)}\n                url=\"/api/v1/discover/trending\"\n                linkUrl=\"/discover/trending\"\n              />\n            );\n            break;\n          case DiscoverSliderType.POPULAR_MOVIES:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey=\"popular-movies\"\n                title={intl.formatMessage(sliderTitles.popularmovies)}\n                url=\"/api/v1/discover/movies\"\n                linkUrl=\"/discover/movies\"\n              />\n            );\n            break;\n          case DiscoverSliderType.MOVIE_GENRES:\n            sliderComponent = <MovieGenreSlider />;\n            break;\n          case DiscoverSliderType.UPCOMING_MOVIES:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey=\"upcoming\"\n                title={intl.formatMessage(sliderTitles.upcoming)}\n                linkUrl={`/discover/movies?primaryReleaseDateGte=${upcomingDate}`}\n                url=\"/api/v1/discover/movies\"\n                extraParams={`primaryReleaseDateGte=${upcomingDate}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.STUDIOS:\n            sliderComponent = <StudioSlider />;\n            break;\n          case DiscoverSliderType.POPULAR_TV:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey=\"popular-tv\"\n                title={intl.formatMessage(sliderTitles.populartv)}\n                url=\"/api/v1/discover/tv\"\n                linkUrl=\"/discover/tv\"\n              />\n            );\n            break;\n          case DiscoverSliderType.TV_GENRES:\n            sliderComponent = <TvGenreSlider />;\n            break;\n          case DiscoverSliderType.UPCOMING_TV:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey=\"upcoming-tv\"\n                title={intl.formatMessage(sliderTitles.upcomingtv)}\n                linkUrl={`/discover/tv?firstAirDateGte=${upcomingDate}`}\n                url=\"/api/v1/discover/tv\"\n                extraParams={`firstAirDateGte=${upcomingDate}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.NETWORKS:\n            sliderComponent = <NetworkSlider />;\n            break;\n          case DiscoverSliderType.TMDB_MOVIE_KEYWORD:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey={`custom-slider-${slider.id}`}\n                title={slider.title ?? ''}\n                url=\"/api/v1/discover/movies\"\n                extraParams={\n                  slider.data\n                    ? `keywords=${encodeURIExtraParams(slider.data)}`\n                    : ''\n                }\n                linkUrl={`/discover/movies?keywords=${slider.data}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_TV_KEYWORD:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey={`custom-slider-${slider.id}`}\n                title={slider.title ?? ''}\n                url=\"/api/v1/discover/tv\"\n                extraParams={\n                  slider.data\n                    ? `keywords=${encodeURIExtraParams(slider.data)}`\n                    : ''\n                }\n                linkUrl={`/discover/tv?keywords=${slider.data}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_MOVIE_GENRE:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey={`custom-slider-${slider.id}`}\n                title={slider.title ?? ''}\n                url={`/api/v1/discover/movies`}\n                extraParams={`genre=${slider.data}`}\n                linkUrl={`/discover/movies?genre=${slider.data}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_TV_GENRE:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey={`custom-slider-${slider.id}`}\n                title={slider.title ?? ''}\n                url={`/api/v1/discover/tv`}\n                extraParams={`genre=${slider.data}`}\n                linkUrl={`/discover/tv?genre=${slider.data}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_STUDIO:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey={`custom-slider-${slider.id}`}\n                title={slider.title ?? ''}\n                url={`/api/v1/discover/movies/studio/${slider.data}`}\n                linkUrl={`/discover/movies/studio/${slider.data}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_NETWORK:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey={`custom-slider-${slider.id}`}\n                title={slider.title ?? ''}\n                url={`/api/v1/discover/tv/network/${slider.data}`}\n                linkUrl={`/discover/tv/network/${slider.data}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_SEARCH:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey={`custom-slider-${slider.id}`}\n                title={slider.title ?? ''}\n                url=\"/api/v1/search\"\n                extraParams={`query=${slider.data}`}\n                linkUrl={`/search?query=${slider.data}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_MOVIE_STREAMING_SERVICES:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey={`custom-slider-${slider.id}`}\n                title={slider.title ?? ''}\n                url=\"/api/v1/discover/movies\"\n                extraParams={`watchRegion=${\n                  slider.data?.split(',')[0]\n                }&watchProviders=${slider.data?.split(',')[1]}`}\n                linkUrl={`/discover/movies?watchRegion=${\n                  slider.data?.split(',')[0]\n                }&watchProviders=${slider.data?.split(',')[1]}`}\n              />\n            );\n            break;\n          case DiscoverSliderType.TMDB_TV_STREAMING_SERVICES:\n            sliderComponent = (\n              <MediaSlider\n                sliderKey={`custom-slider-${slider.id}`}\n                title={slider.title ?? ''}\n                url=\"/api/v1/discover/tv\"\n                extraParams={`watchRegion=${\n                  slider.data?.split(',')[0]\n                }&watchProviders=${slider.data?.split(',')[1]}`}\n                linkUrl={`/discover/tv?watchRegion=${\n                  slider.data?.split(',')[0]\n                }&watchProviders=${slider.data?.split(',')[1]}`}\n              />\n            );\n            break;\n        }\n\n        if (isEditing) {\n          return (\n            <DiscoverSliderEdit\n              key={`discover-slider-${slider.id}-edit`}\n              slider={slider}\n              onDelete={async () => {\n                const newSliders = await mutate();\n\n                if (newSliders) {\n                  setSliders(newSliders);\n                }\n              }}\n              onEnable={() => {\n                const tempSliders = sliders.slice();\n                tempSliders[index].enabled = !tempSliders[index].enabled;\n                setSliders(tempSliders);\n              }}\n              onPositionUpdate={(updatedItemId, position, hasClickedArrows) => {\n                const originalPosition = sliders.findIndex(\n                  (item) => item.id === updatedItemId\n                );\n                const originalItem = sliders[originalPosition];\n\n                const tempSliders = sliders.slice();\n\n                tempSliders.splice(originalPosition, 1);\n                if (hasClickedArrows) {\n                  tempSliders.splice(\n                    position === 'Above' ? index - 1 : index + 1,\n                    0,\n                    originalItem\n                  );\n                } else {\n                  tempSliders.splice(\n                    position === 'Above' && index > originalPosition\n                      ? Math.max(index - 1, 0)\n                      : index,\n                    0,\n                    originalItem\n                  );\n                }\n\n                setSliders(tempSliders);\n              }}\n              disableUpButton={index === 0}\n              disableDownButton={index === sliders.length - 1}\n            >\n              {sliderComponent}\n            </DiscoverSliderEdit>\n          );\n        }\n\n        if (!slider.enabled) {\n          return null;\n        }\n\n        return (\n          <div key={`discover-slider-${slider.id}`}>{sliderComponent}</div>\n        );\n      })}\n    </>\n  );\n};\n\nexport default Discover;\n"
  },
  {
    "path": "src/components/DownloadBlock/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { DownloadingItem } from '@server/lib/downloadtracker';\nimport { FormattedRelativeTime, useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.DownloadBlock', {\n  estimatedtime: 'Estimated {time}',\n  formattedTitle: '{title}: Season {seasonNumber} Episode {episodeNumber}',\n});\n\ninterface DownloadBlockProps {\n  downloadItem: DownloadingItem;\n  is4k?: boolean;\n  title?: string;\n}\n\nconst DownloadBlock = ({\n  downloadItem,\n  is4k = false,\n  title,\n}: DownloadBlockProps) => {\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n\n  return (\n    <div className=\"p-4\">\n      <div className=\"mb-2 w-56 truncate text-sm sm:w-80 md:w-full\">\n        {hasPermission(Permission.ADMIN)\n          ? downloadItem.title\n          : downloadItem.episode\n            ? intl.formatMessage(messages.formattedTitle, {\n                title,\n                seasonNumber: downloadItem?.episode?.seasonNumber,\n                episodeNumber: downloadItem?.episode?.episodeNumber,\n              })\n            : title}\n      </div>\n      <div className=\"relative mb-2 h-6 min-w-0 overflow-hidden rounded-full bg-gray-700\">\n        <div\n          className=\"h-8 bg-indigo-600 transition-all duration-200 ease-in-out\"\n          style={{\n            width: `${\n              downloadItem.size\n                ? Math.round(\n                    ((downloadItem.size - downloadItem.sizeLeft) /\n                      downloadItem.size) *\n                      100\n                  )\n                : 0\n            }%`,\n          }}\n        />\n        <div className=\"absolute inset-0 flex h-6 w-full items-center justify-center text-xs\">\n          <span>\n            {downloadItem.size\n              ? Math.round(\n                  ((downloadItem.size - downloadItem.sizeLeft) /\n                    downloadItem.size) *\n                    100\n                )\n              : 0}\n            %\n          </span>\n        </div>\n      </div>\n      <div className=\"flex items-center justify-between text-xs\">\n        <span>\n          {is4k && (\n            <Badge badgeType=\"warning\" className=\"mr-2\">\n              4K\n            </Badge>\n          )}\n          <Badge className=\"capitalize\">{downloadItem.status}</Badge>\n        </span>\n        <span>\n          {downloadItem.estimatedCompletionTime\n            ? intl.formatMessage(messages.estimatedtime, {\n                time: (\n                  <FormattedRelativeTime\n                    value={Math.floor(\n                      (new Date(\n                        downloadItem.estimatedCompletionTime\n                      ).getTime() -\n                        Date.now()) /\n                        1000\n                    )}\n                    updateIntervalInSeconds={1}\n                    numeric=\"auto\"\n                  />\n                ),\n              })\n            : ''}\n        </span>\n      </div>\n    </div>\n  );\n};\n\nexport default DownloadBlock;\n"
  },
  {
    "path": "src/components/ExternalLinkBlock/index.tsx",
    "content": "import EmbyLogo from '@app/assets/services/emby.svg';\nimport ImdbLogo from '@app/assets/services/imdb.svg';\nimport JellyfinLogo from '@app/assets/services/jellyfin.svg';\nimport LetterboxdLogo from '@app/assets/services/letterboxd.svg';\nimport PlexLogo from '@app/assets/services/plex.svg';\nimport RTLogo from '@app/assets/services/rt.svg';\nimport TmdbLogo from '@app/assets/services/tmdb.svg';\nimport TraktLogo from '@app/assets/services/trakt.svg';\nimport TvdbLogo from '@app/assets/services/tvdb.svg';\nimport useLocale from '@app/hooks/useLocale';\nimport useSettings from '@app/hooks/useSettings';\nimport { MediaType } from '@server/constants/media';\nimport { MediaServerType } from '@server/constants/server';\n\ninterface ExternalLinkBlockProps {\n  mediaType: 'movie' | 'tv';\n  tmdbId?: number;\n  tvdbId?: number;\n  imdbId?: string;\n  rtUrl?: string;\n  mediaUrl?: string;\n}\n\nconst ExternalLinkBlock = ({\n  mediaType,\n  tmdbId,\n  tvdbId,\n  imdbId,\n  rtUrl,\n  mediaUrl,\n}: ExternalLinkBlockProps) => {\n  const settings = useSettings();\n  const { locale } = useLocale();\n\n  return (\n    <div className=\"flex w-full items-center justify-center space-x-5\">\n      {mediaUrl && (\n        <a\n          href={mediaUrl}\n          className=\"w-12 opacity-50 transition duration-300 hover:opacity-100\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          {settings.currentSettings.mediaServerType === MediaServerType.PLEX ? (\n            <PlexLogo />\n          ) : settings.currentSettings.mediaServerType ===\n            MediaServerType.EMBY ? (\n            <EmbyLogo />\n          ) : (\n            <JellyfinLogo />\n          )}\n        </a>\n      )}\n      {tmdbId && (\n        <a\n          href={`https://www.themoviedb.org/${mediaType}/${tmdbId}?language=${locale}`}\n          className=\"w-8 opacity-50 transition duration-300 hover:opacity-100\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          <TmdbLogo />\n        </a>\n      )}\n      {tvdbId && mediaType === MediaType.TV && (\n        <a\n          href={`http://www.thetvdb.com/?tab=series&id=${tvdbId}`}\n          className=\"w-9 opacity-50 transition duration-300 hover:opacity-100\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          <TvdbLogo />\n        </a>\n      )}\n      {imdbId && (\n        <a\n          href={`https://www.imdb.com/title/${imdbId}`}\n          className=\"w-8 opacity-50 transition duration-300 hover:opacity-100\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          <ImdbLogo />\n        </a>\n      )}\n      {rtUrl && (\n        <a\n          href={rtUrl}\n          className=\"w-14 opacity-50 transition duration-300 hover:opacity-100\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          <RTLogo />\n        </a>\n      )}\n      {tmdbId && (\n        <a\n          href={`https://trakt.tv/search/tmdb/${tmdbId}?id_type=${\n            mediaType === 'movie' ? 'movie' : 'show'\n          }`}\n          className=\"w-8 opacity-50 transition duration-300 hover:opacity-100\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          <TraktLogo />\n        </a>\n      )}\n      {tmdbId && mediaType === MediaType.MOVIE && (\n        <a\n          href={`https://letterboxd.com/tmdb/${tmdbId}`}\n          className=\"w-8 opacity-50 transition duration-300 hover:opacity-100\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          <LetterboxdLogo />\n        </a>\n      )}\n    </div>\n  );\n};\n\nexport default ExternalLinkBlock;\n"
  },
  {
    "path": "src/components/GenreCard/index.tsx",
    "content": "import CachedImage from '@app/components/Common/CachedImage';\nimport { withProperties } from '@app/utils/typeHelpers';\nimport Link from 'next/link';\nimport { useState } from 'react';\n\ninterface GenreCardProps {\n  name: string;\n  image: string;\n  url: string;\n  canExpand?: boolean;\n}\n\nconst GenreCard = ({ image, url, name, canExpand = false }: GenreCardProps) => {\n  const [isHovered, setHovered] = useState(false);\n\n  return (\n    <Link\n      href={url}\n      className={`relative flex h-32 items-center justify-center sm:h-36 ${\n        canExpand ? 'w-full' : 'w-56 sm:w-72'\n      } transform-gpu cursor-pointer p-8 shadow ring-1 transition duration-300 ease-in-out ${\n        isHovered\n          ? 'scale-105 bg-gray-700/100 ring-gray-500'\n          : 'scale-100 bg-gray-800/80 ring-gray-700'\n      } overflow-hidden rounded-xl bg-cover bg-center`}\n      onMouseEnter={() => {\n        setHovered(true);\n      }}\n      onMouseLeave={() => setHovered(false)}\n      onKeyDown={(e) => {\n        if (e.key === 'Enter') {\n          setHovered(true);\n        }\n      }}\n      role=\"link\"\n      tabIndex={0}\n    >\n      <CachedImage\n        type=\"tmdb\"\n        src={image}\n        alt=\"\"\n        style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n        fill\n      />\n      <div\n        className={`absolute inset-0 z-10 h-full w-full transition duration-300 ${\n          isHovered ? 'bg-gray-800/10' : 'bg-gray-800/30'\n        }`}\n      />\n      <div className=\"relative z-20 w-full truncate whitespace-normal text-center text-2xl font-bold text-white sm:text-3xl\">\n        {name}\n      </div>\n    </Link>\n  );\n};\n\nconst GenreCardPlaceholder = () => {\n  return (\n    <div\n      className={`relative h-32 w-56 animate-pulse rounded-xl bg-gray-700 sm:h-40 sm:w-72`}\n    />\n  );\n};\n\nexport default withProperties(GenreCard, { Placeholder: GenreCardPlaceholder });\n"
  },
  {
    "path": "src/components/GenreTag/index.tsx",
    "content": "import Spinner from '@app/assets/spinner.svg';\nimport Tag from '@app/components/Common/Tag';\nimport { RectangleStackIcon } from '@heroicons/react/24/outline';\nimport type { TmdbGenre } from '@server/api/themoviedb/interfaces';\nimport useSWR from 'swr';\n\ntype GenreTagProps = {\n  type: 'tv' | 'movie';\n  genreId: number;\n};\n\nconst GenreTag = ({ genreId, type }: GenreTagProps) => {\n  const { data, error } = useSWR<TmdbGenre[]>(`/api/v1/genres/${type}`);\n\n  if (!data && !error) {\n    return (\n      <Tag>\n        <Spinner className=\"h-4 w-4\" />\n      </Tag>\n    );\n  }\n\n  const genre = data?.find((genre) => genre.id === genreId);\n\n  return <Tag iconSvg={<RectangleStackIcon />}>{genre?.name}</Tag>;\n};\n\nexport default GenreTag;\n"
  },
  {
    "path": "src/components/IssueBlock/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport { issueOptions } from '@app/components/IssueModal/constants';\nimport { useUser } from '@app/hooks/useUser';\nimport {\n  CalendarIcon,\n  ExclamationTriangleIcon,\n  EyeIcon,\n  UserIcon,\n} from '@heroicons/react/24/solid';\nimport type Issue from '@server/entity/Issue';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\n\ninterface IssueBlockProps {\n  issue: Issue;\n}\n\nconst IssueBlock = ({ issue }: IssueBlockProps) => {\n  const { user } = useUser();\n  const intl = useIntl();\n  const issueOption = issueOptions.find(\n    (opt) => opt.issueType === issue.issueType\n  );\n\n  if (!issueOption) {\n    return null;\n  }\n\n  return (\n    <div className=\"px-4 py-3 text-gray-300\">\n      <div className=\"flex items-center justify-between\">\n        <div className=\"mr-6 min-w-0 flex-1 flex-col items-center text-sm leading-5\">\n          <div className=\"flex flex-nowrap\">\n            <ExclamationTriangleIcon className=\"mr-1.5 h-5 w-5 flex-shrink-0\" />\n            <span className=\"w-40 truncate md:w-auto\">\n              {intl.formatMessage(issueOption.name)}\n            </span>\n          </div>\n          <div className=\"white mb-1 flex flex-nowrap\">\n            <UserIcon className=\"mr-1.5 h-5 w-5 min-w-0 flex-shrink-0\" />\n            <span className=\"w-40 truncate md:w-auto\">\n              <Link\n                href={\n                  issue.createdBy.id === user?.id\n                    ? '/profile'\n                    : `/users/${issue.createdBy.id}`\n                }\n                className=\"font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline\"\n              >\n                {issue.createdBy.displayName}\n              </Link>\n            </span>\n          </div>\n          <div className=\"white mb-1 flex flex-nowrap\">\n            <CalendarIcon className=\"mr-1.5 h-5 w-5 min-w-0 flex-shrink-0\" />\n            <span className=\"w-40 truncate md:w-auto\">\n              {intl.formatDate(issue.createdAt, {\n                year: 'numeric',\n                month: 'long',\n                day: 'numeric',\n              })}\n            </span>\n          </div>\n        </div>\n        <div className=\"ml-2 flex flex-shrink-0 flex-wrap\">\n          <Link href={`/issues/${issue.id}`} passHref legacyBehavior>\n            <Button buttonType=\"primary\" as=\"a\">\n              <EyeIcon />\n            </Button>\n          </Link>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default IssueBlock;\n"
  },
  {
    "path": "src/components/IssueDetails/IssueComment/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport Modal from '@app/components/Common/Modal';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Menu, Transition } from '@headlessui/react';\nimport { EllipsisVerticalIcon } from '@heroicons/react/24/solid';\nimport type { default as IssueCommentType } from '@server/entity/IssueComment';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport Link from 'next/link';\nimport { Fragment, useState } from 'react';\nimport { FormattedRelativeTime, useIntl } from 'react-intl';\nimport ReactMarkdown from 'react-markdown';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.IssueDetails.IssueComment', {\n  postedby: 'Posted {relativeTime} by {username}',\n  postedbyedited: 'Posted {relativeTime} by {username} (Edited)',\n  delete: 'Delete Comment',\n  areyousuredelete: 'Are you sure you want to delete this comment?',\n  validationComment: 'You must enter a message',\n  edit: 'Edit Comment',\n});\n\ninterface IssueCommentProps {\n  comment: IssueCommentType;\n  isReversed?: boolean;\n  isActiveUser?: boolean;\n  onUpdate?: () => void;\n}\n\nconst IssueComment = ({\n  comment,\n  isReversed = false,\n  isActiveUser = false,\n  onUpdate,\n}: IssueCommentProps) => {\n  const intl = useIntl();\n  const [showDeleteModal, setShowDeleteModal] = useState(false);\n  const [isEditing, setIsEditing] = useState(false);\n  const { hasPermission } = useUser();\n\n  const EditCommentSchema = Yup.object().shape({\n    newMessage: Yup.string().required(\n      intl.formatMessage(messages.validationComment)\n    ),\n  });\n\n  const deleteComment = async () => {\n    try {\n      await axios.delete(`/api/v1/issueComment/${comment.id}`);\n    } catch {\n      // something went wrong deleting the comment\n    } finally {\n      if (onUpdate) {\n        onUpdate();\n      }\n    }\n  };\n\n  return (\n    <div\n      className={`flex ${\n        isReversed ? 'flex-row' : 'flex-row-reverse space-x-reverse'\n      } mt-4 space-x-4`}\n    >\n      <Transition\n        as={Fragment}\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={showDeleteModal}\n      >\n        <Modal\n          title={intl.formatMessage(messages.delete)}\n          onCancel={() => setShowDeleteModal(false)}\n          onOk={() => deleteComment()}\n          okText={intl.formatMessage(messages.delete)}\n          okButtonType=\"danger\"\n        >\n          {intl.formatMessage(messages.areyousuredelete)}\n        </Modal>\n      </Transition>\n      <Link href={isActiveUser ? '/profile' : `/users/${comment.user.id}`}>\n        <CachedImage\n          type=\"avatar\"\n          src={comment.user.avatar}\n          alt=\"\"\n          className=\"h-10 w-10 scale-100 transform-gpu rounded-full object-cover ring-1 ring-gray-500 transition duration-300 hover:scale-105\"\n          width={40}\n          height={40}\n        />\n      </Link>\n      <div className=\"relative flex-1\">\n        <div className=\"w-full rounded-md shadow ring-1 ring-gray-500\">\n          {(isActiveUser || hasPermission(Permission.MANAGE_ISSUES)) && (\n            <Menu\n              as=\"div\"\n              className=\"absolute right-1 top-2 z-40 inline-block text-left\"\n            >\n              {({ open }) => (\n                <>\n                  <div>\n                    <Menu.Button className=\"flex items-center rounded-full text-gray-400 hover:text-gray-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-100\">\n                      <span className=\"sr-only\">Open options</span>\n                      <EllipsisVerticalIcon\n                        className=\"h-5 w-5\"\n                        aria-hidden=\"true\"\n                      />\n                    </Menu.Button>\n                  </div>\n\n                  <Transition\n                    as={Fragment}\n                    show={open}\n                    enter=\"transition ease-out duration-100\"\n                    enterFrom=\"opacity-0 scale-95\"\n                    enterTo=\"opacity-100 scale-100\"\n                    leave=\"transition ease-in duration-75\"\n                    leaveFrom=\"opacity-100 scale-100\"\n                    leaveTo=\"opacity-0 scale-95\"\n                  >\n                    <Menu.Items\n                      static\n                      className=\"absolute right-0 mt-2 w-56 origin-top-right rounded-md bg-gray-700 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none\"\n                    >\n                      <div className=\"py-1\">\n                        {isActiveUser && (\n                          <Menu.Item>\n                            {({ active }) => (\n                              <button\n                                onClick={() => setIsEditing(true)}\n                                className={`block w-full px-4 py-2 text-left text-sm ${\n                                  active\n                                    ? 'bg-gray-600 text-white'\n                                    : 'text-gray-100'\n                                }`}\n                              >\n                                {intl.formatMessage(messages.edit)}\n                              </button>\n                            )}\n                          </Menu.Item>\n                        )}\n                        <Menu.Item>\n                          {({ active }) => (\n                            <button\n                              onClick={() => setShowDeleteModal(true)}\n                              className={`block w-full px-4 py-2 text-left text-sm ${\n                                active\n                                  ? 'bg-gray-600 text-white'\n                                  : 'text-gray-100'\n                              }`}\n                            >\n                              {intl.formatMessage(messages.delete)}\n                            </button>\n                          )}\n                        </Menu.Item>\n                      </div>\n                    </Menu.Items>\n                  </Transition>\n                </>\n              )}\n            </Menu>\n          )}\n          <div\n            className={`absolute top-3 z-10 h-3 w-3 rotate-45 bg-gray-800 shadow ring-1 ring-gray-500 ${\n              isReversed ? '-left-1' : '-right-1'\n            }`}\n          />\n          <div className=\"relative z-20 w-full rounded-md bg-gray-800 py-4 pl-4 pr-8\">\n            {isEditing ? (\n              <Formik\n                initialValues={{ newMessage: comment.message }}\n                onSubmit={async (values) => {\n                  await axios.put(`/api/v1/issueComment/${comment.id}`, {\n                    message: values.newMessage,\n                  });\n\n                  if (onUpdate) {\n                    onUpdate();\n                  }\n\n                  setIsEditing(false);\n                }}\n                validationSchema={EditCommentSchema}\n              >\n                {({ isValid, isSubmitting, errors, touched }) => {\n                  return (\n                    <Form>\n                      <Field\n                        as=\"textarea\"\n                        id=\"newMessage\"\n                        name=\"newMessage\"\n                        className=\"h-24\"\n                      />\n                      {errors.newMessage &&\n                        touched.newMessage &&\n                        typeof errors.newMessage === 'string' && (\n                          <div className=\"error\">{errors.newMessage}</div>\n                        )}\n                      <div className=\"mt-4 flex items-center justify-end space-x-2\">\n                        <Button\n                          type=\"button\"\n                          onClick={() => setIsEditing(false)}\n                        >\n                          {intl.formatMessage(globalMessages.cancel)}\n                        </Button>\n                        <Button\n                          buttonType=\"primary\"\n                          disabled={!isValid || isSubmitting}\n                        >\n                          {intl.formatMessage(globalMessages.save)}\n                        </Button>\n                      </div>\n                    </Form>\n                  );\n                }}\n              </Formik>\n            ) : (\n              <div className=\"prose w-full max-w-full\">\n                <ReactMarkdown\n                  skipHtml\n                  allowedElements={['p', 'em', 'strong', 'ul', 'ol', 'li']}\n                >\n                  {comment.message}\n                </ReactMarkdown>\n              </div>\n            )}\n          </div>\n        </div>\n        <div\n          className={`flex items-center justify-between pt-2 text-xs ${\n            isReversed ? 'flex-row-reverse' : 'flex-row'\n          }`}\n        >\n          <span>\n            {intl.formatMessage(\n              comment.createdAt !== comment.updatedAt\n                ? messages.postedbyedited\n                : messages.postedby,\n              {\n                username: (\n                  <Link\n                    href={\n                      isActiveUser ? '/profile' : `/users/${comment.user.id}`\n                    }\n                    className=\"font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline\"\n                  >\n                    {comment.user.displayName}\n                  </Link>\n                ),\n                relativeTime: (\n                  <FormattedRelativeTime\n                    value={Math.floor(\n                      (new Date(comment.createdAt).getTime() - Date.now()) /\n                        1000\n                    )}\n                    updateIntervalInSeconds={1}\n                    numeric=\"auto\"\n                  />\n                ),\n              }\n            )}\n          </span>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default IssueComment;\n"
  },
  {
    "path": "src/components/IssueDetails/IssueDescription/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Menu, Transition } from '@headlessui/react';\nimport { EllipsisVerticalIcon } from '@heroicons/react/24/solid';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport ReactMarkdown from 'react-markdown';\n\nconst messages = defineMessages('components.IssueDetails.IssueDescription', {\n  description: 'Description',\n  edit: 'Edit Description',\n  deleteissue: 'Delete Issue',\n});\n\ninterface IssueDescriptionProps {\n  description: string;\n  belongsToUser: boolean;\n  commentCount: number;\n  onEdit: (newDescription: string) => void;\n  onDelete: () => void;\n}\n\nconst IssueDescription = ({\n  description,\n  belongsToUser,\n  commentCount,\n  onEdit,\n  onDelete,\n}: IssueDescriptionProps) => {\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n  const [isEditing, setIsEditing] = useState(false);\n\n  return (\n    <div className=\"relative\">\n      <div className=\"flex items-center justify-between\">\n        <div className=\"font-semibold text-gray-100 lg:text-xl\">\n          {intl.formatMessage(messages.description)}\n        </div>\n        {(hasPermission(Permission.MANAGE_ISSUES) || belongsToUser) && (\n          <Menu as=\"div\" className=\"relative inline-block text-left\">\n            {({ open }) => (\n              <>\n                <div>\n                  <Menu.Button className=\"flex items-center rounded-full text-gray-400 hover:text-gray-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-100\">\n                    <span className=\"sr-only\">Open options</span>\n                    <EllipsisVerticalIcon\n                      className=\"h-5 w-5\"\n                      aria-hidden=\"true\"\n                    />\n                  </Menu.Button>\n                </div>\n\n                <Transition\n                  show={open}\n                  as=\"div\"\n                  enter=\"transition ease-out duration-100\"\n                  enterFrom=\"opacity-0 scale-95\"\n                  enterTo=\"opacity-100 scale-100\"\n                  leave=\"transition ease-in duration-75\"\n                  leaveFrom=\"opacity-100 scale-100\"\n                  leaveTo=\"opacity-0 scale-95\"\n                >\n                  <Menu.Items\n                    static\n                    className=\"absolute right-0 mt-2 w-56 origin-top-right rounded-md bg-gray-700 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none\"\n                  >\n                    <div className=\"py-1\">\n                      {belongsToUser && (\n                        <Menu.Item>\n                          {({ active }) => (\n                            <button\n                              onClick={() => setIsEditing(true)}\n                              className={`block w-full px-4 py-2 text-left text-sm ${\n                                active\n                                  ? 'bg-gray-600 text-white'\n                                  : 'text-gray-100'\n                              }`}\n                            >\n                              {intl.formatMessage(messages.edit)}\n                            </button>\n                          )}\n                        </Menu.Item>\n                      )}\n                      {(hasPermission(Permission.MANAGE_ISSUES) ||\n                        !commentCount) && (\n                        <Menu.Item>\n                          {({ active }) => (\n                            <button\n                              onClick={() => onDelete()}\n                              className={`block w-full px-4 py-2 text-left text-sm ${\n                                active\n                                  ? 'bg-gray-600 text-white'\n                                  : 'text-gray-100'\n                              }`}\n                            >\n                              {intl.formatMessage(messages.deleteissue)}\n                            </button>\n                          )}\n                        </Menu.Item>\n                      )}\n                    </div>\n                  </Menu.Items>\n                </Transition>\n              </>\n            )}\n          </Menu>\n        )}\n      </div>\n      {isEditing ? (\n        <Formik\n          initialValues={{ newMessage: description }}\n          onSubmit={(values) => {\n            onEdit(values.newMessage);\n            setIsEditing(false);\n          }}\n        >\n          {() => {\n            return (\n              <Form className=\"mt-4\">\n                <Field\n                  id=\"newMessage\"\n                  name=\"newMessage\"\n                  as=\"textarea\"\n                  className=\"h-40\"\n                />\n                <div className=\"mt-2 flex justify-end\">\n                  <Button\n                    buttonType=\"default\"\n                    className=\"mr-2\"\n                    type=\"button\"\n                    onClick={() => setIsEditing(false)}\n                  >\n                    <span>{intl.formatMessage(globalMessages.cancel)}</span>\n                  </Button>\n                  <Button buttonType=\"primary\">\n                    <span>{intl.formatMessage(globalMessages.save)}</span>\n                  </Button>\n                </div>\n              </Form>\n            );\n          }}\n        </Formik>\n      ) : (\n        <div className=\"prose mt-4\">\n          <ReactMarkdown\n            allowedElements={['p', 'img', 'strong', 'em']}\n            skipHtml\n          >\n            {description}\n          </ReactMarkdown>\n        </div>\n      )}\n    </div>\n  );\n};\n\nexport default IssueDescription;\n"
  },
  {
    "path": "src/components/IssueDetails/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport Modal from '@app/components/Common/Modal';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport IssueComment from '@app/components/IssueDetails/IssueComment';\nimport IssueDescription from '@app/components/IssueDetails/IssueDescription';\nimport { issueOptions } from '@app/components/IssueModal/constants';\nimport useDeepLinks from '@app/hooks/useDeepLinks';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport {\n  ChatBubbleOvalLeftEllipsisIcon,\n  CheckCircleIcon,\n  PlayIcon,\n  ServerIcon,\n} from '@heroicons/react/24/outline';\nimport { ArrowPathIcon } from '@heroicons/react/24/solid';\nimport { IssueStatus } from '@server/constants/issue';\nimport { MediaType } from '@server/constants/media';\nimport { MediaServerType } from '@server/constants/server';\nimport type Issue from '@server/entity/Issue';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useState } from 'react';\nimport { FormattedRelativeTime, useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.IssueDetails', {\n  openedby: '#{issueId} opened {relativeTime} by {username}',\n  closeissue: 'Close Issue',\n  closeissueandcomment: 'Close with Comment',\n  leavecomment: 'Comment',\n  comments: 'Comments',\n  reopenissue: 'Reopen Issue',\n  reopenissueandcomment: 'Reopen with Comment',\n  issuepagetitle: 'Issue',\n  playonplex: 'Play on {mediaServerName}',\n  play4konplex: 'Play in 4K on {mediaServerName}',\n  openinarr: 'Open in {arr}',\n  openin4karr: 'Open in 4K {arr}',\n  toasteditdescriptionsuccess: 'Issue description edited successfully!',\n  toasteditdescriptionfailed:\n    'Something went wrong while editing the issue description.',\n  toaststatusupdated: 'Issue status updated successfully!',\n  toaststatusupdatefailed:\n    'Something went wrong while updating the issue status.',\n  issuetype: 'Type',\n  lastupdated: 'Last Updated',\n  problemseason: 'Affected Season',\n  allseasons: 'All Seasons',\n  season: 'Season {seasonNumber}',\n  problemepisode: 'Affected Episode',\n  allepisodes: 'All Episodes',\n  episode: 'Episode {episodeNumber}',\n  deleteissue: 'Delete Issue',\n  deleteissueconfirm: 'Are you sure you want to delete this issue?',\n  toastissuedeleted: 'Issue deleted successfully!',\n  toastissuedeletefailed: 'Something went wrong while deleting the issue.',\n  nocomments: 'No comments.',\n  unknownissuetype: 'Unknown',\n  commentplaceholder: 'Add a comment…',\n});\n\nconst isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {\n  return (movie as MovieDetails).title !== undefined;\n};\n\nconst IssueDetails = () => {\n  const { addToast } = useToasts();\n  const router = useRouter();\n  const intl = useIntl();\n  const [showDeleteModal, setShowDeleteModal] = useState(false);\n  const { user: currentUser, hasPermission } = useUser();\n  const { data: issueData, mutate: revalidateIssue } = useSWR<Issue>(\n    `/api/v1/issue/${router.query.issueId}`\n  );\n  const { data, error } = useSWR<MovieDetails | TvDetails>(\n    issueData?.media.tmdbId\n      ? `/api/v1/${issueData.media.mediaType}/${issueData.media.tmdbId}`\n      : null\n  );\n\n  const { mediaUrl, mediaUrl4k } = useDeepLinks({\n    mediaUrl: data?.mediaInfo?.mediaUrl,\n    mediaUrl4k: data?.mediaInfo?.mediaUrl4k,\n    iOSPlexUrl: data?.mediaInfo?.iOSPlexUrl,\n    iOSPlexUrl4k: data?.mediaInfo?.iOSPlexUrl4k,\n  });\n\n  const CommentSchema = Yup.object().shape({\n    message: Yup.string().required(),\n  });\n\n  const issueOption = issueOptions.find(\n    (opt) => opt.issueType === issueData?.issueType\n  );\n  const settings = useSettings();\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data || !issueData) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  const belongsToUser = issueData.createdBy.id === currentUser?.id;\n\n  const [firstComment, ...otherComments] = issueData.comments;\n\n  const editFirstComment = async (newMessage: string) => {\n    try {\n      await axios.put(`/api/v1/issueComment/${firstComment.id}`, {\n        message: newMessage,\n      });\n\n      addToast(intl.formatMessage(messages.toasteditdescriptionsuccess), {\n        appearance: 'success',\n        autoDismiss: true,\n      });\n      revalidateIssue();\n    } catch {\n      addToast(intl.formatMessage(messages.toasteditdescriptionfailed), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n  };\n\n  const updateIssueStatus = async (newStatus: 'open' | 'resolved') => {\n    try {\n      await axios.post(`/api/v1/issue/${issueData.id}/${newStatus}`);\n\n      addToast(intl.formatMessage(messages.toaststatusupdated), {\n        appearance: 'success',\n        autoDismiss: true,\n      });\n      revalidateIssue();\n      mutate('/api/v1/issue/count');\n    } catch {\n      addToast(intl.formatMessage(messages.toaststatusupdatefailed), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n  };\n\n  const deleteIssue = async () => {\n    try {\n      await axios.delete(`/api/v1/issue/${issueData.id}`);\n      mutate('/api/v1/issue/count');\n\n      addToast(intl.formatMessage(messages.toastissuedeleted), {\n        appearance: 'success',\n        autoDismiss: true,\n      });\n      router.push('/issues');\n    } catch {\n      addToast(intl.formatMessage(messages.toastissuedeletefailed), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n  };\n\n  const title = isMovie(data) ? data.title : data.name;\n  const releaseYear = isMovie(data) ? data.releaseDate : data.firstAirDate;\n\n  return (\n    <div\n      className=\"media-page\"\n      style={{\n        height: 493,\n      }}\n    >\n      <PageTitle title={[intl.formatMessage(messages.issuepagetitle), title]} />\n      <Transition\n        as=\"div\"\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={showDeleteModal}\n      >\n        <Modal\n          title={intl.formatMessage(messages.deleteissue)}\n          onCancel={() => setShowDeleteModal(false)}\n          onOk={() => deleteIssue()}\n          okText={intl.formatMessage(messages.deleteissue)}\n          okButtonType=\"danger\"\n        >\n          {intl.formatMessage(messages.deleteissueconfirm)}\n        </Modal>\n      </Transition>\n      {data.backdropPath && (\n        <div className=\"media-page-bg-image\">\n          <CachedImage\n            type=\"tmdb\"\n            alt=\"\"\n            src={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data.backdropPath}`}\n            style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n            fill\n            priority\n          />\n          <div\n            className=\"absolute inset-0\"\n            style={{\n              backgroundImage:\n                'linear-gradient(180deg, rgba(17, 24, 39, 0.47) 0%, rgba(17, 24, 39, 1) 100%)',\n            }}\n          />\n        </div>\n      )}\n      <div className=\"media-header\">\n        <div className=\"media-poster\">\n          <CachedImage\n            type=\"tmdb\"\n            src={\n              data.posterPath\n                ? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${data.posterPath}`\n                : '/images/seerr_poster_not_found.png'\n            }\n            alt=\"\"\n            sizes=\"100vw\"\n            style={{ width: '100%', height: 'auto' }}\n            width={600}\n            height={900}\n            priority\n          />\n        </div>\n        <div className=\"media-title\">\n          <div className=\"media-status\">\n            {issueData.status === IssueStatus.OPEN && (\n              <Badge badgeType=\"warning\">\n                {intl.formatMessage(globalMessages.open)}\n              </Badge>\n            )}\n            {issueData.status === IssueStatus.RESOLVED && (\n              <Badge badgeType=\"success\">\n                {intl.formatMessage(globalMessages.resolved)}\n              </Badge>\n            )}\n          </div>\n          <h1>\n            <Link\n              href={`/${\n                issueData.media.mediaType === MediaType.MOVIE ? 'movie' : 'tv'\n              }/${data.id}`}\n              className=\"hover:underline\"\n            >\n              {title}\n            </Link>{' '}\n            {releaseYear && (\n              <span className=\"media-year\">({releaseYear.slice(0, 4)})</span>\n            )}\n          </h1>\n          <span className=\"media-attributes\">\n            {intl.formatMessage(messages.openedby, {\n              issueId: issueData.id,\n              username: (\n                <Link\n                  href={\n                    belongsToUser\n                      ? '/profile'\n                      : `/users/${issueData.createdBy.id}`\n                  }\n                  className=\"group ml-1 inline-flex h-full items-center xl:ml-1.5\"\n                >\n                  <CachedImage\n                    type=\"avatar\"\n                    src={issueData.createdBy.avatar}\n                    alt=\"\"\n                    className=\"mr-0.5 h-5 w-5 scale-100 transform-gpu rounded-full object-cover transition duration-300 group-hover:scale-105 xl:mr-1 xl:h-6 xl:w-6\"\n                    width={20}\n                    height={20}\n                  />\n                  <span className=\"font-semibold text-gray-100 transition duration-300 group-hover:text-white group-hover:underline\">\n                    {issueData.createdBy.displayName}\n                  </span>\n                </Link>\n              ),\n              relativeTime: (\n                <FormattedRelativeTime\n                  value={Math.floor(\n                    (new Date(issueData.createdAt).getTime() - Date.now()) /\n                      1000\n                  )}\n                  updateIntervalInSeconds={1}\n                  numeric=\"auto\"\n                />\n              ),\n            })}\n          </span>\n        </div>\n      </div>\n      <div className=\"relative z-10 mt-6 flex text-gray-300\">\n        <div className=\"flex-1 lg:pr-4\">\n          <IssueDescription\n            description={firstComment.message}\n            belongsToUser={belongsToUser}\n            commentCount={otherComments.length}\n            onEdit={(newMessage) => {\n              editFirstComment(newMessage);\n            }}\n            onDelete={() => setShowDeleteModal(true)}\n          />\n          <div className=\"mt-8 lg:hidden\">\n            <div className=\"media-facts\">\n              <div className=\"media-fact\">\n                <span>{intl.formatMessage(messages.issuetype)}</span>\n                <span className=\"media-fact-value\">\n                  {intl.formatMessage(\n                    issueOption?.name ?? messages.unknownissuetype\n                  )}\n                </span>\n              </div>\n              {issueData.media.mediaType === MediaType.TV && (\n                <>\n                  <div className=\"media-fact\">\n                    <span>{intl.formatMessage(messages.problemseason)}</span>\n                    <span className=\"media-fact-value\">\n                      {intl.formatMessage(\n                        issueData.problemSeason > 0\n                          ? messages.season\n                          : messages.allseasons,\n                        { seasonNumber: issueData.problemSeason }\n                      )}\n                    </span>\n                  </div>\n                  {issueData.problemSeason > 0 && (\n                    <div className=\"media-fact\">\n                      <span>{intl.formatMessage(messages.problemepisode)}</span>\n                      <span className=\"media-fact-value\">\n                        {intl.formatMessage(\n                          issueData.problemEpisode > 0\n                            ? messages.episode\n                            : messages.allepisodes,\n                          { episodeNumber: issueData.problemEpisode }\n                        )}\n                      </span>\n                    </div>\n                  )}\n                </>\n              )}\n              <div className=\"media-fact\">\n                <span>{intl.formatMessage(messages.lastupdated)}</span>\n                <span className=\"media-fact-value\">\n                  <FormattedRelativeTime\n                    value={Math.floor(\n                      (new Date(issueData.updatedAt).getTime() - Date.now()) /\n                        1000\n                    )}\n                    updateIntervalInSeconds={1}\n                    numeric=\"auto\"\n                  />\n                </span>\n              </div>\n            </div>\n            <div className=\"mb-6 mt-4 flex flex-col space-y-2\">\n              {issueData?.media.mediaUrl && (\n                <Button\n                  as=\"a\"\n                  href={mediaUrl}\n                  target=\"_blank\"\n                  rel=\"noreferrer\"\n                  className=\"w-full\"\n                  buttonType=\"ghost\"\n                >\n                  <PlayIcon />\n                  <span>\n                    {settings.currentSettings.mediaServerType ===\n                    MediaServerType.EMBY\n                      ? intl.formatMessage(messages.playonplex, {\n                          mediaServerName: 'Emby',\n                        })\n                      : settings.currentSettings.mediaServerType ===\n                          MediaServerType.PLEX\n                        ? intl.formatMessage(messages.playonplex, {\n                            mediaServerName: 'Plex',\n                          })\n                        : intl.formatMessage(messages.playonplex, {\n                            mediaServerName: 'Jellyfin',\n                          })}\n                  </span>\n                </Button>\n              )}\n              {issueData?.media.serviceUrl &&\n                hasPermission(Permission.ADMIN) && (\n                  <Button\n                    as=\"a\"\n                    href={issueData?.media.serviceUrl}\n                    target=\"_blank\"\n                    rel=\"noreferrer\"\n                    className=\"w-full\"\n                    buttonType=\"ghost\"\n                  >\n                    <ServerIcon />\n                    <span>\n                      {intl.formatMessage(messages.openinarr, {\n                        arr:\n                          issueData.media.mediaType === MediaType.MOVIE\n                            ? 'Radarr'\n                            : 'Sonarr',\n                      })}\n                    </span>\n                  </Button>\n                )}\n              {issueData?.media.mediaUrl4k && (\n                <Button\n                  as=\"a\"\n                  href={mediaUrl4k}\n                  target=\"_blank\"\n                  rel=\"noreferrer\"\n                  className=\"w-full\"\n                  buttonType=\"ghost\"\n                >\n                  <PlayIcon />\n                  <span>\n                    {settings.currentSettings.mediaServerType ===\n                    MediaServerType.EMBY\n                      ? intl.formatMessage(messages.play4konplex, {\n                          mediaServerName: 'Emby',\n                        })\n                      : settings.currentSettings.mediaServerType ===\n                          MediaServerType.PLEX\n                        ? intl.formatMessage(messages.play4konplex, {\n                            mediaServerName: 'Plex',\n                          })\n                        : intl.formatMessage(messages.play4konplex, {\n                            mediaServerName: 'Jellyfin',\n                          })}\n                  </span>\n                </Button>\n              )}\n              {issueData?.media.serviceUrl4k &&\n                hasPermission(Permission.ADMIN) && (\n                  <Button\n                    as=\"a\"\n                    href={issueData?.media.serviceUrl4k}\n                    target=\"_blank\"\n                    rel=\"noreferrer\"\n                    className=\"w-full\"\n                    buttonType=\"ghost\"\n                  >\n                    <ServerIcon />\n                    <span>\n                      {intl.formatMessage(messages.openin4karr, {\n                        arr:\n                          issueData.media.mediaType === MediaType.MOVIE\n                            ? 'Radarr'\n                            : 'Sonarr',\n                      })}\n                    </span>\n                  </Button>\n                )}\n            </div>\n          </div>\n          <div className=\"mt-6\">\n            <div className=\"font-semibold text-gray-100 lg:text-xl\">\n              {intl.formatMessage(messages.comments)}\n            </div>\n            {otherComments.map((comment) => (\n              <IssueComment\n                comment={comment}\n                key={`issue-comment-${comment.id}`}\n                isReversed={issueData.createdBy.id === comment.user.id}\n                isActiveUser={comment.user.id === currentUser?.id}\n                onUpdate={() => revalidateIssue()}\n              />\n            ))}\n            {otherComments.length === 0 && (\n              <div className=\"mb-10 mt-4 text-gray-400\">\n                <span>{intl.formatMessage(messages.nocomments)}</span>\n              </div>\n            )}\n            {(hasPermission(Permission.MANAGE_ISSUES) || belongsToUser) && (\n              <Formik\n                initialValues={{\n                  message: '',\n                }}\n                validationSchema={CommentSchema}\n                onSubmit={async (values, { resetForm }) => {\n                  await axios.post(`/api/v1/issue/${issueData?.id}/comment`, {\n                    message: values.message,\n                  });\n                  revalidateIssue();\n                  resetForm();\n                }}\n              >\n                {({ isValid, isSubmitting, values, handleSubmit }) => {\n                  return (\n                    <Form>\n                      <div className=\"my-6\">\n                        <Field\n                          id=\"message\"\n                          name=\"message\"\n                          as=\"textarea\"\n                          placeholder={intl.formatMessage(\n                            messages.commentplaceholder\n                          )}\n                          className=\"h-20\"\n                        />\n                        <div className=\"mt-4 flex items-center justify-end space-x-2\">\n                          {(hasPermission(Permission.MANAGE_ISSUES) ||\n                            belongsToUser) && (\n                            <>\n                              {issueData.status === IssueStatus.OPEN ? (\n                                <Button\n                                  type=\"button\"\n                                  buttonType=\"danger\"\n                                  onClick={async () => {\n                                    await updateIssueStatus('resolved');\n\n                                    if (values.message) {\n                                      handleSubmit();\n                                    }\n                                  }}\n                                >\n                                  <CheckCircleIcon />\n                                  <span>\n                                    {intl.formatMessage(\n                                      values.message\n                                        ? messages.closeissueandcomment\n                                        : messages.closeissue\n                                    )}\n                                  </span>\n                                </Button>\n                              ) : (\n                                <Button\n                                  type=\"button\"\n                                  buttonType=\"default\"\n                                  onClick={async () => {\n                                    await updateIssueStatus('open');\n\n                                    if (values.message) {\n                                      handleSubmit();\n                                    }\n                                  }}\n                                >\n                                  <ArrowPathIcon />\n                                  <span>\n                                    {intl.formatMessage(\n                                      values.message\n                                        ? messages.reopenissueandcomment\n                                        : messages.reopenissue\n                                    )}\n                                  </span>\n                                </Button>\n                              )}\n                            </>\n                          )}\n                          <Button\n                            type=\"submit\"\n                            buttonType=\"primary\"\n                            disabled={\n                              !isValid || isSubmitting || !values.message\n                            }\n                          >\n                            <ChatBubbleOvalLeftEllipsisIcon />\n                            <span>\n                              {intl.formatMessage(messages.leavecomment)}\n                            </span>\n                          </Button>\n                        </div>\n                      </div>\n                    </Form>\n                  );\n                }}\n              </Formik>\n            )}\n          </div>\n        </div>\n        <div className=\"hidden lg:block lg:w-80 lg:pl-4\">\n          <div className=\"media-facts\">\n            <div className=\"media-fact\">\n              <span>{intl.formatMessage(messages.issuetype)}</span>\n              <span className=\"media-fact-value\">\n                {intl.formatMessage(\n                  issueOption?.name ?? messages.unknownissuetype\n                )}\n              </span>\n            </div>\n            {issueData.media.mediaType === MediaType.TV && (\n              <>\n                <div className=\"media-fact\">\n                  <span>{intl.formatMessage(messages.problemseason)}</span>\n                  <span className=\"media-fact-value\">\n                    {intl.formatMessage(\n                      issueData.problemSeason > 0\n                        ? messages.season\n                        : messages.allseasons,\n                      { seasonNumber: issueData.problemSeason }\n                    )}\n                  </span>\n                </div>\n                {issueData.problemSeason > 0 && (\n                  <div className=\"media-fact\">\n                    <span>{intl.formatMessage(messages.problemepisode)}</span>\n                    <span className=\"media-fact-value\">\n                      {intl.formatMessage(\n                        issueData.problemEpisode > 0\n                          ? messages.episode\n                          : messages.allepisodes,\n                        { episodeNumber: issueData.problemEpisode }\n                      )}\n                    </span>\n                  </div>\n                )}\n              </>\n            )}\n            <div className=\"media-fact\">\n              <span>{intl.formatMessage(messages.lastupdated)}</span>\n              <span className=\"media-fact-value\">\n                <FormattedRelativeTime\n                  value={Math.floor(\n                    (new Date(issueData.updatedAt).getTime() - Date.now()) /\n                      1000\n                  )}\n                  updateIntervalInSeconds={1}\n                  numeric=\"auto\"\n                />\n              </span>\n            </div>\n          </div>\n          <div className=\"mb-6 mt-4 flex flex-col space-y-2\">\n            {issueData?.media.mediaUrl && (\n              <Button\n                as=\"a\"\n                href={mediaUrl}\n                target=\"_blank\"\n                rel=\"noreferrer\"\n                className=\"w-full\"\n                buttonType=\"ghost\"\n              >\n                <PlayIcon />\n                <span>\n                  {settings.currentSettings.mediaServerType ===\n                  MediaServerType.EMBY\n                    ? intl.formatMessage(messages.playonplex, {\n                        mediaServerName: 'Emby',\n                      })\n                    : settings.currentSettings.mediaServerType ===\n                        MediaServerType.PLEX\n                      ? intl.formatMessage(messages.playonplex, {\n                          mediaServerName: 'Plex',\n                        })\n                      : intl.formatMessage(messages.playonplex, {\n                          mediaServerName: 'Jellyfin',\n                        })}\n                </span>\n              </Button>\n            )}\n            {issueData?.media.serviceUrl && hasPermission(Permission.ADMIN) && (\n              <Button\n                as=\"a\"\n                href={issueData?.media.serviceUrl}\n                target=\"_blank\"\n                rel=\"noreferrer\"\n                className=\"w-full\"\n                buttonType=\"ghost\"\n              >\n                <ServerIcon />\n                <span>\n                  {intl.formatMessage(messages.openinarr, {\n                    arr:\n                      issueData.media.mediaType === MediaType.MOVIE\n                        ? 'Radarr'\n                        : 'Sonarr',\n                  })}\n                </span>\n              </Button>\n            )}\n            {issueData?.media.mediaUrl4k && (\n              <Button\n                as=\"a\"\n                href={mediaUrl4k}\n                target=\"_blank\"\n                rel=\"noreferrer\"\n                className=\"w-full\"\n                buttonType=\"ghost\"\n              >\n                <PlayIcon />\n                <span>\n                  {settings.currentSettings.mediaServerType ===\n                  MediaServerType.EMBY\n                    ? intl.formatMessage(messages.play4konplex, {\n                        mediaServerName: 'Emby',\n                      })\n                    : settings.currentSettings.mediaServerType ===\n                        MediaServerType.PLEX\n                      ? intl.formatMessage(messages.play4konplex, {\n                          mediaServerName: 'Plex',\n                        })\n                      : intl.formatMessage(messages.play4konplex, {\n                          mediaServerName: 'Jellyfin',\n                        })}\n                </span>\n              </Button>\n            )}\n            {issueData?.media.serviceUrl4k &&\n              hasPermission(Permission.ADMIN) && (\n                <Button\n                  as=\"a\"\n                  href={issueData?.media.serviceUrl4k}\n                  target=\"_blank\"\n                  rel=\"noreferrer\"\n                  className=\"w-full\"\n                  buttonType=\"ghost\"\n                >\n                  <ServerIcon />\n                  <span>\n                    {intl.formatMessage(messages.openin4karr, {\n                      arr:\n                        issueData.media.mediaType === MediaType.MOVIE\n                          ? 'Radarr'\n                          : 'Sonarr',\n                    })}\n                  </span>\n                </Button>\n              )}\n          </div>\n        </div>\n      </div>\n      <div className=\"extra-bottom-space\" />\n    </div>\n  );\n};\n\nexport default IssueDetails;\n"
  },
  {
    "path": "src/components/IssueList/IssueItem/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport { issueOptions } from '@app/components/IssueModal/constants';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { EyeIcon } from '@heroicons/react/24/solid';\nimport { IssueStatus } from '@server/constants/issue';\nimport { MediaType } from '@server/constants/media';\nimport type Issue from '@server/entity/Issue';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport Link from 'next/link';\nimport { useInView } from 'react-intersection-observer';\nimport { FormattedRelativeTime, useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.IssueList.IssueItem', {\n  openeduserdate: '{date} by {user}',\n  seasons: '{seasonCount, plural, one {Season} other {Seasons}}',\n  episodes: '{episodeCount, plural, one {Episode} other {Episodes}}',\n  problemepisode: 'Affected Episode',\n  issuetype: 'Type',\n  issuestatus: 'Status',\n  opened: 'Opened',\n  viewissue: 'View Issue',\n  unknownissuetype: 'Unknown',\n  descriptionpreview: 'Issue Description',\n});\n\nconst isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {\n  return (movie as MovieDetails).title !== undefined;\n};\n\ninterface IssueItemProps {\n  issue: Issue;\n}\n\nconst IssueItem = ({ issue }: IssueItemProps) => {\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n  const { ref, inView } = useInView({\n    triggerOnce: true,\n  });\n  const url =\n    issue.media.mediaType === 'movie'\n      ? `/api/v1/movie/${issue.media.tmdbId}`\n      : `/api/v1/tv/${issue.media.tmdbId}`;\n  const { data: title, error } = useSWR<MovieDetails | TvDetails>(\n    inView ? url : null\n  );\n\n  if (!title && !error) {\n    return (\n      <div\n        className=\"h-64 w-full animate-pulse rounded-xl bg-gray-800 xl:h-28\"\n        ref={ref}\n      />\n    );\n  }\n\n  if (!title) {\n    return <div>uh oh</div>;\n  }\n\n  const issueOption = issueOptions.find(\n    (opt) => opt.issueType === issue?.issueType\n  );\n\n  const problemSeasonEpisodeLine: React.ReactNode[] = [];\n\n  if (!isMovie(title) && issue) {\n    problemSeasonEpisodeLine.push(\n      <>\n        <span className=\"card-field-name\">\n          {intl.formatMessage(messages.seasons, {\n            seasonCount: issue.problemSeason ? 1 : 0,\n          })}\n        </span>\n        <span className=\"mr-4 uppercase\">\n          <Badge>\n            {issue.problemSeason > 0\n              ? issue.problemSeason\n              : intl.formatMessage(globalMessages.all)}\n          </Badge>\n        </span>\n      </>\n    );\n\n    if (issue.problemSeason > 0) {\n      problemSeasonEpisodeLine.push(\n        <>\n          <span className=\"card-field-name\">\n            {intl.formatMessage(messages.episodes, {\n              episodeCount: issue.problemEpisode ? 1 : 0,\n            })}\n          </span>\n          <span className=\"uppercase\">\n            <Badge>\n              {issue.problemEpisode > 0\n                ? issue.problemEpisode\n                : intl.formatMessage(globalMessages.all)}\n            </Badge>\n          </span>\n        </>\n      );\n    }\n  }\n\n  const description = issue.comments?.[0]?.message || '';\n  const maxDescriptionLength = 120;\n  const shouldTruncate = description.length > maxDescriptionLength;\n  const truncatedDescription = shouldTruncate\n    ? description.substring(0, maxDescriptionLength) + '...'\n    : description;\n\n  return (\n    <div className=\"relative flex w-full flex-col justify-between overflow-hidden rounded-xl bg-gray-800 py-4 text-gray-400 shadow-md ring-1 ring-gray-700 xl:flex-row\">\n      {title.backdropPath && (\n        <div className=\"absolute inset-0 z-0 w-full bg-cover bg-center xl:w-2/3\">\n          <CachedImage\n            type=\"tmdb\"\n            src={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${title.backdropPath}`}\n            alt=\"\"\n            style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n            fill\n          />\n          <div\n            className=\"absolute inset-0\"\n            style={{\n              backgroundImage:\n                'linear-gradient(90deg, rgba(31, 41, 55, 0.47) 0%, rgba(31, 41, 55, 1) 100%)',\n            }}\n          />\n        </div>\n      )}\n      <div className=\"relative flex w-full flex-col justify-between overflow-hidden sm:flex-row\">\n        <div className=\"relative z-10 flex w-full items-center overflow-hidden pl-4 pr-4 sm:pr-0 xl:w-7/12 2xl:w-2/3\">\n          <Link\n            href={\n              issue.media.mediaType === MediaType.MOVIE\n                ? `/movie/${issue.media.tmdbId}`\n                : `/tv/${issue.media.tmdbId}`\n            }\n            className=\"relative h-auto w-12 flex-shrink-0 scale-100 transform-gpu overflow-hidden rounded-md transition duration-300 hover:scale-105\"\n          >\n            <CachedImage\n              type=\"tmdb\"\n              src={\n                title.posterPath\n                  ? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`\n                  : '/images/seerr_poster_not_found.png'\n              }\n              alt=\"\"\n              sizes=\"100vw\"\n              style={{ width: '100%', height: 'auto', objectFit: 'cover' }}\n              width={600}\n              height={900}\n            />\n          </Link>\n          <div className=\"flex flex-col justify-center overflow-hidden pl-2 xl:pl-4\">\n            <div className=\"pt-0.5 text-xs text-white sm:pt-1\">\n              {(isMovie(title) ? title.releaseDate : title.firstAirDate)?.slice(\n                0,\n                4\n              )}\n            </div>\n            <Link\n              href={\n                issue.media.mediaType === MediaType.MOVIE\n                  ? `/movie/${issue.media.tmdbId}`\n                  : `/tv/${issue.media.tmdbId}`\n              }\n              className=\"mr-2 min-w-0 truncate text-lg font-bold text-white hover:underline xl:text-xl\"\n            >\n              {isMovie(title) ? title.title : title.name}\n            </Link>\n            {description && (\n              <div className=\"mt-1 max-w-full\">\n                <div className=\"overflow-hidden text-sm text-gray-300\">\n                  {shouldTruncate ? (\n                    <Tooltip\n                      content={\n                        <div className=\"max-w-sm p-3\">\n                          <div className=\"mb-1 text-sm font-medium text-gray-200\">\n                            Issue Description\n                          </div>\n                          <div className=\"whitespace-pre-wrap text-sm leading-relaxed text-gray-300\">\n                            {description}\n                          </div>\n                        </div>\n                      }\n                      tooltipConfig={{\n                        placement: 'top',\n                        offset: [0, 8],\n                      }}\n                    >\n                      <span className=\"block cursor-help truncate transition-colors hover:text-gray-200\">\n                        {truncatedDescription}\n                      </span>\n                    </Tooltip>\n                  ) : (\n                    <span className=\"block break-words\">{description}</span>\n                  )}\n                </div>\n              </div>\n            )}\n            {problemSeasonEpisodeLine.length > 0 && (\n              <div className=\"card-field mt-1\">\n                {problemSeasonEpisodeLine.map((t, k) => (\n                  <span key={k}>{t}</span>\n                ))}\n              </div>\n            )}\n          </div>\n        </div>\n        <div className=\"z-10 ml-4 mt-4 flex w-full flex-col justify-center overflow-hidden pr-4 text-sm sm:ml-2 sm:mt-0 xl:flex-1 xl:pr-0\">\n          <div className=\"card-field\">\n            <span className=\"card-field-name\">\n              {intl.formatMessage(messages.issuestatus)}\n            </span>\n            {issue.status === IssueStatus.OPEN ? (\n              <Badge badgeType=\"warning\" href={`/issues/${issue.id}`}>\n                {intl.formatMessage(globalMessages.open)}\n              </Badge>\n            ) : (\n              <Badge badgeType=\"success\" href={`/issues/${issue.id}`}>\n                {intl.formatMessage(globalMessages.resolved)}\n              </Badge>\n            )}\n          </div>\n          <div className=\"card-field\">\n            <span className=\"card-field-name\">\n              {intl.formatMessage(messages.issuetype)}\n            </span>\n            <span className=\"flex truncate text-sm text-gray-300\">\n              {intl.formatMessage(\n                issueOption?.name ?? messages.unknownissuetype\n              )}\n            </span>\n          </div>\n          <div className=\"card-field\">\n            {hasPermission([Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES], {\n              type: 'or',\n            }) ? (\n              <>\n                <span className=\"card-field-name\">\n                  {intl.formatMessage(messages.opened)}\n                </span>\n                <span className=\"flex truncate text-sm text-gray-300\">\n                  {intl.formatMessage(messages.openeduserdate, {\n                    date: (\n                      <FormattedRelativeTime\n                        value={Math.floor(\n                          (new Date(issue.createdAt).getTime() - Date.now()) /\n                            1000\n                        )}\n                        updateIntervalInSeconds={1}\n                        numeric=\"auto\"\n                      />\n                    ),\n                    user: (\n                      <Link\n                        href={`/users/${issue.createdBy.id}`}\n                        className=\"group flex items-center truncate\"\n                      >\n                        <CachedImage\n                          type=\"avatar\"\n                          src={issue.createdBy.avatar}\n                          alt=\"\"\n                          className=\"avatar-sm ml-1.5 object-cover\"\n                          width={20}\n                          height={20}\n                        />\n                        <span className=\"truncate text-sm font-semibold group-hover:text-white group-hover:underline\">\n                          {issue.createdBy.displayName}\n                        </span>\n                      </Link>\n                    ),\n                  })}\n                </span>\n              </>\n            ) : (\n              <>\n                <span className=\"card-field-name\">\n                  {intl.formatMessage(messages.opened)}\n                </span>\n                <span className=\"flex truncate text-sm text-gray-300\">\n                  <FormattedRelativeTime\n                    value={Math.floor(\n                      (new Date(issue.createdAt).getTime() - Date.now()) / 1000\n                    )}\n                    updateIntervalInSeconds={1}\n                    numeric=\"auto\"\n                  />\n                </span>\n              </>\n            )}\n          </div>\n        </div>\n      </div>\n      <div className=\"z-10 mt-4 flex w-full flex-col justify-center pl-4 pr-4 xl:mt-0 xl:w-96 xl:items-end xl:pl-0\">\n        <span className=\"w-full\">\n          <Link href={`/issues/${issue.id}`} passHref legacyBehavior>\n            <Button as=\"a\" className=\"w-full\" buttonType=\"primary\">\n              <EyeIcon />\n              <span>{intl.formatMessage(messages.viewissue)}</span>\n            </Button>\n          </Link>\n        </span>\n      </div>\n    </div>\n  );\n};\n\nexport default IssueItem;\n"
  },
  {
    "path": "src/components/IssueList/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport IssueItem from '@app/components/IssueList/IssueItem';\nimport { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport {\n  BarsArrowDownIcon,\n  ChevronLeftIcon,\n  ChevronRightIcon,\n  FunnelIcon,\n} from '@heroicons/react/24/solid';\nimport type { IssueResultsResponse } from '@server/interfaces/api/issueInterfaces';\nimport { useRouter } from 'next/router';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.IssueList', {\n  issues: 'Issues',\n  sortAdded: 'Most Recent',\n  sortModified: 'Last Modified',\n  showallissues: 'Show All Issues',\n});\n\nenum Filter {\n  ALL = 'all',\n  OPEN = 'open',\n  RESOLVED = 'resolved',\n}\n\ntype Sort = 'added' | 'modified';\n\nconst IssueList = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const [currentFilter, setCurrentFilter] = useState<Filter>(Filter.OPEN);\n  const [currentSort, setCurrentSort] = useState<Sort>('added');\n  const [currentPageSize, setCurrentPageSize] = useState<number>(10);\n\n  const page = router.query.page ? Number(router.query.page) : 1;\n  const pageIndex = page - 1;\n  const updateQueryParams = useUpdateQueryParams({ page: page.toString() });\n\n  const { data, error } = useSWR<IssueResultsResponse>(\n    `/api/v1/issue?take=${currentPageSize}&skip=${\n      pageIndex * currentPageSize\n    }&filter=${currentFilter}&sort=${currentSort}`\n  );\n\n  // Restore last set filter values on component mount\n  useEffect(() => {\n    const filterString = window.localStorage.getItem('il-filter-settings');\n\n    if (filterString) {\n      const filterSettings = JSON.parse(filterString);\n\n      setCurrentFilter(filterSettings.currentFilter);\n      setCurrentSort(filterSettings.currentSort);\n      setCurrentPageSize(filterSettings.currentPageSize);\n    }\n\n    // If filter value is provided in query, use that instead\n    if (Object.values(Filter).includes(router.query.filter as Filter)) {\n      setCurrentFilter(router.query.filter as Filter);\n    }\n  }, [router.query.filter]);\n\n  // Set filter values to local storage any time they are changed\n  useEffect(() => {\n    window.localStorage.setItem(\n      'il-filter-settings',\n      JSON.stringify({\n        currentFilter,\n        currentSort,\n        currentPageSize,\n      })\n    );\n  }, [currentFilter, currentSort, currentPageSize]);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <LoadingSpinner />;\n  }\n\n  const hasNextPage = data.pageInfo.pages > pageIndex + 1;\n  const hasPrevPage = pageIndex > 0;\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(messages.issues)} />\n      <div className=\"mb-4 flex flex-col justify-between lg:flex-row lg:items-end\">\n        <Header>{intl.formatMessage(messages.issues)}</Header>\n        <div className=\"mt-2 flex flex-grow flex-col sm:flex-row lg:flex-grow-0\">\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n              <FunnelIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"filter\"\n              name=\"filter\"\n              onChange={(e) => {\n                setCurrentFilter(e.target.value as Filter);\n                router.push({\n                  pathname: router.pathname,\n                  query: router.query.userId\n                    ? { userId: router.query.userId }\n                    : {},\n                });\n              }}\n              value={currentFilter}\n              className=\"rounded-r-only\"\n            >\n              <option value=\"all\">\n                {intl.formatMessage(globalMessages.all)}\n              </option>\n              <option value=\"open\">\n                {intl.formatMessage(globalMessages.open)}\n              </option>\n              <option value=\"resolved\">\n                {intl.formatMessage(globalMessages.resolved)}\n              </option>\n            </select>\n          </div>\n          <div className=\"mb-2 flex flex-grow sm:mb-0 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-gray-100 sm:text-sm\">\n              <BarsArrowDownIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"sort\"\n              name=\"sort\"\n              onChange={(e) => {\n                setCurrentSort(e.target.value as Sort);\n                router.push({\n                  pathname: router.pathname,\n                  query: router.query.userId\n                    ? { userId: router.query.userId }\n                    : {},\n                });\n              }}\n              value={currentSort}\n              className=\"rounded-r-only\"\n            >\n              <option value=\"added\">\n                {intl.formatMessage(messages.sortAdded)}\n              </option>\n              <option value=\"modified\">\n                {intl.formatMessage(messages.sortModified)}\n              </option>\n            </select>\n          </div>\n        </div>\n      </div>\n      {data.results.map((issue) => {\n        return (\n          <div className=\"py-2\" key={`issue-item-${issue.id}`}>\n            <IssueItem issue={issue} />\n          </div>\n        );\n      })}\n      {data.results.length === 0 && (\n        <div className=\"flex w-full flex-col items-center justify-center py-24 text-white\">\n          <span className=\"text-2xl text-gray-400\">\n            {intl.formatMessage(globalMessages.noresults)}\n          </span>\n          {currentFilter !== Filter.ALL && (\n            <div className=\"mt-4\">\n              <Button\n                buttonType=\"primary\"\n                onClick={() => setCurrentFilter(Filter.ALL)}\n              >\n                {intl.formatMessage(messages.showallissues)}\n              </Button>\n            </div>\n          )}\n        </div>\n      )}\n      <div className=\"actions\">\n        <nav\n          className=\"mb-3 flex flex-col items-center space-y-3 sm:flex-row sm:space-y-0\"\n          aria-label=\"Pagination\"\n        >\n          <div className=\"hidden lg:flex lg:flex-1\">\n            <p className=\"text-sm\">\n              {data.results.length > 0 &&\n                intl.formatMessage(globalMessages.showingresults, {\n                  from: pageIndex * currentPageSize + 1,\n                  to:\n                    data.results.length < currentPageSize\n                      ? pageIndex * currentPageSize + data.results.length\n                      : (pageIndex + 1) * currentPageSize,\n                  total: data.pageInfo.results,\n                  strong: (msg: React.ReactNode) => (\n                    <span className=\"font-medium\">{msg}</span>\n                  ),\n                })}\n            </p>\n          </div>\n          <div className=\"flex justify-center sm:flex-1 sm:justify-start lg:justify-center\">\n            <span className=\"-mt-3 items-center truncate text-sm sm:mt-0\">\n              {intl.formatMessage(globalMessages.resultsperpage, {\n                pageSize: (\n                  <select\n                    id=\"pageSize\"\n                    name=\"pageSize\"\n                    onChange={(e) => {\n                      setCurrentPageSize(Number(e.target.value));\n                      router\n                        .push({\n                          pathname: router.pathname,\n                          query: router.query.userId\n                            ? { userId: router.query.userId }\n                            : {},\n                        })\n                        .then(() => window.scrollTo(0, 0));\n                    }}\n                    value={currentPageSize}\n                    className=\"short inline\"\n                  >\n                    <option value=\"5\">5</option>\n                    <option value=\"10\">10</option>\n                    <option value=\"25\">25</option>\n                    <option value=\"50\">50</option>\n                    <option value=\"100\">100</option>\n                  </select>\n                ),\n              })}\n            </span>\n          </div>\n          <div className=\"flex flex-auto justify-center space-x-2 sm:flex-1 sm:justify-end\">\n            <Button\n              disabled={!hasPrevPage}\n              onClick={() => updateQueryParams('page', (page - 1).toString())}\n            >\n              <ChevronLeftIcon />\n              <span>{intl.formatMessage(globalMessages.previous)}</span>\n            </Button>\n            <Button\n              disabled={!hasNextPage}\n              onClick={() => updateQueryParams('page', (page + 1).toString())}\n            >\n              <span>{intl.formatMessage(globalMessages.next)}</span>\n              <ChevronRightIcon />\n            </Button>\n          </div>\n        </nav>\n      </div>\n    </>\n  );\n};\n\nexport default IssueList;\n"
  },
  {
    "path": "src/components/IssueModal/CreateIssueModal/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport Modal from '@app/components/Common/Modal';\nimport { issueOptions } from '@app/components/IssueModal/constants';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { RadioGroup } from '@headlessui/react';\nimport { ArrowRightCircleIcon } from '@heroicons/react/24/solid';\nimport { MediaStatus } from '@server/constants/media';\nimport type Issue from '@server/entity/Issue';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport axios from 'axios';\nimport { Field, Formik } from 'formik';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.IssueModal.CreateIssueModal', {\n  validationMessageRequired: 'You must provide a description',\n  whatswrong: \"What's wrong?\",\n  providedetail:\n    'Please provide a detailed explanation of the issue you encountered.',\n  extras: 'Extras',\n  season: 'Season {seasonNumber}',\n  episode: 'Episode {episodeNumber}',\n  allseasons: 'All Seasons',\n  allepisodes: 'All Episodes',\n  problemseason: 'Affected Season',\n  problemepisode: 'Affected Episode',\n  toastSuccessCreate:\n    'Issue report for <strong>{title}</strong> submitted successfully!',\n  toastFailedCreate: 'Something went wrong while submitting the issue.',\n  toastviewissue: 'View Issue',\n  reportissue: 'Report an Issue',\n  submitissue: 'Submit Issue',\n});\n\nconst isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {\n  return (movie as MovieDetails).title !== undefined;\n};\n\nconst classNames = (...classes: string[]) => {\n  return classes.filter(Boolean).join(' ');\n};\n\ninterface CreateIssueModalProps {\n  mediaType: 'movie' | 'tv';\n  tmdbId?: number;\n  onCancel?: () => void;\n}\n\nconst CreateIssueModal = ({\n  onCancel,\n  mediaType,\n  tmdbId,\n}: CreateIssueModalProps) => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const { hasPermission } = useUser();\n  const { addToast } = useToasts();\n  const { data, error } = useSWR<MovieDetails | TvDetails>(\n    tmdbId ? `/api/v1/${mediaType}/${tmdbId}` : null\n  );\n\n  if (!tmdbId) {\n    return null;\n  }\n\n  const availableSeasons = (data?.mediaInfo?.seasons ?? [])\n    .filter(\n      (season) =>\n        season.status === MediaStatus.AVAILABLE ||\n        season.status === MediaStatus.PARTIALLY_AVAILABLE ||\n        (settings.currentSettings.series4kEnabled &&\n          hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_TV], {\n            type: 'or',\n          }) &&\n          (season.status4k === MediaStatus.AVAILABLE ||\n            season.status4k === MediaStatus.PARTIALLY_AVAILABLE))\n    )\n    .map((season) => season.seasonNumber);\n\n  const CreateIssueModalSchema = Yup.object().shape({\n    message: Yup.string().required(\n      intl.formatMessage(messages.validationMessageRequired)\n    ),\n  });\n\n  return (\n    <Formik\n      initialValues={{\n        selectedIssue: issueOptions[0],\n        message: '',\n        problemSeason: availableSeasons.length === 1 ? availableSeasons[0] : 0,\n        problemEpisode: 0,\n      }}\n      validationSchema={CreateIssueModalSchema}\n      onSubmit={async (values) => {\n        try {\n          const newIssue = await axios.post<Issue>('/api/v1/issue', {\n            issueType: values.selectedIssue.issueType,\n            message: values.message,\n            mediaId: data?.mediaInfo?.id,\n            problemSeason: values.problemSeason,\n            problemEpisode:\n              values.problemSeason > 0 ? values.problemEpisode : 0,\n          });\n\n          if (data) {\n            addToast(\n              <>\n                <div>\n                  {intl.formatMessage(messages.toastSuccessCreate, {\n                    title: isMovie(data) ? data.title : data.name,\n                    strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n                  })}\n                </div>\n                <Link href={`/issues/${newIssue.data.id}`} legacyBehavior>\n                  <Button as=\"a\" className=\"mt-4\">\n                    <span>{intl.formatMessage(messages.toastviewissue)}</span>\n                    <ArrowRightCircleIcon />\n                  </Button>\n                </Link>\n              </>,\n              {\n                appearance: 'success',\n                autoDismiss: true,\n              }\n            );\n\n            mutate('/api/v1/issue/count');\n          }\n\n          if (onCancel) {\n            onCancel();\n          }\n        } catch {\n          addToast(intl.formatMessage(messages.toastFailedCreate), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        }\n      }}\n    >\n      {({ handleSubmit, values, setFieldValue, errors, touched }) => {\n        return (\n          <Modal\n            backgroundClickable\n            onCancel={onCancel}\n            title={intl.formatMessage(messages.reportissue)}\n            subTitle={data && isMovie(data) ? data?.title : data?.name}\n            cancelText={intl.formatMessage(globalMessages.close)}\n            onOk={() => handleSubmit()}\n            okText={intl.formatMessage(messages.submitissue)}\n            loading={!data && !error}\n            backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}\n          >\n            {mediaType === 'tv' && data && !isMovie(data) && (\n              <>\n                <div className=\"form-row\">\n                  <label htmlFor=\"problemSeason\" className=\"text-label\">\n                    {intl.formatMessage(messages.problemseason)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"problemSeason\"\n                        name=\"problemSeason\"\n                        disabled={availableSeasons.length === 1}\n                      >\n                        {availableSeasons.length > 1 && (\n                          <option value={0}>\n                            {intl.formatMessage(messages.allseasons)}\n                          </option>\n                        )}\n                        {availableSeasons.map((season) => (\n                          <option\n                            value={season}\n                            key={`problem-season-${season}`}\n                          >\n                            {season === 0\n                              ? intl.formatMessage(messages.extras)\n                              : intl.formatMessage(messages.season, {\n                                  seasonNumber: season,\n                                })}\n                          </option>\n                        ))}\n                      </Field>\n                    </div>\n                  </div>\n                </div>\n                {values.problemSeason > 0 && (\n                  <div className=\"form-row mb-2\">\n                    <label htmlFor=\"problemEpisode\" className=\"text-label\">\n                      {intl.formatMessage(messages.problemepisode)}\n                      <span className=\"label-required\">*</span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <Field\n                          as=\"select\"\n                          id=\"problemEpisode\"\n                          name=\"problemEpisode\"\n                        >\n                          <option value={0}>\n                            {intl.formatMessage(messages.allepisodes)}\n                          </option>\n                          {[\n                            ...Array(\n                              data.seasons.find(\n                                (season) =>\n                                  Number(values.problemSeason) ===\n                                  season.seasonNumber\n                              )?.episodeCount ?? 0\n                            ),\n                          ].map((i, index) => (\n                            <option\n                              value={index + 1}\n                              key={`problem-episode-${index + 1}`}\n                            >\n                              {intl.formatMessage(messages.episode, {\n                                episodeNumber: index + 1,\n                              })}\n                            </option>\n                          ))}\n                        </Field>\n                      </div>\n                    </div>\n                  </div>\n                )}\n              </>\n            )}\n            <RadioGroup\n              value={values.selectedIssue}\n              onChange={(issue) => setFieldValue('selectedIssue', issue)}\n              className=\"mt-4\"\n            >\n              <RadioGroup.Label className=\"sr-only\">\n                Select an Issue\n              </RadioGroup.Label>\n              <div className=\"-space-y-px overflow-hidden rounded-md bg-gray-800/30\">\n                {issueOptions.map((setting, index) => (\n                  <RadioGroup.Option\n                    key={`issue-type-${setting.issueType}`}\n                    value={setting}\n                    className={({ checked }) =>\n                      classNames(\n                        index === 0 ? 'rounded-tl-md rounded-tr-md' : '',\n                        index === issueOptions.length - 1\n                          ? 'rounded-bl-md rounded-br-md'\n                          : '',\n                        checked\n                          ? 'z-10 border border-indigo-500 bg-indigo-400/20'\n                          : 'border-gray-500',\n                        'relative flex cursor-pointer border p-4 focus:outline-none'\n                      )\n                    }\n                  >\n                    {({ active, checked }) => (\n                      <>\n                        <span\n                          className={`${\n                            checked\n                              ? 'border-transparent bg-indigo-600'\n                              : 'border-gray-300 bg-white'\n                          } ${\n                            active ? 'ring-2 ring-indigo-300 ring-offset-2' : ''\n                          } mt-0.5 flex h-4 w-4 cursor-pointer items-center justify-center rounded-full border`}\n                          aria-hidden=\"true\"\n                        >\n                          <span className=\"h-1.5 w-1.5 rounded-full bg-white\" />\n                        </span>\n                        <div className=\"ml-3 flex flex-col\">\n                          <RadioGroup.Label\n                            as=\"span\"\n                            className={`block text-sm font-medium ${\n                              checked ? 'text-indigo-100' : 'text-gray-100'\n                            }`}\n                          >\n                            {intl.formatMessage(setting.name)}\n                          </RadioGroup.Label>\n                        </div>\n                      </>\n                    )}\n                  </RadioGroup.Option>\n                ))}\n              </div>\n            </RadioGroup>\n            <div className=\"mt-4 flex-col space-y-2\">\n              <label htmlFor=\"message\">\n                {intl.formatMessage(messages.whatswrong)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <Field\n                as=\"textarea\"\n                name=\"message\"\n                id=\"message\"\n                className=\"h-28\"\n                placeholder={intl.formatMessage(messages.providedetail)}\n              />\n              {errors.message &&\n                touched.message &&\n                typeof errors.message === 'string' && (\n                  <div className=\"error\">{errors.message}</div>\n                )}\n            </div>\n          </Modal>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default CreateIssueModal;\n"
  },
  {
    "path": "src/components/IssueModal/constants.ts",
    "content": "import defineMessages from '@app/utils/defineMessages';\nimport { IssueType } from '@server/constants/issue';\nimport type { MessageDescriptor } from 'react-intl';\n\nconst messages = defineMessages('components.IssueModal', {\n  issueAudio: 'Audio',\n  issueVideo: 'Video',\n  issueSubtitles: 'Subtitle',\n  issueOther: 'Other',\n});\n\ninterface IssueOption {\n  name: MessageDescriptor;\n  issueType: IssueType;\n  mediaType?: 'movie' | 'tv';\n}\n\nexport const issueOptions: IssueOption[] = [\n  {\n    name: messages.issueVideo,\n    issueType: IssueType.VIDEO,\n  },\n  {\n    name: messages.issueAudio,\n    issueType: IssueType.AUDIO,\n  },\n  {\n    name: messages.issueSubtitles,\n    issueType: IssueType.SUBTITLES,\n  },\n  {\n    name: messages.issueOther,\n    issueType: IssueType.OTHER,\n  },\n];\n"
  },
  {
    "path": "src/components/IssueModal/index.tsx",
    "content": "import CreateIssueModal from '@app/components/IssueModal/CreateIssueModal';\nimport { Transition } from '@headlessui/react';\n\ninterface IssueModalProps {\n  show?: boolean;\n  onCancel: () => void;\n  mediaType: 'movie' | 'tv';\n  tmdbId: number;\n  issueId?: never;\n}\n\nconst IssueModal = ({ show, mediaType, onCancel, tmdbId }: IssueModalProps) => (\n  <Transition\n    as=\"div\"\n    enter=\"transition-opacity duration-300\"\n    enterFrom=\"opacity-0\"\n    enterTo=\"opacity-100\"\n    leave=\"transition-opacity duration-300\"\n    leaveFrom=\"opacity-100\"\n    leaveTo=\"opacity-0\"\n    show={show}\n  >\n    <CreateIssueModal\n      mediaType={mediaType}\n      onCancel={onCancel}\n      tmdbId={tmdbId}\n    />\n  </Transition>\n);\n\nexport default IssueModal;\n"
  },
  {
    "path": "src/components/JSONEditor/index.tsx",
    "content": "import 'ace-builds/src-noconflict/ace';\nimport 'ace-builds/src-noconflict/mode-json';\nimport 'ace-builds/src-noconflict/theme-dracula';\nimport type { HTMLAttributes } from 'react';\nimport AceEditor from 'react-ace';\ninterface JSONEditorProps extends HTMLAttributes<HTMLDivElement> {\n  name: string;\n  value: string;\n  onUpdate: (value: string) => void;\n}\n\nconst JSONEditor = ({ name, value, onUpdate, onBlur }: JSONEditorProps) => {\n  return (\n    <div className=\"w-full overflow-hidden rounded-md\">\n      <AceEditor\n        mode=\"json\"\n        theme=\"dracula\"\n        onChange={onUpdate}\n        name={name}\n        editorProps={{ $blockScrolling: true }}\n        value={value}\n        onBlur={onBlur}\n        height=\"300px\"\n        width=\"100%\"\n      />\n    </div>\n  );\n};\n\nexport default JSONEditor;\n"
  },
  {
    "path": "src/components/KeywordTag/index.tsx",
    "content": "import Spinner from '@app/assets/spinner.svg';\nimport Tag from '@app/components/Common/Tag';\nimport type { Keyword } from '@server/models/common';\nimport useSWR from 'swr';\n\ntype KeywordTagProps = {\n  keywordId: number;\n};\n\nconst KeywordTag = ({ keywordId }: KeywordTagProps) => {\n  const { data, error } = useSWR<Keyword>(`/api/v1/keyword/${keywordId}`);\n\n  if (!data && !error) {\n    return (\n      <Tag>\n        <Spinner className=\"h-4 w-4\" />\n      </Tag>\n    );\n  }\n\n  return <Tag>{data?.name}</Tag>;\n};\n\nexport default KeywordTag;\n"
  },
  {
    "path": "src/components/LanguageSelector/index.tsx",
    "content": "import globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { Language } from '@server/lib/settings';\nimport { sortBy } from 'lodash';\nimport { useMemo } from 'react';\nimport { useIntl } from 'react-intl';\nimport type { CSSObjectWithLabel } from 'react-select';\nimport Select from 'react-select';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.LanguageSelector', {\n  originalLanguageDefault: 'All Languages',\n  languageServerDefault: 'Default ({language})',\n});\n\ntype OptionType = {\n  value: string;\n  label: string;\n  isFixed?: boolean;\n};\n\nconst selectStyles = {\n  multiValueLabel: (base: CSSObjectWithLabel, props: { data: OptionType }) => {\n    return props.data?.isFixed ? { ...base, paddingRight: 6 } : base;\n  },\n  multiValueRemove: (base: CSSObjectWithLabel, props: { data: OptionType }) => {\n    return props.data?.isFixed ? { ...base, display: 'none' } : base;\n  },\n};\n\ninterface LanguageSelectorProps {\n  value?: string;\n  setFieldValue: (property: string, value: string) => void;\n  serverValue?: string;\n  isUserSettings?: boolean;\n  isDisabled?: boolean;\n}\n\nconst LanguageSelector = ({\n  value,\n  setFieldValue,\n  serverValue,\n  isUserSettings = false,\n  isDisabled,\n}: LanguageSelectorProps) => {\n  const intl = useIntl();\n  const { data: languages } = useSWR<Language[]>('/api/v1/languages');\n\n  const sortedLanguages = useMemo(() => {\n    languages?.forEach((language) => {\n      language.name =\n        intl.formatDisplayName(language.iso_639_1, {\n          type: 'language',\n          fallback: 'none',\n        }) ?? language.english_name;\n    });\n\n    return sortBy(languages, 'name');\n  }, [intl, languages]);\n\n  const languageName = (languageCode: string) =>\n    sortedLanguages?.find((language) => language.iso_639_1 === languageCode)\n      ?.name ?? languageCode;\n\n  const options: OptionType[] =\n    sortedLanguages?.map((language) => ({\n      label: language.name,\n      value: language.iso_639_1,\n    })) ?? [];\n\n  if (isUserSettings) {\n    options.unshift({\n      value: 'server',\n      label: intl.formatMessage(messages.languageServerDefault, {\n        language: serverValue\n          ? serverValue\n              .split('|')\n              .map((value) => languageName(value))\n              .reduce((prev, curr) =>\n                intl.formatMessage(globalMessages.delimitedlist, {\n                  a: prev,\n                  b: curr,\n                })\n              )\n          : intl.formatMessage(messages.originalLanguageDefault),\n      }),\n      isFixed: true,\n    });\n  }\n\n  options.unshift({\n    value: 'all',\n    label: intl.formatMessage(messages.originalLanguageDefault),\n    isFixed: true,\n  });\n\n  return (\n    <Select<OptionType, true>\n      options={options}\n      isMulti\n      isDisabled={isDisabled}\n      className=\"react-select-container\"\n      classNamePrefix=\"react-select\"\n      value={\n        (isUserSettings && value === 'all') || (!isUserSettings && !value)\n          ? {\n              value: 'all',\n              label: intl.formatMessage(messages.originalLanguageDefault),\n              isFixed: true,\n            }\n          : (value === '' || !value || value === 'server') && isUserSettings\n            ? {\n                value: 'server',\n                label: intl.formatMessage(messages.languageServerDefault, {\n                  language: serverValue\n                    ? serverValue\n                        .split('|')\n                        .map((value) => languageName(value))\n                        .reduce((prev, curr) =>\n                          intl.formatMessage(globalMessages.delimitedlist, {\n                            a: prev,\n                            b: curr,\n                          })\n                        )\n                    : intl.formatMessage(messages.originalLanguageDefault),\n                }),\n                isFixed: true,\n              }\n            : (value\n                ?.split('|')\n                .map((code) => {\n                  const matchedLanguage = sortedLanguages?.find(\n                    (lang) => lang.iso_639_1 === code\n                  );\n\n                  if (!matchedLanguage) {\n                    return undefined;\n                  }\n\n                  return {\n                    label: matchedLanguage.name,\n                    value: matchedLanguage.iso_639_1,\n                  };\n                })\n                .filter((option) => option !== undefined) as OptionType[])\n      }\n      onChange={(value, options) => {\n        if (\n          (options &&\n            options.action === 'select-option' &&\n            options.option?.value === 'server') ||\n          value.every((v) => v.value === 'server')\n        ) {\n          return setFieldValue('originalLanguage', '');\n        }\n\n        if (\n          (options &&\n            options.action === 'select-option' &&\n            options.option?.value === 'all') ||\n          value.every((v) => v.value === 'all')\n        ) {\n          return setFieldValue('originalLanguage', isUserSettings ? 'all' : '');\n        }\n\n        setFieldValue(\n          'originalLanguage',\n          value\n            .map((lang) => lang.value)\n            .filter((v) => v !== 'all')\n            .join('|')\n        );\n      }}\n      styles={selectStyles}\n    />\n  );\n};\n\nexport default LanguageSelector;\n"
  },
  {
    "path": "src/components/Layout/LanguagePicker/index.tsx",
    "content": "import { availableLanguages } from '@app/context/LanguageContext';\nimport useClickOutside from '@app/hooks/useClickOutside';\nimport useLocale from '@app/hooks/useLocale';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport { LanguageIcon } from '@heroicons/react/24/solid';\nimport type { AvailableLocale } from '@server/types/languages';\nimport { useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Layout.LanguagePicker', {\n  displaylanguage: 'Display Language',\n});\n\nconst LanguagePicker = () => {\n  const intl = useIntl();\n  const dropdownRef = useRef<HTMLDivElement>(null);\n  const { locale, setLocale } = useLocale();\n  const [isDropdownOpen, setDropdownOpen] = useState(false);\n  useClickOutside(dropdownRef, () => setDropdownOpen(false));\n\n  return (\n    <div className=\"relative\">\n      <div>\n        <button\n          className={`rounded-full p-1 hover:bg-gray-600 hover:text-white focus:bg-gray-600 focus:text-white focus:outline-none focus:ring-1 focus:ring-gray-500 sm:p-2 ${\n            isDropdownOpen ? 'bg-gray-600 text-white' : 'text-gray-400'\n          }`}\n          aria-label=\"Language Picker\"\n          onClick={() => setDropdownOpen(true)}\n        >\n          <LanguageIcon className=\"h-6 w-6\" />\n        </button>\n      </div>\n      <Transition\n        as=\"div\"\n        show={isDropdownOpen}\n        enter=\"transition ease-out duration-100\"\n        enterFrom=\"opacity-0 scale-95\"\n        enterTo=\"opacity-100 scale-100\"\n        leave=\"transition ease-in duration-75\"\n        leaveFrom=\"opacity-100 scale-100\"\n        leaveTo=\"opacity-0 scale-95\"\n      >\n        <div\n          className=\"absolute right-0 mt-2 w-56 origin-top-right rounded-md shadow-lg\"\n          ref={dropdownRef}\n        >\n          <div className=\"rounded-md bg-gray-700 px-3 py-2 ring-1 ring-black ring-opacity-5\">\n            <div>\n              <label\n                htmlFor=\"language\"\n                className=\"block pb-2 text-sm font-bold leading-5 text-gray-300\"\n              >\n                {intl.formatMessage(messages.displaylanguage)}\n              </label>\n              <select\n                id=\"language\"\n                className=\"rounded-md\"\n                onChange={(e) =>\n                  setLocale && setLocale(e.target.value as AvailableLocale)\n                }\n                onBlur={(e) =>\n                  setLocale && setLocale(e.target.value as AvailableLocale)\n                }\n                defaultValue={locale}\n              >\n                {(\n                  Object.keys(\n                    availableLanguages\n                  ) as (keyof typeof availableLanguages)[]\n                ).map((key) => (\n                  <option key={key} value={availableLanguages[key].code}>\n                    {availableLanguages[key].display}\n                  </option>\n                ))}\n              </select>\n            </div>\n          </div>\n        </div>\n      </Transition>\n    </div>\n  );\n};\n\nexport default LanguagePicker;\n"
  },
  {
    "path": "src/components/Layout/MobileMenu/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport { menuMessages } from '@app/components/Layout/Sidebar';\nimport useClickOutside from '@app/hooks/useClickOutside';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport { Transition } from '@headlessui/react';\nimport {\n  ClockIcon,\n  CogIcon,\n  EllipsisHorizontalIcon,\n  ExclamationTriangleIcon,\n  EyeSlashIcon,\n  FilmIcon,\n  SparklesIcon,\n  TvIcon,\n  UsersIcon,\n} from '@heroicons/react/24/outline';\nimport {\n  ClockIcon as FilledClockIcon,\n  CogIcon as FilledCogIcon,\n  ExclamationTriangleIcon as FilledExclamationTriangleIcon,\n  EyeSlashIcon as FilledEyeSlashIcon,\n  FilmIcon as FilledFilmIcon,\n  SparklesIcon as FilledSparklesIcon,\n  TvIcon as FilledTvIcon,\n  UsersIcon as FilledUsersIcon,\n  XMarkIcon,\n} from '@heroicons/react/24/solid';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { cloneElement, useEffect, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\ninterface MobileMenuProps {\n  pendingRequestsCount: number;\n  openIssuesCount: number;\n  revalidateIssueCount: () => void;\n  revalidateRequestsCount: () => void;\n}\n\ninterface MenuLink {\n  href: string;\n  svgIcon: JSX.Element;\n  svgIconSelected: JSX.Element;\n  content: React.ReactNode;\n  activeRegExp: RegExp;\n  as?: string;\n  requiredPermission?: Permission | Permission[];\n  permissionType?: 'and' | 'or';\n  dataTestId?: string;\n}\n\nconst MobileMenu = ({\n  pendingRequestsCount,\n  openIssuesCount,\n  revalidateIssueCount,\n  revalidateRequestsCount,\n}: MobileMenuProps) => {\n  const ref = useRef<HTMLDivElement>(null);\n  const intl = useIntl();\n  const [isOpen, setIsOpen] = useState(false);\n  const { hasPermission } = useUser();\n  const router = useRouter();\n  useClickOutside(ref, () => {\n    setTimeout(() => {\n      if (isOpen) {\n        setIsOpen(false);\n      }\n    }, 150);\n  });\n\n  const toggle = () => setIsOpen(!isOpen);\n\n  const menuLinks: MenuLink[] = [\n    {\n      href: '/',\n      content: intl.formatMessage(menuMessages.dashboard),\n      svgIcon: <SparklesIcon className=\"h-6 w-6\" />,\n      svgIconSelected: <FilledSparklesIcon className=\"h-6 w-6\" />,\n      activeRegExp: /^\\/(discover\\/?)?$/,\n    },\n    {\n      href: '/discover/movies',\n      content: intl.formatMessage(menuMessages.browsemovies),\n      svgIcon: <FilmIcon className=\"h-6 w-6\" />,\n      svgIconSelected: <FilledFilmIcon className=\"h-6 w-6\" />,\n      activeRegExp: /^\\/discover\\/movies$/,\n    },\n    {\n      href: '/discover/tv',\n      content: intl.formatMessage(menuMessages.browsetv),\n      svgIcon: <TvIcon className=\"h-6 w-6\" />,\n      svgIconSelected: <FilledTvIcon className=\"h-6 w-6\" />,\n      activeRegExp: /^\\/discover\\/tv$/,\n    },\n    {\n      href: '/requests',\n      content: intl.formatMessage(menuMessages.requests),\n      svgIcon: <ClockIcon className=\"h-6 w-6\" />,\n      svgIconSelected: <FilledClockIcon className=\"h-6 w-6\" />,\n      activeRegExp: /^\\/requests/,\n    },\n    {\n      href: '/blocklist',\n      content: intl.formatMessage(menuMessages.blocklist),\n      svgIcon: <EyeSlashIcon className=\"h-6 w-6\" />,\n      svgIconSelected: <FilledEyeSlashIcon className=\"h-6 w-6\" />,\n      activeRegExp: /^\\/blocklist/,\n      requiredPermission: [\n        Permission.MANAGE_BLOCKLIST,\n        Permission.VIEW_BLOCKLIST,\n      ],\n      permissionType: 'or',\n    },\n    {\n      href: '/issues',\n      content: intl.formatMessage(menuMessages.issues),\n      svgIcon: <ExclamationTriangleIcon className=\"h-6 w-6\" />,\n      svgIconSelected: <FilledExclamationTriangleIcon className=\"h-6 w-6\" />,\n      activeRegExp: /^\\/issues/,\n      requiredPermission: [\n        Permission.MANAGE_ISSUES,\n        Permission.CREATE_ISSUES,\n        Permission.VIEW_ISSUES,\n      ],\n      permissionType: 'or',\n    },\n    {\n      href: '/users',\n      content: intl.formatMessage(menuMessages.users),\n      svgIcon: <UsersIcon className=\"mr-3 h-6 w-6\" />,\n      svgIconSelected: <FilledUsersIcon className=\"mr-3 h-6 w-6\" />,\n      activeRegExp: /^\\/users/,\n      requiredPermission: Permission.MANAGE_USERS,\n      dataTestId: 'sidebar-menu-users',\n    },\n    {\n      href: '/settings',\n      content: intl.formatMessage(menuMessages.settings),\n      svgIcon: <CogIcon className=\"mr-3 h-6 w-6\" />,\n      svgIconSelected: <FilledCogIcon className=\"mr-3 h-6 w-6\" />,\n      activeRegExp: /^\\/settings/,\n      requiredPermission: Permission.ADMIN,\n      dataTestId: 'sidebar-menu-settings',\n    },\n  ];\n\n  const filteredLinks = menuLinks.filter(\n    (link) =>\n      !link.requiredPermission ||\n      hasPermission(link.requiredPermission, {\n        type: link.permissionType ?? 'and',\n      })\n  );\n\n  useEffect(() => {\n    if (openIssuesCount) {\n      revalidateIssueCount();\n    }\n\n    if (pendingRequestsCount) {\n      revalidateRequestsCount();\n    }\n  }, [\n    revalidateIssueCount,\n    revalidateRequestsCount,\n    pendingRequestsCount,\n    openIssuesCount,\n  ]);\n\n  return (\n    <div className=\"fixed bottom-0 left-0 right-0 z-50\">\n      <Transition\n        show={isOpen}\n        as=\"div\"\n        ref={ref}\n        enter=\"transition duration-500\"\n        enterFrom=\"opacity-0 translate-y-0\"\n        enterTo=\"opacity-100 -translate-y-full\"\n        leave=\"transition duration-500\"\n        leaveFrom=\"opacity-100 -translate-y-full\"\n        leaveTo=\"opacity-0 translate-y-0\"\n        className=\"absolute left-0 right-0 top-0 flex w-full -translate-y-full flex-col space-y-6 border-t border-gray-600 bg-gray-900/90 px-6 py-6 font-semibold text-gray-100 backdrop-blur\"\n      >\n        {filteredLinks.map((link) => {\n          const isActive = router.pathname.match(link.activeRegExp);\n          return (\n            <Link\n              key={`mobile-menu-link-${link.href}`}\n              href={link.href}\n              className={`flex items-center ${\n                isActive ? 'text-indigo-500' : ''\n              }`}\n              onKeyDown={(e) => {\n                if (e.key === 'Enter') {\n                  setIsOpen(false);\n                }\n              }}\n              onClick={() => setIsOpen(false)}\n              role=\"button\"\n              tabIndex={0}\n            >\n              {cloneElement(isActive ? link.svgIconSelected : link.svgIcon, {\n                className: 'h-5 w-5',\n              })}\n              <span className=\"ml-2\">{link.content}</span>\n              {link.href === '/requests' &&\n                pendingRequestsCount > 0 &&\n                hasPermission(Permission.MANAGE_REQUESTS) && (\n                  <div className=\"ml-auto flex\">\n                    <Badge className=\"rounded-md border-indigo-500 bg-gradient-to-br from-indigo-600 to-purple-600\">\n                      {pendingRequestsCount}\n                    </Badge>\n                  </div>\n                )}\n              {link.href === '/issues' &&\n                openIssuesCount > 0 &&\n                hasPermission(Permission.MANAGE_ISSUES) && (\n                  <div className=\"ml-auto flex\">\n                    <Badge className=\"rounded-md border-indigo-500 bg-gradient-to-br from-indigo-600 to-purple-600\">\n                      {openIssuesCount}\n                    </Badge>\n                  </div>\n                )}\n            </Link>\n          );\n        })}\n      </Transition>\n      <div className=\"padding-bottom-safe border-t border-gray-600 bg-gray-800/90 backdrop-blur\">\n        <div className=\"flex h-full items-center justify-between px-6 py-4 text-gray-100\">\n          {filteredLinks\n            .slice(0, filteredLinks.length === 5 ? 5 : 4)\n            .map((link) => {\n              const isActive =\n                router.pathname.match(link.activeRegExp) && !isOpen;\n              return (\n                <Link\n                  key={`mobile-menu-link-${link.href}`}\n                  href={link.href}\n                  className={`relative flex flex-col items-center space-y-1 ${\n                    isActive ? 'text-indigo-500' : ''\n                  }`}\n                >\n                  {cloneElement(\n                    isActive ? link.svgIconSelected : link.svgIcon,\n                    {\n                      className: 'h-6 w-6',\n                    }\n                  )}\n                  {link.href === '/requests' &&\n                    pendingRequestsCount > 0 &&\n                    hasPermission(Permission.MANAGE_REQUESTS) && (\n                      <div className=\"absolute bottom-3 left-3\">\n                        <Badge\n                          className={`bg-gradient-to-br ${\n                            router.pathname.match(link.activeRegExp)\n                              ? 'border-indigo-600 from-indigo-700 to-purple-700'\n                              : 'border-indigo-500 from-indigo-600 to-purple-600'\n                          } flex ${\n                            pendingRequestsCount > 99 ? 'w-6' : 'w-4'\n                          } h-4 items-center justify-center !px-[5px] !py-[7px] text-[8px]`}\n                        >\n                          {pendingRequestsCount > 99\n                            ? '99+'\n                            : pendingRequestsCount}\n                        </Badge>\n                      </div>\n                    )}\n                </Link>\n              );\n            })}\n          {filteredLinks.length > 4 && filteredLinks.length !== 5 && (\n            <button\n              className={`flex flex-col items-center space-y-1 ${\n                isOpen ? 'text-indigo-500' : ''\n              }`}\n              onClick={() => toggle()}\n            >\n              {isOpen ? (\n                <XMarkIcon className=\"h-6 w-6\" />\n              ) : (\n                <EllipsisHorizontalIcon className=\"h-6 w-6\" />\n              )}\n            </button>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default MobileMenu;\n"
  },
  {
    "path": "src/components/Layout/Notifications/index.tsx",
    "content": "import { BellIcon } from '@heroicons/react/24/outline';\n\nconst Notifications = () => {\n  return (\n    <button\n      className=\"rounded-full p-1 text-gray-400 hover:bg-gray-500 hover:text-white focus:text-white focus:outline-none focus:ring\"\n      aria-label=\"Notifications\"\n    >\n      <BellIcon className=\"h-6 w-6\" />\n    </button>\n  );\n};\n\nexport default Notifications;\n"
  },
  {
    "path": "src/components/Layout/PullToRefresh/index.tsx",
    "content": "import { ArrowPathIcon } from '@heroicons/react/24/outline';\nimport { useRouter } from 'next/router';\nimport { useEffect, useRef, useState } from 'react';\n\nconst PullToRefresh = () => {\n  const router = useRouter();\n  const [pullStartPoint, setPullStartPoint] = useState(0);\n  const [pullChange, setPullChange] = useState(0);\n  const refreshDiv = useRef<HTMLDivElement>(null);\n\n  // Various pull down thresholds that determine icon location\n  const pullDownInitThreshold = pullChange > 20;\n  const pullDownStopThreshold = 120;\n  const pullDownReloadThreshold = pullChange > 340;\n  const pullDownIconLocation = pullChange / 3;\n\n  useEffect(() => {\n    // Reload function that is called when reload threshold has been hit\n    // Add loading class to determine when to add spin animation\n    const forceReload = () => {\n      setPullStartPoint(0);\n      refreshDiv.current?.classList.add('loading');\n      setTimeout(() => {\n        router.reload();\n      }, 1000);\n    };\n\n    const html = document.querySelector('html');\n\n    // Determines if we are at the top of the page\n    // Locks or unlocks page when pulling down to refresh\n    const pullStart = (e: TouchEvent) => {\n      setPullStartPoint(e.targetTouches[0].screenY);\n\n      const html = document.querySelector('html');\n\n      if (window.scrollY === 0 && window.scrollX === 0) {\n        refreshDiv.current?.classList.add('block');\n        refreshDiv.current?.classList.remove('hidden');\n        document.body.style.touchAction = 'none';\n        document.body.style.overscrollBehavior = 'none';\n        if (html) {\n          html.style.overscrollBehaviorY = 'none';\n        }\n      } else {\n        setPullStartPoint(0);\n        refreshDiv.current?.classList.remove('block');\n        refreshDiv.current?.classList.add('hidden');\n      }\n    };\n\n    // Tracks how far we have pulled down the refresh icon\n    const pullDown = async (e: TouchEvent) => {\n      const screenY = e.targetTouches[0].screenY;\n      const pullLength =\n        pullStartPoint < screenY ? Math.abs(screenY - pullStartPoint) : 0;\n\n      setPullChange(pullLength);\n    };\n\n    // Will reload the page if we are past the threshold\n    // Otherwise, we reset the pull\n    const pullFinish = () => {\n      if (pullDownReloadThreshold && pullStartPoint !== 0) {\n        forceReload();\n      } else {\n        setPullChange(0);\n        setTimeout(() => setPullStartPoint(0), 200);\n      }\n\n      document.body.style.touchAction = 'auto';\n      document.body.style.overscrollBehaviorY = 'auto';\n      if (html) {\n        html.style.overscrollBehaviorY = 'auto';\n      }\n    };\n\n    window.addEventListener('touchstart', pullStart, { passive: false });\n    window.addEventListener('touchmove', pullDown, { passive: false });\n    window.addEventListener('touchend', pullFinish, { passive: false });\n\n    return () => {\n      window.removeEventListener('touchstart', pullStart);\n      window.removeEventListener('touchmove', pullDown);\n      window.removeEventListener('touchend', pullFinish);\n    };\n  }, [\n    pullDownInitThreshold,\n    pullDownReloadThreshold,\n    pullStartPoint,\n    refreshDiv,\n    router,\n    setPullStartPoint,\n  ]);\n\n  if (\n    pullStartPoint === 0 &&\n    !refreshDiv.current?.classList.contains('loading')\n  ) {\n    return null;\n  }\n\n  return (\n    <div\n      ref={refreshDiv}\n      className=\"absolute left-0 right-0 top-0 z-50 m-auto w-fit transition-all ease-out\"\n      id=\"refreshIcon\"\n      style={{\n        top:\n          pullDownIconLocation < pullDownStopThreshold && pullDownInitThreshold\n            ? pullDownIconLocation\n            : pullDownInitThreshold\n              ? pullDownStopThreshold\n              : '',\n      }}\n    >\n      <div\n        className={`${\n          refreshDiv.current?.classList.contains('loading') && 'animate-spin'\n        } relative -top-28 h-9 w-9 rounded-full border-4 border-gray-800 bg-gray-800 shadow-md shadow-black ring-1 ring-gray-700`}\n        style={{ animationDirection: 'reverse' }}\n      >\n        <ArrowPathIcon\n          className={`rounded-full ${\n            pullDownReloadThreshold && 'rotate-180'\n          } text-indigo-500 transition-all duration-300`}\n        />\n      </div>\n    </div>\n  );\n};\n\nexport default PullToRefresh;\n"
  },
  {
    "path": "src/components/Layout/SearchInput/index.tsx",
    "content": "import useSearchInput from '@app/hooks/useSearchInput';\nimport defineMessages from '@app/utils/defineMessages';\nimport { XCircleIcon } from '@heroicons/react/24/outline';\nimport { MagnifyingGlassIcon } from '@heroicons/react/24/solid';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Layout.SearchInput', {\n  searchPlaceholder: 'Search Movies & TV',\n});\n\nconst SearchInput = () => {\n  const intl = useIntl();\n  const { searchValue, setSearchValue, setIsOpen, clear } = useSearchInput();\n  return (\n    <div className=\"flex flex-1\">\n      <div className=\"flex w-full\">\n        <label htmlFor=\"search_field\" className=\"sr-only\">\n          Search\n        </label>\n        <div className=\"relative flex w-full items-center text-white focus-within:text-gray-200\">\n          <div className=\"pointer-events-none absolute inset-y-0 left-4 flex items-center\">\n            <MagnifyingGlassIcon className=\"h-5 w-5\" />\n          </div>\n          <input\n            id=\"search_field\"\n            style={{ paddingRight: searchValue.length > 0 ? '1.75rem' : '' }}\n            className=\"block w-full rounded-full border border-gray-600 bg-gray-900/80 py-2 pl-10 text-white placeholder-gray-300 hover:border-gray-500 focus:border-gray-500 focus:bg-gray-900 focus:placeholder-gray-400 focus:outline-none focus:ring-0 sm:text-base\"\n            placeholder={intl.formatMessage(messages.searchPlaceholder)}\n            type=\"search\"\n            autoComplete=\"off\"\n            value={searchValue}\n            onChange={(e) => setSearchValue(e.target.value)}\n            onFocus={() => setIsOpen(true)}\n            onBlur={() => {\n              if (searchValue === '') {\n                setIsOpen(false);\n              }\n            }}\n            onKeyUp={(e) => {\n              if (e.key === 'Enter') {\n                e.preventDefault();\n                (e.target as HTMLInputElement).blur();\n              }\n            }}\n          />\n          {searchValue.length > 0 && (\n            <button\n              className=\"absolute inset-y-0 right-2 m-auto h-7 w-7 border-none p-1 text-gray-400 outline-none transition hover:text-white focus:border-none focus:outline-none\"\n              onClick={() => clear()}\n            >\n              <XCircleIcon className=\"h-5 w-5\" />\n            </button>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default SearchInput;\n"
  },
  {
    "path": "src/components/Layout/Sidebar/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport UserWarnings from '@app/components/Layout/UserWarnings';\nimport VersionStatus from '@app/components/Layout/VersionStatus';\nimport useClickOutside from '@app/hooks/useClickOutside';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport {\n  ClockIcon,\n  CogIcon,\n  ExclamationTriangleIcon,\n  EyeSlashIcon,\n  FilmIcon,\n  SparklesIcon,\n  TvIcon,\n  UsersIcon,\n  XMarkIcon,\n} from '@heroicons/react/24/outline';\nimport Image from 'next/image';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { Fragment, useEffect, useRef } from 'react';\nimport { useIntl } from 'react-intl';\n\nexport const menuMessages = defineMessages('components.Layout.Sidebar', {\n  dashboard: 'Discover',\n  browsemovies: 'Movies',\n  browsetv: 'Series',\n  requests: 'Requests',\n  blocklist: 'Blocklist',\n  issues: 'Issues',\n  users: 'Users',\n  settings: 'Settings',\n});\n\ninterface SidebarProps {\n  open?: boolean;\n  setClosed: () => void;\n  pendingRequestsCount: number;\n  openIssuesCount: number;\n  revalidateIssueCount: () => void;\n  revalidateRequestsCount: () => void;\n}\n\ninterface SidebarLinkProps {\n  href: string;\n  svgIcon: React.ReactNode;\n  messagesKey: keyof typeof menuMessages;\n  activeRegExp: RegExp;\n  as?: string;\n  requiredPermission?: Permission | Permission[];\n  permissionType?: 'and' | 'or';\n  dataTestId?: string;\n}\n\nconst SidebarLinks: SidebarLinkProps[] = [\n  {\n    href: '/',\n    messagesKey: 'dashboard',\n    svgIcon: <SparklesIcon className=\"mr-3 h-6 w-6\" />,\n    activeRegExp: /^\\/(discover\\/?)?$/,\n  },\n  {\n    href: '/discover/movies',\n    messagesKey: 'browsemovies',\n    svgIcon: <FilmIcon className=\"mr-3 h-6 w-6\" />,\n    activeRegExp: /^\\/discover\\/movies$/,\n  },\n  {\n    href: '/discover/tv',\n    messagesKey: 'browsetv',\n    svgIcon: <TvIcon className=\"mr-3 h-6 w-6\" />,\n    activeRegExp: /^\\/discover\\/tv$/,\n  },\n  {\n    href: '/requests',\n    messagesKey: 'requests',\n    svgIcon: <ClockIcon className=\"mr-3 h-6 w-6\" />,\n    activeRegExp: /^\\/requests/,\n  },\n  {\n    href: '/blocklist',\n    messagesKey: 'blocklist',\n    svgIcon: <EyeSlashIcon className=\"mr-3 h-6 w-6\" />,\n    activeRegExp: /^\\/blocklist/,\n    requiredPermission: [\n      Permission.MANAGE_BLOCKLIST,\n      Permission.VIEW_BLOCKLIST,\n    ],\n    permissionType: 'or',\n  },\n  {\n    href: '/issues',\n    messagesKey: 'issues',\n    svgIcon: <ExclamationTriangleIcon className=\"mr-3 h-6 w-6\" />,\n    activeRegExp: /^\\/issues/,\n    requiredPermission: [\n      Permission.MANAGE_ISSUES,\n      Permission.CREATE_ISSUES,\n      Permission.VIEW_ISSUES,\n    ],\n    permissionType: 'or',\n  },\n  {\n    href: '/users',\n    messagesKey: 'users',\n    svgIcon: <UsersIcon className=\"mr-3 h-6 w-6\" />,\n    activeRegExp: /^\\/users/,\n    requiredPermission: Permission.MANAGE_USERS,\n    dataTestId: 'sidebar-menu-users',\n  },\n  {\n    href: '/settings',\n    messagesKey: 'settings',\n    svgIcon: <CogIcon className=\"mr-3 h-6 w-6\" />,\n    activeRegExp: /^\\/settings/,\n    requiredPermission: Permission.ADMIN,\n    dataTestId: 'sidebar-menu-settings',\n  },\n];\n\nconst Sidebar = ({\n  open,\n  setClosed,\n  pendingRequestsCount,\n  openIssuesCount,\n  revalidateIssueCount,\n  revalidateRequestsCount,\n}: SidebarProps) => {\n  const navRef = useRef<HTMLDivElement>(null);\n  const router = useRouter();\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n  useClickOutside(navRef, () => setClosed());\n\n  useEffect(() => {\n    if (openIssuesCount) {\n      revalidateIssueCount();\n    }\n\n    if (pendingRequestsCount) {\n      revalidateRequestsCount();\n    }\n  }, [\n    revalidateIssueCount,\n    revalidateRequestsCount,\n    pendingRequestsCount,\n    openIssuesCount,\n  ]);\n\n  return (\n    <>\n      <div className=\"lg:hidden\">\n        <Transition as={Fragment} show={open}>\n          <div className=\"fixed inset-0 z-40 flex\">\n            <Transition.Child\n              as=\"div\"\n              enter=\"transition-opacity ease-linear duration-300\"\n              enterFrom=\"opacity-0\"\n              enterTo=\"opacity-100\"\n              leave=\"transition-opacity ease-linear duration-300\"\n              leaveFrom=\"opacity-100\"\n              leaveTo=\"opacity-0\"\n            >\n              <div className=\"fixed inset-0\">\n                <div className=\"absolute inset-0 bg-gray-900 opacity-90\" />\n              </div>\n            </Transition.Child>\n            <Transition.Child\n              as=\"div\"\n              enter=\"transition-transform ease-in-out duration-300\"\n              enterFrom=\"-translate-x-full\"\n              enterTo=\"translate-x-0\"\n              leave=\"transition-transform ease-in-out duration-300\"\n              leaveFrom=\"translate-x-0\"\n              leaveTo=\"-translate-x-full\"\n            >\n              <>\n                <div className=\"sidebar relative flex h-full w-full max-w-xs flex-1 flex-col bg-gray-800\">\n                  <div className=\"sidebar-close-button absolute right-0 -mr-14 p-1\">\n                    <button\n                      className=\"flex h-12 w-12 items-center justify-center rounded-full focus:bg-gray-600 focus:outline-none\"\n                      aria-label=\"Close sidebar\"\n                      onClick={() => setClosed()}\n                    >\n                      <XMarkIcon className=\"h-6 w-6 text-white\" />\n                    </button>\n                  </div>\n                  <div\n                    ref={navRef}\n                    className=\"flex flex-1 flex-col overflow-y-auto pb-8 pt-4 sm:pb-4\"\n                  >\n                    <div className=\"flex flex-shrink-0 items-center px-2\">\n                      <span className=\"w-full px-4 text-xl text-gray-50\">\n                        <Link href=\"/\" className=\"relative block h-24 w-64\">\n                          <Image src=\"/logo_full.svg\" alt=\"Logo\" fill />\n                        </Link>\n                      </span>\n                    </div>\n                    <nav className=\"mt-10 flex-1 space-y-4 px-4\">\n                      {SidebarLinks.filter((link) =>\n                        link.requiredPermission\n                          ? hasPermission(link.requiredPermission, {\n                              type: link.permissionType ?? 'and',\n                            })\n                          : true\n                      ).map((sidebarLink) => {\n                        return (\n                          <Link\n                            key={`mobile-${sidebarLink.messagesKey}`}\n                            href={sidebarLink.href}\n                            as={sidebarLink.as}\n                            onClick={() => setClosed()}\n                            onKeyDown={(e) => {\n                              if (e.key === 'Enter') {\n                                setClosed();\n                              }\n                            }}\n                            role=\"button\"\n                            tabIndex={0}\n                            className={`flex items-center rounded-md px-2 py-2 text-base font-medium leading-6 text-white transition duration-150 ease-in-out focus:outline-none ${\n                              router.pathname.match(sidebarLink.activeRegExp)\n                                ? 'bg-gradient-to-br from-indigo-600 to-purple-600 hover:from-indigo-500 hover:to-purple-500'\n                                : 'hover:bg-gray-700 focus:bg-gray-700'\n                            } `}\n                            data-testid={`${sidebarLink.dataTestId}-mobile`}\n                          >\n                            {sidebarLink.svgIcon}\n                            {intl.formatMessage(\n                              menuMessages[sidebarLink.messagesKey]\n                            )}\n                          </Link>\n                        );\n                      })}\n                    </nav>\n                    <div className=\"px-2\">\n                      <UserWarnings onClick={() => setClosed()} />\n                    </div>\n\n                    {hasPermission(Permission.ADMIN) && (\n                      <div className=\"px-2\">\n                        <VersionStatus onClick={() => setClosed()} />\n                      </div>\n                    )}\n                  </div>\n                </div>\n                <div className=\"w-14 flex-shrink-0\">\n                  {/* <!-- Force sidebar to shrink to fit close icon --> */}\n                </div>\n              </>\n            </Transition.Child>\n          </div>\n        </Transition>\n      </div>\n\n      <div className=\"fixed bottom-0 left-0 top-0 z-30 hidden lg:flex lg:flex-shrink-0\">\n        <div className=\"sidebar flex w-64 flex-col\">\n          <div className=\"flex h-0 flex-1 flex-col\">\n            <div className=\"flex flex-1 flex-col overflow-y-auto pb-4\">\n              <div className=\"flex flex-shrink-0 items-center\">\n                <span className=\"w-full px-4 py-2 text-2xl text-gray-50\">\n                  <Link href=\"/\" className=\"relative block h-24\">\n                    <Image src=\"/logo_full.svg\" alt=\"Logo\" fill />\n                  </Link>\n                </span>\n              </div>\n              <nav className=\"mt-8 flex-1 space-y-4 px-4\">\n                {SidebarLinks.filter((link) =>\n                  link.requiredPermission\n                    ? hasPermission(link.requiredPermission, {\n                        type: link.permissionType ?? 'and',\n                      })\n                    : true\n                ).map((sidebarLink) => {\n                  return (\n                    <Link\n                      key={`desktop-${sidebarLink.messagesKey}`}\n                      href={sidebarLink.href}\n                      as={sidebarLink.as}\n                      className={`group flex items-center rounded-md px-2 py-2 text-lg font-medium leading-6 text-white transition duration-150 ease-in-out focus:outline-none ${\n                        router.pathname.match(sidebarLink.activeRegExp)\n                          ? 'bg-gradient-to-br from-indigo-600 to-purple-600 hover:from-indigo-500 hover:to-purple-500'\n                          : 'hover:bg-gray-700 focus:bg-gray-700'\n                      } `}\n                      data-testid={sidebarLink.dataTestId}\n                    >\n                      {sidebarLink.svgIcon}\n                      {intl.formatMessage(\n                        menuMessages[sidebarLink.messagesKey]\n                      )}\n                      {sidebarLink.messagesKey === 'requests' &&\n                        pendingRequestsCount > 0 &&\n                        hasPermission(Permission.MANAGE_REQUESTS) && (\n                          <div className=\"ml-auto flex\">\n                            <Badge\n                              className={`rounded-md bg-gradient-to-br ${\n                                router.pathname.match(sidebarLink.activeRegExp)\n                                  ? 'border-indigo-600 from-indigo-700 to-purple-700'\n                                  : 'border-indigo-500 from-indigo-600 to-purple-600'\n                              }`}\n                            >\n                              {pendingRequestsCount}\n                            </Badge>\n                          </div>\n                        )}\n                      {sidebarLink.messagesKey === 'issues' &&\n                        openIssuesCount > 0 &&\n                        hasPermission(Permission.MANAGE_ISSUES) && (\n                          <div className=\"ml-auto flex\">\n                            <Badge\n                              className={`rounded-md bg-gradient-to-br ${\n                                router.pathname.match(sidebarLink.activeRegExp)\n                                  ? 'border-indigo-600 from-indigo-700 to-purple-700'\n                                  : 'border-indigo-500 from-indigo-600 to-purple-600'\n                              }`}\n                            >\n                              {openIssuesCount}\n                            </Badge>\n                          </div>\n                        )}\n                    </Link>\n                  );\n                })}\n              </nav>\n              <div className=\"px-2\">\n                <UserWarnings />\n              </div>\n              {hasPermission(Permission.ADMIN) && (\n                <div className=\"px-2\">\n                  <VersionStatus />\n                </div>\n              )}\n            </div>\n          </div>\n        </div>\n      </div>\n    </>\n  );\n};\n\nexport default Sidebar;\n"
  },
  {
    "path": "src/components/Layout/UserDropdown/MiniQuotaDisplay/index.tsx",
    "content": "import InfinityIcon from '@app/assets/infinity.svg';\nimport { SmallLoadingSpinner } from '@app/components/Common/LoadingSpinner';\nimport ProgressCircle from '@app/components/Common/ProgressCircle';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { QuotaResponse } from '@server/interfaces/api/userInterfaces';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages(\n  'components.Layout.UserDropdown.MiniQuotaDisplay',\n  {\n    movierequests: 'Movie Requests',\n    seriesrequests: 'Series Requests',\n  }\n);\n\ntype MiniQuotaDisplayProps = {\n  userId: number;\n};\n\nconst MiniQuotaDisplay = ({ userId }: MiniQuotaDisplayProps) => {\n  const intl = useIntl();\n  const { data, error } = useSWR<QuotaResponse>(`/api/v1/user/${userId}/quota`);\n\n  if (error) {\n    return null;\n  }\n\n  if (!data && !error) {\n    return <SmallLoadingSpinner />;\n  }\n\n  return (\n    <>\n      {((data?.movie.limit ?? 0) !== 0 || (data?.tv.limit ?? 0) !== 0) && (\n        <div className=\"flex\">\n          <div className=\"flex basis-1/2 flex-col space-y-2\">\n            <div className=\"text-sm text-gray-200\">\n              {intl.formatMessage(messages.movierequests)}\n            </div>\n            <div className=\"flex h-full items-center space-x-2 text-gray-200\">\n              {(data?.movie.limit ?? 0) > 0 ? (\n                <>\n                  <ProgressCircle\n                    className=\"h-8 w-8\"\n                    progress={Math.round(\n                      ((data?.movie.remaining ?? 0) /\n                        (data?.movie.limit ?? 1)) *\n                        100\n                    )}\n                    useHeatLevel\n                  />\n                  <span className=\"text-lg font-bold\">\n                    {data?.movie.remaining} / {data?.movie.limit}\n                  </span>\n                </>\n              ) : (\n                <>\n                  <InfinityIcon className=\"w-7\" />\n                  <span className=\"font-bold\">Unlimited</span>\n                </>\n              )}\n            </div>\n          </div>\n          <div className=\"flex basis-1/2 flex-col space-y-2\">\n            <div className=\"text-sm text-gray-200\">\n              {intl.formatMessage(messages.seriesrequests)}\n            </div>\n            <div className=\"flex h-full items-center space-x-2 text-gray-200\">\n              {(data?.tv.limit ?? 0) > 0 ? (\n                <>\n                  <ProgressCircle\n                    className=\"h-8 w-8\"\n                    progress={Math.round(\n                      ((data?.tv.remaining ?? 0) / (data?.tv.limit ?? 1)) * 100\n                    )}\n                    useHeatLevel\n                  />\n                  <span className=\"text-lg font-bold text-gray-200\">\n                    {data?.tv.remaining} / {data?.tv.limit}\n                  </span>\n                </>\n              ) : (\n                <>\n                  <InfinityIcon className=\"w-7\" />\n                  <span className=\"font-bold\">Unlimited</span>\n                </>\n              )}\n            </div>\n          </div>\n        </div>\n      )}\n    </>\n  );\n};\n\nexport default MiniQuotaDisplay;\n"
  },
  {
    "path": "src/components/Layout/UserDropdown/index.tsx",
    "content": "import CachedImage from '@app/components/Common/CachedImage';\nimport MiniQuotaDisplay from '@app/components/Layout/UserDropdown/MiniQuotaDisplay';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Menu, Transition } from '@headlessui/react';\nimport {\n  ArrowRightOnRectangleIcon,\n  ClockIcon,\n} from '@heroicons/react/24/outline';\nimport { CogIcon, UserIcon } from '@heroicons/react/24/solid';\nimport axios from 'axios';\nimport type { LinkProps } from 'next/link';\nimport Link from 'next/link';\nimport { Fragment, forwardRef } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Layout.UserDropdown', {\n  myprofile: 'Profile',\n  settings: 'Settings',\n  requests: 'Requests',\n  signout: 'Sign Out',\n});\n\nconst ForwardedLink = forwardRef<\n  HTMLAnchorElement,\n  LinkProps & React.ComponentPropsWithoutRef<'a'>\n>(({ href, children, ...rest }, ref) => {\n  return (\n    <Link href={href} ref={ref} {...rest}>\n      {children}\n    </Link>\n  );\n});\n\nForwardedLink.displayName = 'ForwardedLink';\n\nconst UserDropdown = () => {\n  const intl = useIntl();\n  const { user, revalidate, hasPermission } = useUser();\n\n  const logout = async () => {\n    const response = await axios.post('/api/v1/auth/logout');\n\n    if (response.data?.status === 'ok') {\n      revalidate();\n    }\n  };\n\n  return (\n    <Menu as=\"div\" className=\"relative ml-3\">\n      <div>\n        <Menu.Button\n          className=\"flex max-w-xs items-center rounded-full text-sm ring-1 ring-gray-700 hover:ring-gray-500 focus:outline-none focus:ring-gray-500\"\n          data-testid=\"user-menu\"\n        >\n          <CachedImage\n            type=\"avatar\"\n            className=\"h-8 w-8 rounded-full object-cover sm:h-10 sm:w-10\"\n            src={user ? user.avatar : ''}\n            alt=\"\"\n            width={40}\n            height={40}\n          />\n        </Menu.Button>\n      </div>\n      <Transition\n        as={Fragment}\n        enter=\"transition ease-out duration-100\"\n        enterFrom=\"opacity-0 scale-95\"\n        enterTo=\"opacity-100 scale-100\"\n        leave=\"transition ease-in duration-75\"\n        leaveFrom=\"opacity-100 scale-100\"\n        leaveTo=\"opacity-0 scale-95\"\n        appear\n      >\n        <Menu.Items className=\"absolute right-0 mt-2 w-72 origin-top-right rounded-md shadow-lg\">\n          <div className=\"divide-y divide-gray-700 rounded-md bg-gray-800/80 ring-1 ring-gray-700 backdrop-blur\">\n            <div className=\"flex flex-col space-y-4 px-4 py-4\">\n              <div className=\"flex items-center space-x-2\">\n                <CachedImage\n                  type=\"avatar\"\n                  className=\"h-8 w-8 rounded-full object-cover sm:h-10 sm:w-10\"\n                  src={user ? user.avatar : ''}\n                  alt=\"\"\n                  width={40}\n                  height={40}\n                />\n                <div className=\"flex min-w-0 flex-col\">\n                  <span className=\"truncate text-xl font-semibold text-gray-200\">\n                    {user?.displayName}\n                  </span>\n                  {user?.displayName?.toLowerCase() !== user?.email && (\n                    <span className=\"truncate text-sm text-gray-400\">\n                      {user?.email}\n                    </span>\n                  )}\n                </div>\n              </div>\n              {user && <MiniQuotaDisplay userId={user?.id} />}\n            </div>\n            <div className=\"p-1\">\n              <Menu.Item>\n                {({ active }) => (\n                  <ForwardedLink\n                    href={`/profile`}\n                    className={`flex items-center rounded px-4 py-2 text-sm font-medium text-gray-200 transition duration-150 ease-in-out ${\n                      active\n                        ? 'bg-gradient-to-br from-indigo-600 to-purple-600 text-white'\n                        : ''\n                    }`}\n                    data-testid=\"user-menu-profile\"\n                  >\n                    <UserIcon className=\"mr-2 inline h-5 w-5\" />\n                    <span>{intl.formatMessage(messages.myprofile)}</span>\n                  </ForwardedLink>\n                )}\n              </Menu.Item>\n              <Menu.Item>\n                {({ active }) => (\n                  <ForwardedLink\n                    href={\n                      hasPermission(\n                        [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n                        { type: 'or' }\n                      )\n                        ? `/users/${user?.id}/requests?filter=all`\n                        : '/requests'\n                    }\n                    className={`flex items-center rounded px-4 py-2 text-sm font-medium text-gray-200 transition duration-150 ease-in-out ${\n                      active\n                        ? 'bg-gradient-to-br from-indigo-600 to-purple-600 text-white'\n                        : ''\n                    }`}\n                    data-testid=\"user-menu-settings\"\n                  >\n                    <ClockIcon className=\"mr-2 inline h-5 w-5\" />\n                    <span>{intl.formatMessage(messages.requests)}</span>\n                  </ForwardedLink>\n                )}\n              </Menu.Item>\n              <Menu.Item>\n                {({ active }) => (\n                  <ForwardedLink\n                    href={`/profile/settings`}\n                    className={`flex items-center rounded px-4 py-2 text-sm font-medium text-gray-200 transition duration-150 ease-in-out ${\n                      active\n                        ? 'bg-gradient-to-br from-indigo-600 to-purple-600 text-white'\n                        : ''\n                    }`}\n                    data-testid=\"user-menu-settings\"\n                  >\n                    <CogIcon className=\"mr-2 inline h-5 w-5\" />\n                    <span>{intl.formatMessage(messages.settings)}</span>\n                  </ForwardedLink>\n                )}\n              </Menu.Item>\n              <Menu.Item>\n                {({ active }) => (\n                  <a\n                    href=\"#\"\n                    className={`flex items-center rounded px-4 py-2 text-sm font-medium text-gray-200 transition duration-150 ease-in-out ${\n                      active\n                        ? 'bg-gradient-to-br from-indigo-600 to-purple-600 text-white'\n                        : ''\n                    }`}\n                    onClick={() => logout()}\n                  >\n                    <ArrowRightOnRectangleIcon className=\"mr-2 inline h-5 w-5\" />\n                    <span>{intl.formatMessage(messages.signout)}</span>\n                  </a>\n                )}\n              </Menu.Item>\n            </div>\n          </div>\n        </Menu.Items>\n      </Transition>\n    </Menu>\n  );\n};\n\nexport default UserDropdown;\n"
  },
  {
    "path": "src/components/Layout/UserWarnings/index.tsx",
    "content": "import { useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ExclamationTriangleIcon } from '@heroicons/react/24/outline';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Layout.UserWarnings', {\n  emailRequired: 'An email address is required.',\n  emailInvalid: 'Email address is invalid.',\n  passwordRequired: 'A password is required.',\n});\n\ninterface UserWarningsProps {\n  onClick?: () => void;\n}\n\nconst UserWarnings: React.FC<UserWarningsProps> = ({ onClick }) => {\n  const intl = useIntl();\n  const { user } = useUser();\n  //check if a user has warnings\n  if (!user || !user.warnings || user.warnings.length === 0) {\n    return null;\n  }\n\n  let res = null;\n\n  user.warnings.forEach((warning) => {\n    let link = '';\n    let warningText = '';\n    let warningTitle = '';\n    switch (warning) {\n      case 'userEmailRequired':\n        link = '/profile/settings/';\n        warningTitle = 'Profile is incomplete';\n        warningText = intl.formatMessage(messages.emailRequired);\n    }\n\n    res = (\n      <Link\n        href={link}\n        onClick={onClick}\n        onKeyDown={(e) => {\n          if (e.key === 'Enter' && onClick) {\n            onClick();\n          }\n        }}\n        role=\"button\"\n        tabIndex={0}\n        className=\"mx-2 mb-2 flex items-center rounded-lg bg-yellow-500 p-2 text-xs text-white ring-1 ring-gray-700 transition duration-300 hover:bg-yellow-400\"\n      >\n        <ExclamationTriangleIcon className=\"h-6 w-6\" />\n        <div className=\"flex min-w-0 flex-1 flex-col truncate px-2 last:pr-0\">\n          <span className=\"font-bold\">{warningTitle}</span>\n          <span className=\"truncate\">{warningText}</span>\n        </div>\n      </Link>\n    );\n  });\n\n  return res;\n};\n\nexport default UserWarnings;\n"
  },
  {
    "path": "src/components/Layout/VersionStatus/index.tsx",
    "content": "import defineMessages from '@app/utils/defineMessages';\nimport {\n  ArrowUpCircleIcon,\n  BeakerIcon,\n  CodeBracketIcon,\n  ServerIcon,\n} from '@heroicons/react/24/outline';\nimport type { StatusResponse } from '@server/interfaces/api/settingsInterfaces';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Layout.VersionStatus', {\n  streamdevelop: 'Seerr Develop',\n  streamstable: 'Seerr Stable',\n  outofdate: 'Out of Date',\n  commitsbehind:\n    '{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} behind',\n});\n\ninterface VersionStatusProps {\n  onClick?: () => void;\n}\n\nconst VersionStatus = ({ onClick }: VersionStatusProps) => {\n  const intl = useIntl();\n  const { data } = useSWR<StatusResponse>('/api/v1/status', {\n    refreshInterval: 60 * 1000,\n  });\n\n  if (!data) {\n    return null;\n  }\n\n  const versionStream =\n    data.commitTag === 'local'\n      ? 'Keep it up! 👍'\n      : data.version.startsWith('develop-')\n        ? intl.formatMessage(messages.streamdevelop)\n        : intl.formatMessage(messages.streamstable);\n\n  return (\n    <Link\n      href=\"/settings/about\"\n      onClick={onClick}\n      onKeyDown={(e) => {\n        if (e.key === 'Enter' && onClick) {\n          onClick();\n        }\n      }}\n      role=\"button\"\n      tabIndex={0}\n      className={`mx-2 flex items-center rounded-lg p-2 text-xs ring-1 ring-gray-700 transition duration-300 ${\n        data.updateAvailable\n          ? 'bg-yellow-500 text-white hover:bg-yellow-400'\n          : 'bg-gray-900 text-gray-300 hover:bg-gray-800'\n      }`}\n    >\n      {data.commitTag === 'local' ? (\n        <CodeBracketIcon className=\"h-6 w-6\" />\n      ) : data.version.startsWith('develop-') ? (\n        <BeakerIcon className=\"h-6 w-6\" />\n      ) : (\n        <ServerIcon className=\"h-6 w-6\" />\n      )}\n      <div className=\"flex min-w-0 flex-1 flex-col truncate px-2 last:pr-0\">\n        <span className=\"font-bold\">{versionStream}</span>\n        <span className=\"truncate\">\n          {data.commitTag === 'local' ? (\n            '(⌐■_■)'\n          ) : data.commitsBehind > 0 ? (\n            intl.formatMessage(messages.commitsbehind, {\n              commitsBehind: data.commitsBehind,\n            })\n          ) : data.commitsBehind === -1 ? (\n            intl.formatMessage(messages.outofdate)\n          ) : (\n            <code className=\"bg-transparent p-0\">\n              {data.version.replace('develop-', '')}\n            </code>\n          )}\n        </span>\n      </div>\n      {data.updateAvailable && <ArrowUpCircleIcon className=\"h-6 w-6\" />}\n    </Link>\n  );\n};\n\nexport default VersionStatus;\n"
  },
  {
    "path": "src/components/Layout/index.tsx",
    "content": "import MobileMenu from '@app/components/Layout/MobileMenu';\nimport PullToRefresh from '@app/components/Layout/PullToRefresh';\nimport SearchInput from '@app/components/Layout/SearchInput';\nimport Sidebar from '@app/components/Layout/Sidebar';\nimport UserDropdown from '@app/components/Layout/UserDropdown';\nimport useLocale from '@app/hooks/useLocale';\nimport useSettings from '@app/hooks/useSettings';\nimport { useUser } from '@app/hooks/useUser';\nimport { ArrowLeftIcon, Bars3BottomLeftIcon } from '@heroicons/react/24/solid';\nimport type { AvailableLocale } from '@server/types/languages';\nimport { useRouter } from 'next/router';\nimport { useEffect, useState } from 'react';\nimport useSWR from 'swr';\n\ntype LayoutProps = {\n  children: React.ReactNode;\n};\n\nconst Layout = ({ children }: LayoutProps) => {\n  const [isSidebarOpen, setSidebarOpen] = useState(false);\n  const [isScrolled, setIsScrolled] = useState(false);\n  const { user } = useUser();\n  const router = useRouter();\n  const { currentSettings } = useSettings();\n  const { setLocale } = useLocale();\n  const { data: requestResponse, mutate: revalidateRequestsCount } = useSWR(\n    '/api/v1/request/count',\n    {\n      revalidateOnMount: true,\n    }\n  );\n  const { data: issueResponse, mutate: revalidateIssueCount } = useSWR(\n    '/api/v1/issue/count',\n    {\n      revalidateOnMount: true,\n    }\n  );\n\n  useEffect(() => {\n    if (setLocale && user) {\n      setLocale(\n        (user?.settings?.locale\n          ? user.settings.locale\n          : currentSettings.locale) as AvailableLocale\n      );\n    }\n  }, [setLocale, currentSettings.locale, user]);\n\n  useEffect(() => {\n    const updateScrolled = () => {\n      if (window.pageYOffset > 20) {\n        setIsScrolled(true);\n      } else {\n        setIsScrolled(false);\n      }\n    };\n\n    window.addEventListener('scroll', updateScrolled, { passive: true });\n\n    return () => {\n      window.removeEventListener('scroll', updateScrolled);\n    };\n  }, []);\n\n  return (\n    <div className=\"flex h-full min-h-full min-w-0 bg-gray-900\">\n      <div className=\"pwa-only fixed inset-0 z-20 h-1 w-full border-gray-700 md:border-t\" />\n      <div className=\"absolute top-0 h-64 w-full bg-gradient-to-bl from-gray-800 to-gray-900\">\n        <div className=\"relative inset-0 h-full w-full bg-gradient-to-t from-gray-900 to-transparent\" />\n      </div>\n      <Sidebar\n        open={isSidebarOpen}\n        setClosed={() => setSidebarOpen(false)}\n        pendingRequestsCount={requestResponse?.pending ?? 0}\n        openIssuesCount={issueResponse?.open ?? 0}\n        revalidateIssueCount={() => revalidateIssueCount()}\n        revalidateRequestsCount={() => revalidateRequestsCount()}\n      />\n      <div className=\"sm:hidden\">\n        <MobileMenu\n          pendingRequestsCount={requestResponse?.pending ?? 0}\n          openIssuesCount={issueResponse?.open ?? 0}\n          revalidateIssueCount={() => revalidateIssueCount()}\n          revalidateRequestsCount={() => revalidateRequestsCount()}\n        />\n      </div>\n\n      <div className=\"relative mb-16 flex w-0 min-w-0 flex-1 flex-col lg:ml-64\">\n        <PullToRefresh />\n        <div\n          className={`searchbar fixed left-0 right-0 top-0 z-10 flex flex-shrink-0 transition duration-300 ${\n            isScrolled ? 'bg-gray-700/80' : 'bg-transparent'\n          } lg:left-64`}\n          style={{\n            backdropFilter: isScrolled ? 'blur(5px)' : undefined,\n            WebkitBackdropFilter: isScrolled ? 'blur(5px)' : undefined,\n          }}\n        >\n          <div className=\"flex flex-1 items-center justify-between px-4 md:pl-4 md:pr-4\">\n            <button\n              className={`mr-2 hidden text-white sm:block ${\n                isScrolled ? 'opacity-90' : 'opacity-70'\n              } transition duration-300 focus:outline-none lg:hidden`}\n              aria-label=\"Open sidebar\"\n              onClick={() => setSidebarOpen(true)}\n              data-testid=\"sidebar-toggle\"\n            >\n              <Bars3BottomLeftIcon className=\"h-7 w-7\" />\n            </button>\n            <button\n              className={`mr-2 text-white ${\n                isScrolled ? 'opacity-90' : 'opacity-70'\n              } pwa-only transition duration-300 hover:text-white focus:text-white focus:outline-none`}\n              onClick={() => router.back()}\n            >\n              <ArrowLeftIcon className=\"w-7\" />\n            </button>\n            <SearchInput />\n            <div className=\"flex items-center\">\n              <UserDropdown />\n            </div>\n          </div>\n        </div>\n\n        <main className=\"relative top-16 z-0 focus:outline-none\" tabIndex={0}>\n          <div className=\"mb-6\">\n            <div className=\"max-w-8xl mx-auto px-4\">{children}</div>\n          </div>\n        </main>\n      </div>\n    </div>\n  );\n};\n\nexport default Layout;\n"
  },
  {
    "path": "src/components/LoadingBar/index.tsx",
    "content": "import { NProgress } from '@tanem/react-nprogress';\nimport { useRouter } from 'next/router';\nimport React, { useEffect, useState } from 'react';\nimport ReactDOM from 'react-dom';\n\ninterface BarProps {\n  progress: number;\n  isFinished: boolean;\n}\n\nconst Bar = ({ progress, isFinished }: BarProps) => {\n  return (\n    <div\n      className={`duration-400 fixed left-0 top-0 z-50 w-full transition-opacity ease-out ${\n        isFinished ? 'opacity-0' : 'opacity-100'\n      }`}\n    >\n      <div\n        className=\"bg-indigo-400 transition-width duration-300\"\n        style={{\n          height: '3px',\n          width: `${progress * 100}%`,\n        }}\n      />\n    </div>\n  );\n};\n\nconst NProgressBar = ({ loading }: { loading: boolean }) => (\n  <NProgress isAnimating={loading}>\n    {({ isFinished, progress }) => (\n      <Bar progress={progress} isFinished={isFinished} />\n    )}\n  </NProgress>\n);\n\nconst MemoizedNProgress = React.memo(NProgressBar);\n\nconst LoadingBar = (): React.ReactPortal | null => {\n  const [mounted, setMounted] = useState(false);\n  const [loading, setLoading] = useState(false);\n  const router = useRouter();\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  useEffect(() => {\n    const handleLoading = () => {\n      setLoading(true);\n    };\n    const handleFinishedLoading = () => {\n      setLoading(false);\n    };\n    router.events.on('routeChangeStart', handleLoading);\n    router.events.on('routeChangeComplete', handleFinishedLoading);\n    router.events.on('routeChangeError', handleFinishedLoading);\n\n    return () => {\n      router.events.off('routeChangeStart', handleLoading);\n      router.events.off('routeChangeComplete', handleFinishedLoading);\n      router.events.off('routeChangeError', handleFinishedLoading);\n    };\n  }, [router]);\n\n  return mounted\n    ? ReactDOM.createPortal(\n        <MemoizedNProgress loading={loading} />,\n        document.body\n      )\n    : null;\n};\n\nexport default LoadingBar;\n"
  },
  {
    "path": "src/components/Login/AddEmailModal.tsx",
    "content": "import Modal from '@app/components/Common/Modal';\nimport useSettings from '@app/hooks/useSettings';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport axios from 'axios';\nimport { Field, Formik } from 'formik';\nimport { useIntl } from 'react-intl';\nimport validator from 'validator';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Login', {\n  title: 'Add Email',\n  description:\n    'Since this is your first time logging into {applicationName}, you are required to add a valid email address.',\n  email: 'Email address',\n  validationEmailRequired: 'You must provide an email',\n  validationEmailFormat: 'Invalid email',\n  saving: 'Adding…',\n  save: 'Add',\n});\n\ninterface AddEmailModalProps {\n  username: string;\n  password: string;\n  onClose: () => void;\n  onSave: () => void;\n}\n\nconst AddEmailModal: React.FC<AddEmailModalProps> = ({\n  onClose,\n  username,\n  password,\n  onSave,\n}) => {\n  const intl = useIntl();\n  const settings = useSettings();\n\n  const EmailSettingsSchema = Yup.object().shape({\n    email: Yup.string()\n      .test(\n        'email',\n        intl.formatMessage(messages.validationEmailFormat),\n        (value) => !value || validator.isEmail(value, { require_tld: false })\n      )\n      .required(intl.formatMessage(messages.validationEmailRequired)),\n  });\n\n  return (\n    <Transition\n      appear\n      show\n      enter=\"transition ease-in-out duration-300 transform opacity-0\"\n      enterFrom=\"opacity-0\"\n      enterTo=\"opacuty-100\"\n      leave=\"transition ease-in-out duration-300 transform opacity-100\"\n      leaveFrom=\"opacity-100\"\n      leaveTo=\"opacity-0\"\n    >\n      <Formik\n        initialValues={{\n          email: '',\n        }}\n        validationSchema={EmailSettingsSchema}\n        onSubmit={async (values) => {\n          try {\n            await axios.post('/api/v1/auth/jellyfin', {\n              username: username,\n              password: password,\n              email: values.email,\n            });\n\n            onSave();\n          } catch {\n            // set error here\n          }\n        }}\n      >\n        {({ errors, touched, handleSubmit, isSubmitting, isValid }) => {\n          return (\n            <Modal\n              onCancel={onClose}\n              okButtonType=\"primary\"\n              okText={\n                isSubmitting\n                  ? intl.formatMessage(messages.saving)\n                  : intl.formatMessage(messages.save)\n              }\n              okDisabled={isSubmitting || !isValid}\n              onOk={() => handleSubmit()}\n              title={intl.formatMessage(messages.title)}\n            >\n              {intl.formatMessage(messages.description, {\n                applicationName: settings.currentSettings.applicationTitle,\n              })}\n              <label htmlFor=\"email\" className=\"text-label\">\n                {intl.formatMessage(messages.email)}\n              </label>\n              <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n                <div className=\"flex rounded-md shadow-sm\">\n                  <Field\n                    id=\"email\"\n                    name=\"email\"\n                    type=\"text\"\n                    placeholder={intl.formatMessage(messages.email)}\n                  />\n                </div>\n                {errors.email && touched.email && (\n                  <div className=\"error\">{errors.email}</div>\n                )}\n              </div>\n            </Modal>\n          );\n        }}\n      </Formik>\n    </Transition>\n  );\n};\n\nexport default AddEmailModal;\n"
  },
  {
    "path": "src/components/Login/JellyfinLogin.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport useSettings from '@app/hooks/useSettings';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowLeftOnRectangleIcon } from '@heroicons/react/24/outline';\nimport { ExclamationTriangleIcon } from '@heroicons/react/24/solid';\nimport { ApiErrorCode } from '@server/constants/error';\nimport { MediaServerType, ServerType } from '@server/constants/server';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Login', {\n  loginwithapp: 'Login with {appName}',\n  username: 'Username',\n  password: 'Password',\n  validationusernamerequired: 'Username required',\n  validationpasswordrequired: 'Password required',\n  loginerror: 'Something went wrong while trying to sign in.',\n  adminerror: 'You must use an admin account to sign in.',\n  noadminerror: 'No admin user found on the server.',\n  credentialerror: 'The username or password is incorrect.',\n  invalidurlerror: 'Unable to connect to {mediaServerName} server.',\n  tipUsernameHasTrailingWhitespace: 'The username ends with whitespace',\n  signingin: 'Signing In…',\n  signin: 'Sign In',\n  forgotpassword: 'Forgot Password?',\n});\n\ninterface JellyfinLoginProps {\n  revalidate: () => void;\n  serverType?: MediaServerType;\n}\n\nconst JellyfinLogin: React.FC<JellyfinLoginProps> = ({\n  revalidate,\n  serverType,\n}) => {\n  const toasts = useToasts();\n  const intl = useIntl();\n  const settings = useSettings();\n\n  const mediaServerFormatValues = {\n    mediaServerName:\n      serverType === MediaServerType.JELLYFIN\n        ? ServerType.JELLYFIN\n        : serverType === MediaServerType.EMBY\n          ? ServerType.EMBY\n          : 'Media Server',\n  };\n\n  const LoginSchema = Yup.object().shape({\n    username: Yup.string().required(\n      intl.formatMessage(messages.validationusernamerequired)\n    ),\n    password: Yup.string(),\n  });\n  const baseUrl = settings.currentSettings.jellyfinExternalHost\n    ? settings.currentSettings.jellyfinExternalHost\n    : settings.currentSettings.jellyfinHost;\n  const jellyfinForgotPasswordUrl =\n    settings.currentSettings.jellyfinForgotPasswordUrl;\n\n  return (\n    <div>\n      <Formik\n        initialValues={{\n          username: '',\n          password: '',\n        }}\n        validationSchema={LoginSchema}\n        validateOnBlur={false}\n        onSubmit={async (values) => {\n          try {\n            await axios.post('/api/v1/auth/jellyfin', {\n              username: values.username,\n              password: values.password,\n              email: values.username,\n            });\n          } catch (e) {\n            let errorMessage = messages.loginerror;\n            switch (e?.response?.data?.message) {\n              case ApiErrorCode.InvalidUrl:\n                errorMessage = messages.invalidurlerror;\n                break;\n              case ApiErrorCode.InvalidCredentials:\n                errorMessage = messages.credentialerror;\n                break;\n              case ApiErrorCode.NotAdmin:\n                errorMessage = messages.adminerror;\n                break;\n              case ApiErrorCode.NoAdminUser:\n                errorMessage = messages.noadminerror;\n                break;\n            }\n            toasts.addToast(\n              intl.formatMessage(errorMessage, mediaServerFormatValues),\n              {\n                autoDismiss: true,\n                appearance: 'error',\n              }\n            );\n          } finally {\n            revalidate();\n          }\n        }}\n      >\n        {({ errors, touched, values, isSubmitting, isValid }) => {\n          return (\n            <>\n              <Form data-form-type=\"login\">\n                <div>\n                  <h2 className=\"-mt-1 mb-6 text-center text-lg font-bold text-neutral-200\">\n                    {intl.formatMessage(messages.loginwithapp, {\n                      appName: mediaServerFormatValues.mediaServerName,\n                    })}\n                  </h2>\n\n                  <div className=\"mb-4 mt-1\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"username\"\n                        name=\"username\"\n                        type=\"text\"\n                        placeholder={intl.formatMessage(messages.username)}\n                        className=\"!bg-gray-700/80 placeholder:text-gray-400\"\n                        data-form-type=\"username\"\n                      />\n                    </div>\n                    {touched.username && values.username.match(/\\s$/) && (\n                      <div className=\"warning label-tip flex items-center\">\n                        <ExclamationTriangleIcon className=\"mr-1 h-4 w-4\" />\n                        {intl.formatMessage(\n                          messages.tipUsernameHasTrailingWhitespace\n                        )}\n                      </div>\n                    )}\n                    {errors.username && touched.username && (\n                      <div className=\"error\">{errors.username}</div>\n                    )}\n                  </div>\n\n                  <div className=\"mb-2 mt-1\">\n                    <div className=\"form-input-field\">\n                      <SensitiveInput\n                        as=\"field\"\n                        id=\"password\"\n                        name=\"password\"\n                        type=\"password\"\n                        autoComplete=\"current-password\"\n                        placeholder={intl.formatMessage(messages.password)}\n                        className=\"!bg-gray-700/80 placeholder:text-gray-400\"\n                        data-form-type=\"password\"\n                        data-1pignore=\"false\"\n                        data-lpignore=\"false\"\n                      />\n                    </div>\n                    <div className=\"flex\">\n                      {errors.password && touched.password && (\n                        <div className=\"error\">{errors.password}</div>\n                      )}\n                      <div className=\"flex-grow\" />\n                      {baseUrl && (\n                        <a\n                          href={\n                            jellyfinForgotPasswordUrl\n                              ? `${jellyfinForgotPasswordUrl}`\n                              : `${baseUrl}/web/index.html#!/${\n                                  settings.currentSettings.mediaServerType ===\n                                  MediaServerType.EMBY\n                                    ? 'startup/'\n                                    : ''\n                                }forgotpassword.html`\n                          }\n                          className=\"pt-2 text-sm text-indigo-500 hover:text-indigo-400\"\n                        >\n                          {intl.formatMessage(messages.forgotpassword)}\n                        </a>\n                      )}\n                    </div>\n                  </div>\n                </div>\n\n                <Button\n                  buttonType=\"primary\"\n                  type=\"submit\"\n                  disabled={isSubmitting || !isValid}\n                  className=\"mt-2 w-full shadow-sm\"\n                >\n                  <ArrowLeftOnRectangleIcon />\n                  <span>\n                    {isSubmitting\n                      ? intl.formatMessage(messages.signingin)\n                      : intl.formatMessage(messages.signin)}\n                  </span>\n                </Button>\n              </Form>\n            </>\n          );\n        }}\n      </Formik>\n    </div>\n  );\n};\n\nexport default JellyfinLogin;\n"
  },
  {
    "path": "src/components/Login/LocalLogin.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport useSettings from '@app/hooks/useSettings';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowLeftOnRectangleIcon } from '@heroicons/react/24/outline';\nimport { ExclamationTriangleIcon } from '@heroicons/react/24/solid';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport Link from 'next/link';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Login', {\n  loginwithapp: 'Login with {appName}',\n  username: 'Username',\n  email: 'Email Address',\n  password: 'Password',\n  validationemailrequired: 'You must provide a valid email address',\n  validationpasswordrequired: 'You must provide a password',\n  loginerror: 'Something went wrong while trying to sign in.',\n  tipEmailHasTrailingWhitespace: 'The email ends with whitespace',\n  signingin: 'Signing In…',\n  signin: 'Sign In',\n  forgotpassword: 'Forgot Password?',\n});\n\ninterface LocalLoginProps {\n  revalidate: () => void;\n}\n\nconst LocalLogin = ({ revalidate }: LocalLoginProps) => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const [loginError, setLoginError] = useState<string | null>(null);\n\n  const LoginSchema = Yup.object().shape({\n    email: Yup.string().required(\n      intl.formatMessage(messages.validationemailrequired)\n    ),\n    password: Yup.string().required(\n      intl.formatMessage(messages.validationpasswordrequired)\n    ),\n  });\n\n  const passwordResetEnabled =\n    settings.currentSettings.applicationUrl &&\n    settings.currentSettings.emailEnabled;\n\n  return (\n    <Formik\n      initialValues={{\n        email: '',\n        password: '',\n      }}\n      validationSchema={LoginSchema}\n      validateOnBlur={false}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/auth/local', {\n            email: values.email,\n            password: values.password,\n          });\n        } catch {\n          setLoginError(intl.formatMessage(messages.loginerror));\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({ errors, touched, values, isSubmitting, isValid }) => {\n        return (\n          <>\n            <Form data-form-type=\"login\">\n              <div>\n                <h2 className=\"-mt-1 mb-6 text-center text-lg font-bold text-neutral-200\">\n                  {intl.formatMessage(messages.loginwithapp, {\n                    appName: settings.currentSettings.applicationTitle,\n                  })}\n                </h2>\n\n                <div className=\"mb-4 mt-1\">\n                  <div className=\"form-input-field\">\n                    <Field\n                      id=\"email\"\n                      name=\"email\"\n                      placeholder={`${intl.formatMessage(\n                        messages.email\n                      )} / ${intl.formatMessage(messages.username)}`}\n                      type=\"text\"\n                      inputMode=\"email\"\n                      data-testid=\"email\"\n                      data-form-type=\"username,email\"\n                      className=\"!bg-gray-700/80 placeholder:text-gray-400\"\n                    />\n                  </div>\n                  {touched.email && values.email.match(/\\s$/) && (\n                    <div className=\"warning label-tip flex items-center\">\n                      <ExclamationTriangleIcon className=\"mr-1 h-4 w-4\" />\n                      {intl.formatMessage(\n                        messages.tipEmailHasTrailingWhitespace\n                      )}\n                    </div>\n                  )}\n                  {errors.email &&\n                    touched.email &&\n                    typeof errors.email === 'string' && (\n                      <div className=\"error\">{errors.email}</div>\n                    )}\n                </div>\n                <div className=\"mb-2 mt-1\">\n                  <div className=\"form-input-field\">\n                    <SensitiveInput\n                      as=\"field\"\n                      id=\"password\"\n                      name=\"password\"\n                      type=\"password\"\n                      placeholder={intl.formatMessage(messages.password)}\n                      autoComplete=\"current-password\"\n                      data-testid=\"password\"\n                      data-form-type=\"password\"\n                      className=\"!bg-gray-700/80 placeholder:text-gray-400\"\n                      data-1pignore=\"false\"\n                      data-lpignore=\"false\"\n                    />\n                  </div>\n                  <div className=\"flex\">\n                    {errors.password &&\n                      touched.password &&\n                      typeof errors.password === 'string' && (\n                        <div className=\"error\">{errors.password}</div>\n                      )}\n                    <div className=\"flex-grow\" />\n                    {passwordResetEnabled && (\n                      <Link\n                        href=\"/resetpassword\"\n                        className=\"pt-2 text-sm text-indigo-500 hover:text-indigo-400\"\n                      >\n                        {intl.formatMessage(messages.forgotpassword)}\n                      </Link>\n                    )}\n                  </div>\n                </div>\n                {loginError && (\n                  <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n                    <div className=\"error\">{loginError}</div>\n                  </div>\n                )}\n              </div>\n\n              <Button\n                buttonType=\"primary\"\n                type=\"submit\"\n                disabled={isSubmitting || !isValid}\n                data-testid=\"local-signin-button\"\n                className=\"mt-2 w-full shadow-sm\"\n              >\n                <ArrowLeftOnRectangleIcon />\n                <span>\n                  {isSubmitting\n                    ? intl.formatMessage(messages.signingin)\n                    : intl.formatMessage(messages.signin)}\n                </span>\n              </Button>\n            </Form>\n          </>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default LocalLogin;\n"
  },
  {
    "path": "src/components/Login/PlexLoginButton.tsx",
    "content": "import PlexIcon from '@app/assets/services/plex.svg';\nimport Button from '@app/components/Common/Button';\nimport { SmallLoadingSpinner } from '@app/components/Common/LoadingSpinner';\nimport usePlexLogin from '@app/hooks/usePlexLogin';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Fragment } from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nconst messages = defineMessages('components.Login', {\n  loginwithapp: 'Login with {appName}',\n});\n\ninterface PlexLoginButtonProps {\n  onAuthToken: (authToken: string) => void;\n  isProcessing?: boolean;\n  onError?: (message: string) => void;\n  large?: boolean;\n}\n\nconst PlexLoginButton = ({\n  onAuthToken,\n  onError,\n  isProcessing,\n  large,\n}: PlexLoginButtonProps) => {\n  const { loading, login } = usePlexLogin({ onAuthToken, onError });\n\n  return (\n    <Button\n      className=\"relative flex-1 border-[#cc7b19] bg-[rgba(204,123,25,0.3)] hover:border-[#cc7b19] hover:bg-[rgba(204,123,25,0.7)] disabled:opacity-50\"\n      onClick={login}\n      disabled={loading || isProcessing}\n      data-testid=\"plex-login-button\"\n    >\n      {loading && (\n        <div className=\"absolute right-0 mr-4 h-4 w-4\">\n          <SmallLoadingSpinner />\n        </div>\n      )}\n\n      {large ? (\n        <FormattedMessage\n          {...messages.loginwithapp}\n          values={{\n            appName: <PlexIcon className=\"ml-[0.35em] mt-[2px] w-8\" />,\n          }}\n        >\n          {(chunks) => (\n            <>\n              {chunks.map((c, index) =>\n                typeof c === 'string' ? (\n                  <span key={index}>{c}</span>\n                ) : (\n                  <Fragment key={index}>{c}</Fragment>\n                )\n              )}\n            </>\n          )}\n        </FormattedMessage>\n      ) : (\n        <PlexIcon className=\"w-8\" />\n      )}\n    </Button>\n  );\n};\n\nexport default PlexLoginButton;\n"
  },
  {
    "path": "src/components/Login/index.tsx",
    "content": "import EmbyLogo from '@app/assets/services/emby-icon-only.svg';\nimport JellyfinLogo from '@app/assets/services/jellyfin-icon.svg';\nimport PlexLogo from '@app/assets/services/plex.svg';\nimport Button from '@app/components/Common/Button';\nimport ImageFader from '@app/components/Common/ImageFader';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport LanguagePicker from '@app/components/Layout/LanguagePicker';\nimport JellyfinLogin from '@app/components/Login/JellyfinLogin';\nimport LocalLogin from '@app/components/Login/LocalLogin';\nimport PlexLoginButton from '@app/components/Login/PlexLoginButton';\nimport useSettings from '@app/hooks/useSettings';\nimport { useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport { XCircleIcon } from '@heroicons/react/24/solid';\nimport { MediaServerType } from '@server/constants/server';\nimport axios from 'axios';\nimport { useRouter } from 'next/dist/client/router';\nimport Image from 'next/image';\nimport { useEffect, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { CSSTransition, SwitchTransition } from 'react-transition-group';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Login', {\n  signin: 'Sign In',\n  signinheader: 'Sign in to continue',\n  signinwithplex: 'Use your Plex account',\n  signinwithjellyfin: 'Use your {mediaServerName} account',\n  signinwithoverseerr: 'Use your {applicationTitle} account',\n  orsigninwith: 'Or sign in with',\n});\n\nconst Login = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const settings = useSettings();\n  const { user, revalidate } = useUser();\n\n  const [error, setError] = useState('');\n  const [isProcessing, setProcessing] = useState(false);\n  const [authToken, setAuthToken] = useState<string | undefined>(undefined);\n  const [mediaServerLogin, setMediaServerLogin] = useState(\n    settings.currentSettings.mediaServerLogin\n  );\n\n  // Effect that is triggered when the `authToken` comes back from the Plex OAuth\n  // We take the token and attempt to sign in. If we get a success message, we will\n  // ask swr to revalidate the user which _should_ come back with a valid user.\n  useEffect(() => {\n    const login = async () => {\n      setProcessing(true);\n      try {\n        const response = await axios.post('/api/v1/auth/plex', { authToken });\n\n        if (response.data?.id) {\n          revalidate();\n        }\n      } catch (e) {\n        setError(e.response?.data?.message);\n        setAuthToken(undefined);\n        setProcessing(false);\n      }\n    };\n    if (authToken) {\n      login();\n    }\n  }, [authToken, revalidate]);\n\n  // Effect that is triggered whenever `useUser`'s user changes. If we get a new\n  // valid user, we redirect the user to the home page as the login was successful.\n  useEffect(() => {\n    if (user) {\n      router.push('/');\n    }\n  }, [user, router]);\n\n  const { data: backdrops } = useSWR<string[]>('/api/v1/backdrops', {\n    refreshInterval: 0,\n    refreshWhenHidden: false,\n    revalidateOnFocus: false,\n  });\n\n  const mediaServerName =\n    settings.currentSettings.mediaServerType === MediaServerType.PLEX\n      ? 'Plex'\n      : settings.currentSettings.mediaServerType === MediaServerType.JELLYFIN\n        ? 'Jellyfin'\n        : settings.currentSettings.mediaServerType === MediaServerType.EMBY\n          ? 'Emby'\n          : undefined;\n\n  const MediaServerLogo =\n    settings.currentSettings.mediaServerType === MediaServerType.PLEX\n      ? PlexLogo\n      : settings.currentSettings.mediaServerType === MediaServerType.JELLYFIN\n        ? JellyfinLogo\n        : settings.currentSettings.mediaServerType === MediaServerType.EMBY\n          ? EmbyLogo\n          : undefined;\n\n  const isJellyfin =\n    settings.currentSettings.mediaServerType === MediaServerType.JELLYFIN ||\n    settings.currentSettings.mediaServerType === MediaServerType.EMBY;\n  const mediaServerLoginRef = useRef<HTMLDivElement>(null);\n  const localLoginRef = useRef<HTMLDivElement>(null);\n  const loginRef = mediaServerLogin ? mediaServerLoginRef : localLoginRef;\n\n  const loginFormVisible =\n    (isJellyfin && settings.currentSettings.mediaServerLogin) ||\n    settings.currentSettings.localLogin;\n  const additionalLoginOptions = [\n    settings.currentSettings.mediaServerLogin &&\n      (settings.currentSettings.mediaServerType === MediaServerType.PLEX ? (\n        <PlexLoginButton\n          key=\"plex\"\n          isProcessing={isProcessing}\n          onAuthToken={(authToken) => setAuthToken(authToken)}\n          large={!isJellyfin && !settings.currentSettings.localLogin}\n        />\n      ) : (\n        settings.currentSettings.localLogin &&\n        (mediaServerLogin ? (\n          <Button\n            key=\"seerr\"\n            data-testid=\"seerr-login-button\"\n            className=\"flex-1 bg-transparent\"\n            onClick={() => setMediaServerLogin(false)}\n          >\n            {/* eslint-disable-next-line @next/next/no-img-element */}\n            <img\n              src=\"/os_icon.svg\"\n              alt={settings.currentSettings.applicationTitle}\n              className=\"mr-2 h-5\"\n            />\n            <span>{settings.currentSettings.applicationTitle}</span>\n          </Button>\n        ) : (\n          <Button\n            key=\"mediaserver\"\n            data-testid=\"mediaserver-login-button\"\n            className=\"flex-1 bg-transparent\"\n            onClick={() => setMediaServerLogin(true)}\n          >\n            <MediaServerLogo />\n            <span>{mediaServerName}</span>\n          </Button>\n        ))\n      )),\n  ].filter((o): o is JSX.Element => !!o);\n\n  return (\n    <div className=\"relative flex min-h-screen flex-col bg-gray-900 py-14\">\n      <PageTitle title={intl.formatMessage(messages.signin)} />\n      <ImageFader\n        backgroundImages={\n          backdrops?.map(\n            (backdrop) => `https://image.tmdb.org/t/p/original${backdrop}`\n          ) ?? []\n        }\n      />\n      <div className=\"absolute right-4 top-4 z-50\">\n        <LanguagePicker />\n      </div>\n      <div className=\"relative z-40 mt-10 flex flex-col items-center px-4 sm:mx-auto sm:w-full sm:max-w-md\">\n        <div className=\"relative h-48 w-full max-w-full\">\n          <Image src=\"/logo_stacked.svg\" alt=\"Logo\" fill />\n        </div>\n      </div>\n      <div className=\"relative z-50 mt-8 sm:mx-auto sm:w-full sm:max-w-md\">\n        <div\n          className=\"bg-gray-800/50 shadow sm:rounded-lg\"\n          style={{ backdropFilter: 'blur(5px)' }}\n        >\n          <>\n            <Transition\n              as=\"div\"\n              show={!!error}\n              enter=\"transition-opacity duration-300\"\n              enterFrom=\"opacity-0\"\n              enterTo=\"opacity-100\"\n              leave=\"transition-opacity duration-300\"\n              leaveFrom=\"opacity-100\"\n              leaveTo=\"opacity-0\"\n            >\n              <div className=\"mb-4 rounded-md bg-red-600 p-4\">\n                <div className=\"flex\">\n                  <div className=\"flex-shrink-0\">\n                    <XCircleIcon className=\"h-5 w-5 text-red-300\" />\n                  </div>\n                  <div className=\"ml-3\">\n                    <h3 className=\"text-sm font-medium text-red-300\">\n                      {error}\n                    </h3>\n                  </div>\n                </div>\n              </div>\n            </Transition>\n            <div className=\"px-10 py-8\">\n              <SwitchTransition mode=\"out-in\">\n                <CSSTransition\n                  key={mediaServerLogin ? 'ms' : 'local'}\n                  nodeRef={loginRef}\n                  addEndListener={(done) => {\n                    loginRef.current?.addEventListener(\n                      'transitionend',\n                      done,\n                      false\n                    );\n                  }}\n                  onEntered={() => {\n                    document\n                      .querySelector<HTMLInputElement>('#email, #username')\n                      ?.focus();\n                  }}\n                  classNames={{\n                    appear: 'opacity-0',\n                    appearActive: 'transition-opacity duration-500 opacity-100',\n                    enter: 'opacity-0',\n                    enterActive: 'transition-opacity duration-500 opacity-100',\n                    exitActive: 'transition-opacity duration-0 opacity-0',\n                  }}\n                >\n                  <div ref={loginRef} className=\"button-container\">\n                    {isJellyfin &&\n                    (mediaServerLogin ||\n                      !settings.currentSettings.localLogin) ? (\n                      <JellyfinLogin\n                        serverType={settings.currentSettings.mediaServerType}\n                        revalidate={revalidate}\n                      />\n                    ) : (\n                      settings.currentSettings.localLogin && (\n                        <LocalLogin revalidate={revalidate} />\n                      )\n                    )}\n                  </div>\n                </CSSTransition>\n              </SwitchTransition>\n\n              {additionalLoginOptions.length > 0 &&\n                (loginFormVisible ? (\n                  <div className=\"flex items-center py-5\">\n                    <div className=\"flex-grow border-t border-gray-600\" />\n                    <span className=\"mx-2 flex-shrink text-sm text-gray-400\">\n                      {intl.formatMessage(messages.orsigninwith)}\n                    </span>\n                    <div className=\"flex-grow border-t border-gray-600\" />\n                  </div>\n                ) : (\n                  <h2 className=\"mb-6 text-center text-lg font-bold text-neutral-200\">\n                    {intl.formatMessage(messages.signinheader)}\n                  </h2>\n                ))}\n\n              <div\n                className={`flex w-full flex-wrap gap-2 ${\n                  !loginFormVisible ? 'flex-col' : ''\n                }`}\n              >\n                {additionalLoginOptions}\n              </div>\n            </div>\n          </>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default Login;\n"
  },
  {
    "path": "src/components/ManageSlideOver/index.tsx",
    "content": "import BlocklistBlock from '@app/components/BlocklistBlock';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport ConfirmButton from '@app/components/Common/ConfirmButton';\nimport SlideOver from '@app/components/Common/SlideOver';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport DownloadBlock from '@app/components/DownloadBlock';\nimport IssueBlock from '@app/components/IssueBlock';\nimport RequestBlock from '@app/components/RequestBlock';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Bars4Icon, ServerIcon } from '@heroicons/react/24/outline';\nimport {\n  CheckCircleIcon,\n  DocumentMinusIcon,\n  TrashIcon,\n} from '@heroicons/react/24/solid';\nimport { IssueStatus } from '@server/constants/issue';\nimport {\n  MediaRequestStatus,\n  MediaStatus,\n  MediaType,\n} from '@server/constants/media';\nimport { MediaServerType } from '@server/constants/server';\nimport type { MediaWatchDataResponse } from '@server/interfaces/api/mediaInterfaces';\nimport type { DownloadingItem } from '@server/lib/downloadtracker';\nimport type { RadarrSettings, SonarrSettings } from '@server/lib/settings';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport axios from 'axios';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst filterDuplicateDownloads = (\n  items: DownloadingItem[] = []\n): DownloadingItem[] => {\n  const seen = new Set<string>();\n  return items.filter((item) => {\n    if (seen.has(item.downloadId)) return false;\n    seen.add(item.downloadId);\n    return true;\n  });\n};\n\nconst messages = defineMessages('components.ManageSlideOver', {\n  manageModalTitle: 'Manage {mediaType}',\n  manageModalIssues: 'Open Issues',\n  manageModalRequests: 'Requests',\n  manageModalMedia: 'Media',\n  manageModalMedia4k: '4K Media',\n  manageModalAdvanced: 'Advanced',\n  manageModalNoRequests: 'No requests.',\n  manageModalClearMedia: 'Clear Data',\n  manageModalClearMediaWarning:\n    '* This will irreversibly remove all data for this {mediaType}, including any requests. If this item exists in your {mediaServerName} library, the media information will be recreated during the next scan.',\n  manageModalRemoveMediaWarning:\n    '* This will irreversibly remove this {mediaType} from {arr}, including all files.',\n  openarr: 'Open in {arr}',\n  removearr: 'Remove from {arr}',\n  openarr4k: 'Open in 4K {arr}',\n  removearr4k: 'Remove from 4K {arr}',\n  downloadstatus: 'Downloads',\n  markavailable: 'Mark as Available',\n  mark4kavailable: 'Mark as Available in 4K',\n  markallseasonsavailable: 'Mark All Seasons as Available',\n  markallseasons4kavailable: 'Mark All Seasons as Available in 4K',\n  opentautulli: 'Open in Tautulli',\n  plays:\n    '<strong>{playCount, number}</strong> {playCount, plural, one {play} other {plays}}',\n  pastdays: 'Past {days, number} Days',\n  alltime: 'All Time',\n  playedby: 'Played By',\n  movie: 'movie',\n  tvshow: 'series',\n});\n\nconst isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {\n  return (movie as MovieDetails).title !== undefined;\n};\n\ninterface ManageSlideOverProps {\n  // mediaType: 'movie' | 'tv';\n  show?: boolean;\n  onClose: () => void;\n  revalidate: () => void;\n}\n\ninterface ManageSlideOverMovieProps extends ManageSlideOverProps {\n  mediaType: 'movie';\n  data: MovieDetails;\n}\n\ninterface ManageSlideOverTvProps extends ManageSlideOverProps {\n  mediaType: 'tv';\n  data: TvDetails;\n}\n\nconst ManageSlideOver = ({\n  show,\n  mediaType,\n  onClose,\n  data,\n  revalidate,\n}: ManageSlideOverMovieProps | ManageSlideOverTvProps) => {\n  const { user: currentUser, hasPermission } = useUser();\n  const intl = useIntl();\n  const settings = useSettings();\n  const { data: watchData } = useSWR<MediaWatchDataResponse>(\n    settings.currentSettings.mediaServerType === MediaServerType.PLEX &&\n      data.mediaInfo &&\n      hasPermission(Permission.ADMIN)\n      ? `/api/v1/media/${data.mediaInfo.id}/watch_data`\n      : null\n  );\n  const { data: radarrData } = useSWR<RadarrSettings[]>(\n    hasPermission(Permission.ADMIN) ? '/api/v1/settings/radarr' : null\n  );\n  const { data: sonarrData } = useSWR<SonarrSettings[]>(\n    hasPermission(Permission.ADMIN) ? '/api/v1/settings/sonarr' : null\n  );\n\n  const deleteMedia = async () => {\n    if (data.mediaInfo) {\n      await axios.delete(`/api/v1/media/${data.mediaInfo.id}`);\n      revalidate();\n      onClose();\n    }\n  };\n\n  const deleteMediaFile = async (is4k = false) => {\n    if (data.mediaInfo) {\n      await axios.delete(\n        `/api/v1/media/${data.mediaInfo.id}/file?is4k=${is4k}`\n      );\n      await axios.delete(`/api/v1/media/${data.mediaInfo.id}`);\n      revalidate();\n      onClose();\n    }\n  };\n\n  const isDefaultService = () => {\n    if (data.mediaInfo) {\n      if (data.mediaInfo.mediaType === MediaType.MOVIE) {\n        return (\n          radarrData?.find(\n            (radarr) =>\n              radarr.isDefault && radarr.id === data.mediaInfo?.serviceId\n          ) !== undefined\n        );\n      } else {\n        return (\n          sonarrData?.find(\n            (sonarr) =>\n              sonarr.isDefault && sonarr.id === data.mediaInfo?.serviceId\n          ) !== undefined\n        );\n      }\n    }\n    return false;\n  };\n\n  const isDefault4kService = () => {\n    if (data.mediaInfo) {\n      if (data.mediaInfo.mediaType === MediaType.MOVIE) {\n        return (\n          radarrData?.find(\n            (radarr) =>\n              radarr.isDefault &&\n              radarr.is4k &&\n              radarr.id === data.mediaInfo?.serviceId4k\n          ) !== undefined\n        );\n      } else {\n        return (\n          sonarrData?.find(\n            (sonarr) =>\n              sonarr.isDefault &&\n              sonarr.is4k &&\n              sonarr.id === data.mediaInfo?.serviceId4k\n          ) !== undefined\n        );\n      }\n    }\n    return false;\n  };\n\n  const markAvailable = async (is4k = false) => {\n    if (data.mediaInfo) {\n      await axios.post(`/api/v1/media/${data.mediaInfo?.id}/available`, {\n        is4k,\n        ...(mediaType === 'tv' && {\n          seasons: data.seasons.filter((season) => season.seasonNumber !== 0),\n        }),\n      });\n      revalidate();\n    }\n  };\n\n  const requests =\n    data.mediaInfo?.requests?.filter(\n      (request) => request.status !== MediaRequestStatus.DECLINED\n    ) ?? [];\n\n  const openIssues =\n    data.mediaInfo?.issues?.filter(\n      (issue) => issue.status === IssueStatus.OPEN\n    ) ?? [];\n\n  const styledPlayCount = (playCount: number): JSX.Element => {\n    return (\n      <>\n        {intl.formatMessage(messages.plays, {\n          playCount,\n          strong: (msg: React.ReactNode) => (\n            <strong className=\"text-2xl font-semibold\">{msg}</strong>\n          ),\n        })}\n      </>\n    );\n  };\n\n  return (\n    <SlideOver\n      show={show}\n      title={intl.formatMessage(messages.manageModalTitle, {\n        mediaType: intl.formatMessage(\n          mediaType === 'movie' ? globalMessages.movie : globalMessages.tvshow\n        ),\n      })}\n      onClose={() => onClose()}\n      subText={isMovie(data) ? data.title : data.name}\n    >\n      <div className=\"space-y-6\">\n        {((data?.mediaInfo?.downloadStatus ?? []).length > 0 ||\n          (data?.mediaInfo?.downloadStatus4k ?? []).length > 0) && (\n          <div>\n            <h3 className=\"mb-2 text-xl font-bold\">\n              {intl.formatMessage(messages.downloadstatus)}\n            </h3>\n            <div className=\"overflow-hidden rounded-md border border-gray-700 shadow\">\n              <ul>\n                {filterDuplicateDownloads(data.mediaInfo?.downloadStatus).map(\n                  (status, index) => (\n                    <Tooltip\n                      key={`dl-status-${status.externalId}-${index}`}\n                      content={status.title}\n                    >\n                      <li className=\"border-b border-gray-700 last:border-b-0\">\n                        <DownloadBlock downloadItem={status} />\n                      </li>\n                    </Tooltip>\n                  )\n                )}\n                {filterDuplicateDownloads(data.mediaInfo?.downloadStatus4k).map(\n                  (status, index) => (\n                    <Tooltip\n                      key={`dl-status-4k-${status.externalId}-${index}`}\n                      content={status.title}\n                    >\n                      <li className=\"border-b border-gray-700 last:border-b-0\">\n                        <DownloadBlock downloadItem={status} is4k />\n                      </li>\n                    </Tooltip>\n                  )\n                )}\n              </ul>\n            </div>\n          </div>\n        )}\n        {hasPermission([Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES], {\n          type: 'or',\n        }) &&\n          openIssues.length > 0 && (\n            <div>\n              <h3 className=\"mb-2 text-xl font-bold\">\n                {intl.formatMessage(messages.manageModalIssues)}\n              </h3>\n              <div className=\"overflow-hidden rounded-md border border-gray-700 shadow\">\n                <ul>\n                  {openIssues.map((issue) => (\n                    <li\n                      key={`manage-issue-${issue.id}`}\n                      className=\"border-b border-gray-700 last:border-b-0\"\n                    >\n                      <IssueBlock issue={issue} />\n                    </li>\n                  ))}\n                </ul>\n              </div>\n            </div>\n          )}\n        {requests.length > 0 && (\n          <div>\n            <h3 className=\"mb-2 text-xl font-bold\">\n              {intl.formatMessage(messages.manageModalRequests)}\n            </h3>\n            <div className=\"overflow-hidden rounded-md border border-gray-700 shadow\">\n              <ul>\n                {requests.map((request) => (\n                  <li\n                    key={`manage-request-${request.id}`}\n                    className=\"border-b border-gray-700 last:border-b-0\"\n                  >\n                    <RequestBlock\n                      request={request}\n                      onUpdate={() => revalidate()}\n                    />\n                  </li>\n                ))}\n              </ul>\n            </div>\n          </div>\n        )}\n        {data.mediaInfo?.status === MediaStatus.BLOCKLISTED && (\n          <div>\n            <h3 className=\"mb-2 text-xl font-bold\">\n              {intl.formatMessage(globalMessages.blocklist)}\n            </h3>\n            <div className=\"overflow-hidden rounded-md border border-gray-700 shadow\">\n              <BlocklistBlock\n                tmdbId={data.mediaInfo.tmdbId}\n                mediaType={data.mediaInfo.mediaType}\n                onUpdate={() => revalidate()}\n                onDelete={() => onClose()}\n              />\n            </div>\n          </div>\n        )}\n        {hasPermission(Permission.ADMIN) &&\n          (data.mediaInfo?.serviceUrl ||\n            data.mediaInfo?.tautulliUrl ||\n            watchData?.data) && (\n            <div>\n              <h3 className=\"mb-2 text-xl font-bold\">\n                {intl.formatMessage(messages.manageModalMedia)}\n              </h3>\n              <div className=\"space-y-2\">\n                {(watchData?.data || data.mediaInfo?.tautulliUrl) && (\n                  <div>\n                    {!!watchData?.data && (\n                      <div\n                        className={`grid grid-cols-1 divide-y divide-gray-700 overflow-hidden border-gray-700 text-sm text-gray-300 shadow ${\n                          data.mediaInfo?.tautulliUrl\n                            ? 'rounded-t-md border-x border-t'\n                            : 'rounded-md border'\n                        }`}\n                      >\n                        <div className=\"grid grid-cols-3 divide-x divide-gray-700\">\n                          <div className=\"px-4 py-3\">\n                            <div className=\"font-bold\">\n                              {intl.formatMessage(messages.pastdays, {\n                                days: 7,\n                              })}\n                            </div>\n                            <div className=\"text-white\">\n                              {styledPlayCount(watchData.data.playCount7Days)}\n                            </div>\n                          </div>\n                          <div className=\"px-4 py-3\">\n                            <div className=\"font-bold\">\n                              {intl.formatMessage(messages.pastdays, {\n                                days: 30,\n                              })}\n                            </div>\n                            <div className=\"text-white\">\n                              {styledPlayCount(watchData.data.playCount30Days)}\n                            </div>\n                          </div>\n                          <div className=\"px-4 py-3\">\n                            <div className=\"font-bold\">\n                              {intl.formatMessage(messages.alltime)}\n                            </div>\n                            <div className=\"text-white\">\n                              {styledPlayCount(watchData.data.playCount)}\n                            </div>\n                          </div>\n                        </div>\n                        {!!watchData.data.users.length && (\n                          <div className=\"flex flex-row space-x-2 px-4 pb-2 pt-3\">\n                            <span className=\"shrink-0 font-bold leading-8\">\n                              {intl.formatMessage(messages.playedby)}\n                            </span>\n                            <span className=\"flex flex-row flex-wrap\">\n                              {watchData.data.users.map((user) => (\n                                <Link\n                                  href={\n                                    currentUser?.id === user.id\n                                      ? '/profile'\n                                      : `/users/${user.id}`\n                                  }\n                                  key={`watch-user-${user.id}`}\n                                  className=\"z-0 -mr-2 mb-1 shrink-0 hover:z-50\"\n                                >\n                                  <Tooltip\n                                    key={`watch-user-${user.id}`}\n                                    content={user.displayName}\n                                  >\n                                    <CachedImage\n                                      type=\"avatar\"\n                                      src={user.avatar}\n                                      alt={user.displayName}\n                                      className=\"h-8 w-8 scale-100 transform-gpu rounded-full object-cover ring-1 ring-gray-500 transition duration-300 hover:scale-105\"\n                                      width={32}\n                                      height={32}\n                                    />\n                                  </Tooltip>\n                                </Link>\n                              ))}\n                            </span>\n                          </div>\n                        )}\n                      </div>\n                    )}\n                    {data.mediaInfo?.tautulliUrl && (\n                      <a\n                        href={data.mediaInfo.tautulliUrl}\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        <Button\n                          buttonType=\"ghost\"\n                          className={`w-full ${\n                            watchData?.data ? 'rounded-t-none' : ''\n                          }`}\n                        >\n                          <Bars4Icon />\n                          <span>\n                            {intl.formatMessage(messages.opentautulli)}\n                          </span>\n                        </Button>\n                      </a>\n                    )}\n                  </div>\n                )}\n                {data.mediaInfo?.serviceUrl && (\n                  <a\n                    href={data?.mediaInfo?.serviceUrl}\n                    target=\"_blank\"\n                    rel=\"noreferrer\"\n                    className=\"block\"\n                  >\n                    <Button buttonType=\"ghost\" className=\"w-full\">\n                      <ServerIcon />\n                      <span>\n                        {intl.formatMessage(messages.openarr, {\n                          arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr',\n                        })}\n                      </span>\n                    </Button>\n                  </a>\n                )}\n\n                {hasPermission(Permission.ADMIN) &&\n                  data?.mediaInfo?.serviceUrl &&\n                  isDefaultService() && (\n                    <div>\n                      <ConfirmButton\n                        onClick={() => deleteMediaFile(false)}\n                        confirmText={intl.formatMessage(\n                          globalMessages.areyousure\n                        )}\n                        className=\"w-full\"\n                      >\n                        <TrashIcon />\n                        <span>\n                          {intl.formatMessage(messages.removearr, {\n                            arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr',\n                          })}\n                        </span>\n                      </ConfirmButton>\n                      <div className=\"mt-1 text-xs text-gray-400\">\n                        {intl.formatMessage(\n                          messages.manageModalRemoveMediaWarning,\n                          {\n                            mediaType: intl.formatMessage(\n                              mediaType === 'movie'\n                                ? messages.movie\n                                : messages.tvshow\n                            ),\n                            arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr',\n                          }\n                        )}\n                      </div>\n                    </div>\n                  )}\n              </div>\n            </div>\n          )}\n        {hasPermission(Permission.ADMIN) &&\n          (data.mediaInfo?.serviceUrl4k ||\n            data.mediaInfo?.tautulliUrl4k ||\n            watchData?.data4k) && (\n            <div>\n              <h3 className=\"mb-2 text-xl font-bold\">\n                {intl.formatMessage(messages.manageModalMedia4k)}\n              </h3>\n              <div className=\"space-y-2\">\n                {(watchData?.data4k || data.mediaInfo?.tautulliUrl4k) && (\n                  <div>\n                    {watchData?.data4k && (\n                      <div\n                        className={`grid grid-cols-1 divide-y divide-gray-700 overflow-hidden border-gray-700 text-sm text-gray-300 shadow ${\n                          data.mediaInfo?.tautulliUrl4k\n                            ? 'rounded-t-md border-x border-t'\n                            : 'rounded-md border'\n                        }`}\n                      >\n                        <div className=\"grid grid-cols-3 divide-x divide-gray-700\">\n                          <div className=\"px-4 py-3\">\n                            <div className=\"font-bold\">\n                              {intl.formatMessage(messages.pastdays, {\n                                days: 7,\n                              })}\n                            </div>\n                            <div className=\"text-white\">\n                              {styledPlayCount(watchData.data4k.playCount7Days)}\n                            </div>\n                          </div>\n                          <div className=\"px-4 py-3\">\n                            <div className=\"font-bold\">\n                              {intl.formatMessage(messages.pastdays, {\n                                days: 30,\n                              })}\n                            </div>\n                            <div className=\"text-white\">\n                              {styledPlayCount(\n                                watchData.data4k.playCount30Days\n                              )}\n                            </div>\n                          </div>\n                          <div className=\"px-4 py-3\">\n                            <div className=\"font-bold\">\n                              {intl.formatMessage(messages.alltime)}\n                            </div>\n                            <div className=\"text-white\">\n                              {styledPlayCount(watchData.data4k.playCount)}\n                            </div>\n                          </div>\n                        </div>\n                        {!!watchData.data4k.users.length && (\n                          <div className=\"flex flex-row space-x-2 px-4 pb-2 pt-3\">\n                            <span className=\"shrink-0 font-bold leading-8\">\n                              {intl.formatMessage(messages.playedby)}\n                            </span>\n                            <span className=\"flex flex-row flex-wrap\">\n                              {watchData.data4k.users.map((user) => (\n                                <Link\n                                  href={\n                                    currentUser?.id === user.id\n                                      ? '/profile'\n                                      : `/users/${user.id}`\n                                  }\n                                  key={`watch-user-${user.id}`}\n                                  className=\"z-0 -mr-2 mb-1 shrink-0 hover:z-50\"\n                                >\n                                  <Tooltip\n                                    key={`watch-user-${user.id}`}\n                                    content={user.displayName}\n                                  >\n                                    <CachedImage\n                                      type=\"avatar\"\n                                      src={user.avatar}\n                                      alt={user.displayName}\n                                      className=\"h-8 w-8 scale-100 transform-gpu rounded-full object-cover ring-1 ring-gray-500 transition duration-300 hover:scale-105\"\n                                      width={32}\n                                      height={32}\n                                    />\n                                  </Tooltip>\n                                </Link>\n                              ))}\n                            </span>\n                          </div>\n                        )}\n                      </div>\n                    )}\n                    {data.mediaInfo?.tautulliUrl4k && (\n                      <a\n                        href={data.mediaInfo.tautulliUrl4k}\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        <Button\n                          buttonType=\"ghost\"\n                          className={`w-full ${\n                            watchData?.data4k ? 'rounded-t-none' : ''\n                          }`}\n                        >\n                          <Bars4Icon />\n                          <span>\n                            {intl.formatMessage(messages.opentautulli)}\n                          </span>\n                        </Button>\n                      </a>\n                    )}\n                  </div>\n                )}\n                {data?.mediaInfo?.serviceUrl4k && (\n                  <>\n                    <a\n                      href={data?.mediaInfo?.serviceUrl4k}\n                      target=\"_blank\"\n                      rel=\"noreferrer\"\n                      className=\"block\"\n                    >\n                      <Button buttonType=\"ghost\" className=\"w-full\">\n                        <ServerIcon />\n                        <span>\n                          {intl.formatMessage(messages.openarr4k, {\n                            arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr',\n                          })}\n                        </span>\n                      </Button>\n                    </a>\n                    {isDefault4kService() && (\n                      <div>\n                        <ConfirmButton\n                          onClick={() => deleteMediaFile(true)}\n                          confirmText={intl.formatMessage(\n                            globalMessages.areyousure\n                          )}\n                          className=\"w-full\"\n                        >\n                          <TrashIcon />\n                          <span>\n                            {intl.formatMessage(messages.removearr4k, {\n                              arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr',\n                            })}\n                          </span>\n                        </ConfirmButton>\n                        <div className=\"mt-1 text-xs text-gray-400\">\n                          {intl.formatMessage(\n                            messages.manageModalRemoveMediaWarning,\n                            {\n                              mediaType: intl.formatMessage(\n                                mediaType === 'movie'\n                                  ? messages.movie\n                                  : messages.tvshow\n                              ),\n                              arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr',\n                            }\n                          )}\n                        </div>\n                      </div>\n                    )}\n                  </>\n                )}\n              </div>\n            </div>\n          )}\n        {hasPermission(Permission.ADMIN) &&\n          data?.mediaInfo &&\n          data.mediaInfo.status !== MediaStatus.BLOCKLISTED && (\n            <div>\n              <h3 className=\"mb-2 text-xl font-bold\">\n                {intl.formatMessage(messages.manageModalAdvanced)}\n              </h3>\n              <div className=\"space-y-2\">\n                {data?.mediaInfo.status !== MediaStatus.AVAILABLE && (\n                  <Button\n                    onClick={() => markAvailable()}\n                    className=\"w-full\"\n                    buttonType=\"success\"\n                  >\n                    <CheckCircleIcon />\n                    <span>\n                      {intl.formatMessage(\n                        mediaType === 'movie'\n                          ? messages.markavailable\n                          : messages.markallseasonsavailable\n                      )}\n                    </span>\n                  </Button>\n                )}\n                {data?.mediaInfo.status4k !== MediaStatus.AVAILABLE &&\n                  settings.currentSettings.series4kEnabled && (\n                    <Button\n                      onClick={() => markAvailable(true)}\n                      className=\"w-full\"\n                      buttonType=\"success\"\n                    >\n                      <CheckCircleIcon />\n                      <span>\n                        {intl.formatMessage(\n                          mediaType === 'movie'\n                            ? messages.mark4kavailable\n                            : messages.markallseasons4kavailable\n                        )}\n                      </span>\n                    </Button>\n                  )}\n                <div>\n                  <ConfirmButton\n                    onClick={() => deleteMedia()}\n                    confirmText={intl.formatMessage(globalMessages.areyousure)}\n                    className=\"w-full\"\n                  >\n                    <DocumentMinusIcon />\n                    <span>\n                      {intl.formatMessage(messages.manageModalClearMedia)}\n                    </span>\n                  </ConfirmButton>\n                  <div className=\"mt-2 text-xs text-gray-400\">\n                    {intl.formatMessage(messages.manageModalClearMediaWarning, {\n                      mediaType: intl.formatMessage(\n                        mediaType === 'movie' ? messages.movie : messages.tvshow\n                      ),\n                      mediaServerName:\n                        settings.currentSettings.mediaServerType ===\n                        MediaServerType.EMBY\n                          ? 'Emby'\n                          : settings.currentSettings.mediaServerType ===\n                              MediaServerType.PLEX\n                            ? 'Plex'\n                            : 'Jellyfin',\n                    })}\n                  </div>\n                </div>\n              </div>\n            </div>\n          )}\n      </div>\n    </SlideOver>\n  );\n};\n\nexport default ManageSlideOver;\n"
  },
  {
    "path": "src/components/MediaSlider/ShowMoreCard/index.tsx",
    "content": "import CachedImage from '@app/components/Common/CachedImage';\nimport TitleCard from '@app/components/TitleCard';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowRightCircleIcon } from '@heroicons/react/24/solid';\nimport Link from 'next/link';\nimport { useState } from 'react';\nimport { useInView } from 'react-intersection-observer';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.MediaSlider.ShowMoreCard', {\n  seemore: 'See More',\n});\n\ninterface ShowMoreCardProps {\n  url: string;\n  posters: (string | undefined)[];\n}\n\nconst ShowMoreCard = ({ url, posters }: ShowMoreCardProps) => {\n  const intl = useIntl();\n  const [isHovered, setHovered] = useState(false);\n  const { ref, inView } = useInView({\n    triggerOnce: true,\n  });\n\n  if (!inView) {\n    return (\n      <div ref={ref}>\n        <TitleCard.Placeholder />\n      </div>\n    );\n  }\n\n  return (\n    <Link\n      href={url}\n      className={'w-36 sm:w-36 md:w-44'}\n      onMouseEnter={() => {\n        setHovered(true);\n      }}\n      onMouseLeave={() => setHovered(false)}\n      onKeyDown={(e) => {\n        if (e.key === 'Enter') {\n          setHovered(true);\n        }\n      }}\n      role=\"link\"\n      tabIndex={0}\n    >\n      <div\n        className={`relative w-36 transform-gpu cursor-pointer overflow-hidden rounded-xl text-white shadow-lg ring-1 transition duration-150 ease-in-out sm:w-36 md:w-44 ${\n          isHovered\n            ? 'scale-105 bg-gray-600 ring-gray-500'\n            : 'scale-100 bg-gray-800 ring-gray-700'\n        }`}\n      >\n        <div style={{ paddingBottom: '150%' }}>\n          <div className=\"absolute inset-0 flex h-full w-full flex-col items-center p-2\">\n            <div className=\"relative z-10 grid h-full w-full grid-cols-2 items-center justify-center gap-2 opacity-30\">\n              {posters[0] && (\n                <div className=\"\">\n                  <CachedImage\n                    type=\"tmdb\"\n                    src={`https://image.tmdb.org/t/p/w300_and_h450_face${posters[0]}`}\n                    alt=\"\"\n                    className=\"rounded-md\"\n                    width={300}\n                    height={450}\n                  />\n                </div>\n              )}\n              {posters[1] && (\n                <div className=\"\">\n                  <CachedImage\n                    type=\"tmdb\"\n                    src={`https://image.tmdb.org/t/p/w300_and_h450_face${posters[1]}`}\n                    alt=\"\"\n                    className=\"rounded-md\"\n                    width={300}\n                    height={450}\n                  />\n                </div>\n              )}\n              {posters[2] && (\n                <div className=\"\">\n                  <CachedImage\n                    type=\"tmdb\"\n                    src={`https://image.tmdb.org/t/p/w300_and_h450_face${posters[2]}`}\n                    alt=\"\"\n                    className=\"rounded-md\"\n                    width={300}\n                    height={450}\n                  />\n                </div>\n              )}\n              {posters[3] && (\n                <div className=\"\">\n                  <CachedImage\n                    type=\"tmdb\"\n                    src={`https://image.tmdb.org/t/p/w300_and_h450_face${posters[3]}`}\n                    alt=\"\"\n                    className=\"rounded-md\"\n                    width={300}\n                    height={450}\n                  />\n                </div>\n              )}\n            </div>\n            <div className=\"absolute inset-0 z-20 flex flex-col items-center justify-center text-white\">\n              <ArrowRightCircleIcon className=\"w-14\" />\n              <div className=\"mt-2 font-extrabold\">\n                {intl.formatMessage(messages.seemore)}\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </Link>\n  );\n};\n\nexport default ShowMoreCard;\n"
  },
  {
    "path": "src/components/MediaSlider/index.tsx",
    "content": "import ShowMoreCard from '@app/components/MediaSlider/ShowMoreCard';\nimport PersonCard from '@app/components/PersonCard';\nimport Slider from '@app/components/Slider';\nimport TitleCard from '@app/components/TitleCard';\nimport useSettings from '@app/hooks/useSettings';\nimport { useUser } from '@app/hooks/useUser';\nimport { ArrowRightCircleIcon } from '@heroicons/react/24/outline';\nimport { MediaStatus } from '@server/constants/media';\nimport { Permission } from '@server/lib/permissions';\nimport type {\n  MovieResult,\n  PersonResult,\n  TvResult,\n} from '@server/models/Search';\nimport Link from 'next/link';\nimport { useEffect } from 'react';\nimport useSWRInfinite from 'swr/infinite';\n\ninterface MixedResult {\n  page: number;\n  totalResults: number;\n  totalPages: number;\n  results: (TvResult | MovieResult | PersonResult)[];\n}\n\ninterface MediaSliderProps {\n  title: string;\n  url: string;\n  linkUrl?: string;\n  sliderKey: string;\n  hideWhenEmpty?: boolean;\n  extraParams?: string;\n  onNewTitles?: (titleCount: number) => void;\n}\n\nconst MediaSlider = ({\n  title,\n  url,\n  linkUrl,\n  extraParams,\n  sliderKey,\n  hideWhenEmpty = false,\n  onNewTitles,\n}: MediaSliderProps) => {\n  const settings = useSettings();\n  const { hasPermission } = useUser();\n  const { data, error, setSize, size } = useSWRInfinite<MixedResult>(\n    (pageIndex: number, previousPageData: MixedResult | null) => {\n      if (previousPageData && pageIndex + 1 > previousPageData.totalPages) {\n        return null;\n      }\n\n      return `${url}?page=${pageIndex + 1}${\n        extraParams ? `&${extraParams}` : ''\n      }`;\n    },\n    {\n      initialSize: 2,\n      revalidateFirstPage: false,\n    }\n  );\n\n  let titles = (data ?? []).reduce(\n    (a, v) => [...a, ...v.results],\n    [] as (MovieResult | TvResult | PersonResult)[]\n  );\n\n  if (settings.currentSettings.hideAvailable) {\n    titles = titles.filter(\n      (i) =>\n        (i.mediaType === 'movie' || i.mediaType === 'tv') &&\n        i.mediaInfo?.status !== MediaStatus.AVAILABLE &&\n        i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE\n    );\n  }\n\n  if (settings.currentSettings.hideBlocklisted) {\n    titles = titles.filter(\n      (i) =>\n        (i.mediaType === 'movie' || i.mediaType === 'tv') &&\n        i.mediaInfo?.status !== MediaStatus.BLOCKLISTED\n    );\n  }\n\n  useEffect(() => {\n    if (\n      titles.length < 24 &&\n      size < 5 &&\n      (data?.[0]?.totalResults ?? 0) > size * 20\n    ) {\n      setSize(size + 1);\n    }\n\n    if (onNewTitles) {\n      // We aren't reporting all titles. We just want to know if there are any titles\n      // at all for our purposes.\n      onNewTitles(titles.length);\n    }\n  }, [titles, setSize, size, data, onNewTitles]);\n\n  if (hideWhenEmpty && (data?.[0].results ?? []).length === 0) {\n    return null;\n  }\n\n  const blocklistVisibility = hasPermission(\n    [Permission.MANAGE_BLOCKLIST, Permission.VIEW_BLOCKLIST],\n    { type: 'or' }\n  );\n\n  const finalTitles = titles\n    .slice(0, 20)\n    .filter((title) => {\n      if (!blocklistVisibility)\n        return (\n          (title as TvResult | MovieResult).mediaInfo?.status !==\n          MediaStatus.BLOCKLISTED\n        );\n      return title;\n    })\n    .map((title) => {\n      switch (title.mediaType) {\n        case 'movie':\n          return (\n            <TitleCard\n              key={title.id}\n              id={title.id}\n              isAddedToWatchlist={title.mediaInfo?.watchlists?.length ?? 0}\n              image={title.posterPath}\n              status={title.mediaInfo?.status}\n              summary={title.overview}\n              title={title.title}\n              userScore={title.voteAverage}\n              year={title.releaseDate}\n              mediaType={title.mediaType}\n              inProgress={(title.mediaInfo?.downloadStatus ?? []).length > 0}\n            />\n          );\n        case 'tv':\n          return (\n            <TitleCard\n              key={title.id}\n              id={title.id}\n              isAddedToWatchlist={title.mediaInfo?.watchlists?.length ?? 0}\n              image={title.posterPath}\n              status={title.mediaInfo?.status}\n              summary={title.overview}\n              title={title.name}\n              userScore={title.voteAverage}\n              year={title.firstAirDate}\n              mediaType={title.mediaType}\n              inProgress={(title.mediaInfo?.downloadStatus ?? []).length > 0}\n            />\n          );\n        case 'person':\n          return (\n            <PersonCard\n              personId={title.id}\n              name={title.name}\n              profilePath={title.profilePath}\n            />\n          );\n      }\n    });\n\n  if (linkUrl && titles.length > 20) {\n    finalTitles.push(\n      <ShowMoreCard\n        url={linkUrl}\n        posters={titles\n          .slice(20, 24)\n          .map((title) =>\n            title.mediaType !== 'person' ? title.posterPath : undefined\n          )}\n      />\n    );\n  }\n\n  return (\n    <>\n      <div className=\"slider-header\">\n        {linkUrl ? (\n          <Link href={linkUrl} className=\"slider-title min-w-0 pr-16\">\n            <span className=\"truncate\">{title}</span>\n            <ArrowRightCircleIcon />\n          </Link>\n        ) : (\n          <div className=\"slider-title\">\n            <span>{title}</span>\n          </div>\n        )}\n      </div>\n      <Slider\n        sliderKey={sliderKey}\n        isLoading={!data && !error}\n        isEmpty={false}\n        items={finalTitles}\n      />\n    </>\n  );\n};\n\nexport default MediaSlider;\n"
  },
  {
    "path": "src/components/MetadataSelector/index.tsx",
    "content": "import defineMessages from '@app/utils/defineMessages';\nimport { useIntl } from 'react-intl';\nimport Select, { type StylesConfig } from 'react-select';\n\nenum MetadataProviderType {\n  TMDB = 'tmdb',\n  TVDB = 'tvdb',\n}\n\ntype MetadataProviderOptionType = {\n  testId?: string;\n  value: MetadataProviderType;\n  label: string;\n};\n\nconst messages = defineMessages('components.MetadataSelector', {\n  tmdbLabel: 'The Movie Database (TMDB)',\n  tvdbLabel: 'TheTVDB',\n  selectMetdataProvider: 'Select a metadata provider',\n});\n\ninterface MetadataSelectorProps {\n  testId: string;\n  value: MetadataProviderType;\n  onChange: (value: MetadataProviderType) => void;\n  isDisabled?: boolean;\n}\n\nconst MetadataSelector = ({\n  testId = 'metadata-provider-selector',\n  value,\n  onChange,\n  isDisabled = false,\n}: MetadataSelectorProps) => {\n  const intl = useIntl();\n\n  const metadataProviderOptions: MetadataProviderOptionType[] = [\n    {\n      testId: 'tmdb-option',\n      value: MetadataProviderType.TMDB,\n      label: intl.formatMessage(messages.tmdbLabel),\n    },\n    {\n      testId: 'tvdb-option',\n      value: MetadataProviderType.TVDB,\n      label: intl.formatMessage(messages.tvdbLabel),\n    },\n  ];\n\n  const customStyles: StylesConfig<MetadataProviderOptionType, false> = {\n    option: (base) => ({\n      ...base,\n      display: 'flex',\n      alignItems: 'center',\n    }),\n    singleValue: (base) => ({\n      ...base,\n      display: 'flex',\n      alignItems: 'center',\n    }),\n  };\n\n  const formatOptionLabel = (option: MetadataProviderOptionType) => (\n    <div className=\"flex items-center\">\n      <span data-testid={option.testId}>{option.label}</span>\n    </div>\n  );\n\n  return (\n    <div data-testid={testId}>\n      <Select\n        options={metadataProviderOptions}\n        isDisabled={isDisabled}\n        className=\"react-select-container\"\n        classNamePrefix=\"react-select\"\n        value={metadataProviderOptions.find((option) => option.value === value)}\n        onChange={(selectedOption) => {\n          if (selectedOption) {\n            onChange(selectedOption.value);\n          }\n        }}\n        placeholder={intl.formatMessage(messages.selectMetdataProvider)}\n        styles={customStyles}\n        formatOptionLabel={formatOptionLabel}\n      />\n    </div>\n  );\n};\n\nexport { MetadataProviderType };\nexport default MetadataSelector;\n"
  },
  {
    "path": "src/components/MovieDetails/MovieCast/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport PersonCard from '@app/components/PersonCard';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { MovieDetails } from '@server/models/Movie';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.MovieDetails.MovieCast', {\n  fullcast: 'Full Cast',\n});\n\nconst MovieCast = () => {\n  const router = useRouter();\n  const intl = useIntl();\n  const { data, error } = useSWR<MovieDetails>(\n    `/api/v1/movie/${router.query.movieId}`\n  );\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  return (\n    <>\n      <PageTitle title={[intl.formatMessage(messages.fullcast), data.title]} />\n      <div className=\"mb-5 mt-1\">\n        <Header\n          subtext={\n            <Link href={`/movie/${data.id}`} className=\"hover:underline\">\n              {data.title}\n            </Link>\n          }\n        >\n          {intl.formatMessage(messages.fullcast)}\n        </Header>\n      </div>\n      <ul className=\"cards-vertical\">\n        {data?.credits.cast.map((person, index) => {\n          return (\n            <li key={`cast-${person.id}-${index}`}>\n              <PersonCard\n                name={person.name}\n                personId={person.id}\n                subName={person.character}\n                profilePath={person.profilePath}\n                canExpand\n              />\n            </li>\n          );\n        })}\n      </ul>\n    </>\n  );\n};\n\nexport default MovieCast;\n"
  },
  {
    "path": "src/components/MovieDetails/MovieCrew/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport PersonCard from '@app/components/PersonCard';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { MovieDetails } from '@server/models/Movie';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.MovieDetails.MovieCrew', {\n  fullcrew: 'Full Crew',\n});\n\nconst MovieCrew = () => {\n  const router = useRouter();\n  const intl = useIntl();\n  const { data, error } = useSWR<MovieDetails>(\n    `/api/v1/movie/${router.query.movieId}`\n  );\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  return (\n    <>\n      <PageTitle title={[intl.formatMessage(messages.fullcrew), data.title]} />\n      <div className=\"mb-5 mt-1\">\n        <Header\n          subtext={\n            <Link href={`/movie/${data.id}`} className=\"hover:underline\">\n              {data.title}\n            </Link>\n          }\n        >\n          {intl.formatMessage(messages.fullcrew)}\n        </Header>\n      </div>\n      <ul className=\"cards-vertical\">\n        {data?.credits.crew.map((person, index) => {\n          return (\n            <li key={`crew-${person.id}-${index}`}>\n              <PersonCard\n                name={person.name}\n                personId={person.id}\n                subName={person.job}\n                profilePath={person.profilePath}\n                canExpand\n              />\n            </li>\n          );\n        })}\n      </ul>\n    </>\n  );\n};\n\nexport default MovieCrew;\n"
  },
  {
    "path": "src/components/MovieDetails/MovieRecommendations.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { MovieResult } from '@server/models/Search';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.MovieDetails', {\n  recommendations: 'Recommendations',\n});\n\nconst MovieRecommendations = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const { data: movieData } = useSWR<MovieDetails>(\n    `/api/v1/movie/${router.query.movieId}`\n  );\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<MovieResult>(\n    `/api/v1/movie/${router.query.movieId}/recommendations`\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[intl.formatMessage(messages.recommendations), movieData?.title]}\n      />\n      <div className=\"mb-5 mt-1\">\n        <Header\n          subtext={\n            <Link href={`/movie/${movieData?.id}`} className=\"hover:underline\">\n              {movieData?.title}\n            </Link>\n          }\n        >\n          {intl.formatMessage(messages.recommendations)}\n        </Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isReachingEnd={isReachingEnd}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default MovieRecommendations;\n"
  },
  {
    "path": "src/components/MovieDetails/MovieSimilar.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { MovieResult } from '@server/models/Search';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.MovieDetails', {\n  similar: 'Similar Titles',\n});\n\nconst MovieSimilar = () => {\n  const router = useRouter();\n  const intl = useIntl();\n  const { data: movieData } = useSWR<MovieDetails>(\n    `/api/v1/movie/${router.query.movieId}`\n  );\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<MovieResult>(`/api/v1/movie/${router.query.movieId}/similar`);\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[intl.formatMessage(messages.similar), movieData?.title]}\n      />\n      <div className=\"mb-5 mt-1\">\n        <Header\n          subtext={\n            <Link href={`/movie/${movieData?.id}`} className=\"hover:underline\">\n              {movieData?.title}\n            </Link>\n          }\n        >\n          {intl.formatMessage(messages.similar)}\n        </Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default MovieSimilar;\n"
  },
  {
    "path": "src/components/MovieDetails/index.tsx",
    "content": "import RTAudFresh from '@app/assets/rt_aud_fresh.svg';\nimport RTAudRotten from '@app/assets/rt_aud_rotten.svg';\nimport RTFresh from '@app/assets/rt_fresh.svg';\nimport RTRotten from '@app/assets/rt_rotten.svg';\nimport ImdbLogo from '@app/assets/services/imdb.svg';\nimport Spinner from '@app/assets/spinner.svg';\nimport TmdbLogo from '@app/assets/tmdb_logo.svg';\nimport BlocklistModal from '@app/components/BlocklistModal';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport type { PlayButtonLink } from '@app/components/Common/PlayButton';\nimport PlayButton from '@app/components/Common/PlayButton';\nimport Tag from '@app/components/Common/Tag';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport ExternalLinkBlock from '@app/components/ExternalLinkBlock';\nimport IssueModal from '@app/components/IssueModal';\nimport ManageSlideOver from '@app/components/ManageSlideOver';\nimport MediaSlider from '@app/components/MediaSlider';\nimport PersonCard from '@app/components/PersonCard';\nimport RequestButton from '@app/components/RequestButton';\nimport Slider from '@app/components/Slider';\nimport StatusBadge from '@app/components/StatusBadge';\nimport useDeepLinks from '@app/hooks/useDeepLinks';\nimport useLocale from '@app/hooks/useLocale';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, UserType, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport { sortCrewPriority } from '@app/utils/creditHelpers';\nimport defineMessages from '@app/utils/defineMessages';\nimport { refreshIntervalHelper } from '@app/utils/refreshIntervalHelper';\nimport {\n  ArrowRightCircleIcon,\n  CloudIcon,\n  CogIcon,\n  ExclamationTriangleIcon,\n  EyeSlashIcon,\n  FilmIcon,\n  MinusCircleIcon,\n  PlayIcon,\n  StarIcon,\n  TicketIcon,\n} from '@heroicons/react/24/outline';\nimport {\n  ChevronDoubleDownIcon,\n  ChevronDoubleUpIcon,\n} from '@heroicons/react/24/solid';\nimport { type RatingResponse } from '@server/api/ratings';\nimport { IssueStatus } from '@server/constants/issue';\nimport { MediaStatus, MediaType } from '@server/constants/media';\nimport { MediaServerType } from '@server/constants/server';\nimport type { MovieDetails as MovieDetailsType } from '@server/models/Movie';\nimport axios from 'axios';\nimport { countries } from 'country-flag-icons';\nimport 'country-flag-icons/3x2/flags.css';\nimport { uniqBy } from 'lodash';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.MovieDetails', {\n  originaltitle: 'Original Title',\n  releasedate:\n    '{releaseCount, plural, one {Release Date} other {Release Dates}}',\n  revenue: 'Revenue',\n  budget: 'Budget',\n  watchtrailer: 'Watch Trailer',\n  originallanguage: 'Original Language',\n  overview: 'Overview',\n  runtime: '{minutes} minutes',\n  cast: 'Cast',\n  recommendations: 'Recommendations',\n  similar: 'Similar Titles',\n  overviewunavailable: 'Overview unavailable.',\n  studio: '{studioCount, plural, one {Studio} other {Studios}}',\n  viewfullcrew: 'View Full Crew',\n  openradarr: 'Open Movie in Radarr',\n  openradarr4k: 'Open Movie in 4K Radarr',\n  downloadstatus: 'Download Status',\n  play: 'Play on {mediaServerName}',\n  play4k: 'Play 4K on {mediaServerName}',\n  markavailable: 'Mark as Available',\n  mark4kavailable: 'Mark as Available in 4K',\n  showmore: 'Show More',\n  showless: 'Show Less',\n  streamingproviders: 'Currently Streaming On',\n  productioncountries:\n    'Production {countryCount, plural, one {Country} other {Countries}}',\n  theatricalrelease: 'Theatrical Release',\n  digitalrelease: 'Digital Release',\n  physicalrelease: 'Physical Release',\n  reportissue: 'Report an Issue',\n  managemovie: 'Manage Movie',\n  rtcriticsscore: 'Rotten Tomatoes Tomatometer',\n  rtaudiencescore: 'Rotten Tomatoes Audience Score',\n  tmdbuserscore: 'TMDB User Score',\n  imdbuserscore: 'IMDB User Score – votes: {formattedCount}',\n  watchlistSuccess: '<strong>{title}</strong> added to watchlist successfully!',\n  watchlistDeleted:\n    '<strong>{title}</strong> Removed from watchlist successfully!',\n  watchlistError: 'Something went wrong. Please try again.',\n  removefromwatchlist: 'Remove From Watchlist',\n  addtowatchlist: 'Add To Watchlist',\n});\n\ninterface MovieDetailsProps {\n  movie?: MovieDetailsType;\n}\n\nconst MovieDetails = ({ movie }: MovieDetailsProps) => {\n  const settings = useSettings();\n  const { user, hasPermission } = useUser();\n  const router = useRouter();\n  const intl = useIntl();\n  const { locale } = useLocale();\n  const [showManager, setShowManager] = useState(\n    router.query.manage == '1' ? true : false\n  );\n  const minStudios = 3;\n  const [showMoreStudios, setShowMoreStudios] = useState(false);\n  const [showIssueModal, setShowIssueModal] = useState(false);\n  const [isUpdating, setIsUpdating] = useState<boolean>(false);\n  const [toggleWatchlist, setToggleWatchlist] = useState<boolean>(\n    !movie?.onUserWatchlist\n  );\n  const [isBlocklistUpdating, setIsBlocklistUpdating] =\n    useState<boolean>(false);\n  const [showBlocklistModal, setShowBlocklistModal] = useState(false);\n  const { addToast } = useToasts();\n\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<MovieDetailsType>(`/api/v1/movie/${router.query.movieId}`, {\n    fallbackData: movie,\n    refreshInterval: refreshIntervalHelper(\n      {\n        downloadStatus: movie?.mediaInfo?.downloadStatus,\n        downloadStatus4k: movie?.mediaInfo?.downloadStatus4k,\n      },\n      15000\n    ),\n  });\n\n  const { data: ratingData } = useSWR<RatingResponse>(\n    `/api/v1/movie/${router.query.movieId}/ratingscombined`\n  );\n\n  const sortedCrew = useMemo(\n    () => sortCrewPriority(data?.credits.crew ?? []),\n    [data]\n  );\n\n  useEffect(() => {\n    setShowManager(router.query.manage == '1' ? true : false);\n  }, [router.query.manage]);\n\n  const closeBlocklistModal = useCallback(\n    () => setShowBlocklistModal(false),\n    []\n  );\n\n  const { mediaUrl: plexUrl, mediaUrl4k: plexUrl4k } = useDeepLinks({\n    mediaUrl: data?.mediaInfo?.mediaUrl,\n    mediaUrl4k: data?.mediaInfo?.mediaUrl4k,\n    iOSPlexUrl: data?.mediaInfo?.iOSPlexUrl,\n    iOSPlexUrl4k: data?.mediaInfo?.iOSPlexUrl4k,\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  const showAllStudios = data.productionCompanies.length <= minStudios + 1;\n  const mediaLinks: PlayButtonLink[] = [];\n\n  if (\n    plexUrl &&\n    hasPermission([Permission.REQUEST, Permission.REQUEST_MOVIE], {\n      type: 'or',\n    })\n  ) {\n    mediaLinks.push({\n      text: getAvailableMediaServerName(),\n      url: plexUrl,\n      svg: <PlayIcon />,\n    });\n  }\n\n  if (\n    settings.currentSettings.movie4kEnabled &&\n    plexUrl4k &&\n    hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE], {\n      type: 'or',\n    })\n  ) {\n    mediaLinks.push({\n      text: getAvailable4kMediaServerName(),\n      url: plexUrl4k,\n      svg: <PlayIcon />,\n    });\n  }\n\n  const trailerVideo = data.relatedVideos\n    ?.filter((r) => r.type === 'Trailer')\n    .sort((a, b) => a.size - b.size)\n    .pop();\n  const trailerUrl =\n    trailerVideo?.site === 'YouTube' &&\n    settings.currentSettings.youtubeUrl != ''\n      ? `${settings.currentSettings.youtubeUrl}${trailerVideo?.key}`\n      : trailerVideo?.url;\n\n  if (trailerUrl) {\n    mediaLinks.push({\n      text: intl.formatMessage(messages.watchtrailer),\n      url: trailerUrl,\n      svg: <FilmIcon />,\n    });\n  }\n\n  const discoverRegion = user?.settings?.discoverRegion\n    ? user.settings.discoverRegion\n    : settings.currentSettings.discoverRegion\n      ? settings.currentSettings.discoverRegion\n      : 'US';\n\n  const releases = data.releases.results.find(\n    (r) => r.iso_3166_1 === discoverRegion\n  )?.release_dates;\n\n  // Release date types:\n  // 1. Premiere\n  // 2. Theatrical (limited)\n  // 3. Theatrical\n  // 4. Digital\n  // 5. Physical\n  // 6. TV\n  const filteredReleases = uniqBy(\n    releases?.filter((r) => r.type > 2 && r.type < 6),\n    'type'\n  );\n\n  const movieAttributes: React.ReactNode[] = [];\n\n  const certification = releases?.find((r) => r.certification)?.certification;\n  if (certification) {\n    movieAttributes.push(\n      <span className=\"rounded-md border p-0.5 py-0\">{certification}</span>\n    );\n  }\n\n  if (data.runtime) {\n    movieAttributes.push(\n      intl.formatMessage(messages.runtime, { minutes: data.runtime })\n    );\n  }\n\n  if (data.genres.length) {\n    movieAttributes.push(\n      data.genres\n        .map((g) => (\n          <Link\n            href={`/discover/movies?genre=${g.id}`}\n            key={`genre-${g.id}`}\n            className=\"hover:underline\"\n          >\n            {g.name}\n          </Link>\n        ))\n        .reduce((prev, curr) => (\n          <>\n            {intl.formatMessage(globalMessages.delimitedlist, {\n              a: prev,\n              b: curr,\n            })}\n          </>\n        ))\n    );\n  }\n\n  const streamingRegion = user?.settings?.streamingRegion\n    ? user.settings.streamingRegion\n    : settings.currentSettings.streamingRegion\n      ? settings.currentSettings.streamingRegion\n      : 'US';\n  const streamingProviders =\n    data?.watchProviders?.find(\n      (provider) => provider.iso_3166_1 === streamingRegion\n    )?.flatrate ?? [];\n\n  function getAvailableMediaServerName() {\n    if (settings.currentSettings.mediaServerType === MediaServerType.EMBY) {\n      return intl.formatMessage(messages.play, { mediaServerName: 'Emby' });\n    }\n\n    if (settings.currentSettings.mediaServerType === MediaServerType.PLEX) {\n      return intl.formatMessage(messages.play, { mediaServerName: 'Plex' });\n    }\n\n    return intl.formatMessage(messages.play, { mediaServerName: 'Jellyfin' });\n  }\n\n  function getAvailable4kMediaServerName() {\n    if (settings.currentSettings.mediaServerType === MediaServerType.EMBY) {\n      return intl.formatMessage(messages.play, { mediaServerName: 'Emby' });\n    }\n\n    if (settings.currentSettings.mediaServerType === MediaServerType.PLEX) {\n      return intl.formatMessage(messages.play4k, { mediaServerName: 'Plex' });\n    }\n\n    return intl.formatMessage(messages.play4k, { mediaServerName: 'Jellyfin' });\n  }\n\n  const onClickWatchlistBtn = async (): Promise<void> => {\n    setIsUpdating(true);\n\n    try {\n      const response = await axios.post('/api/v1/watchlist', {\n        tmdbId: movie?.id,\n        mediaType: MediaType.MOVIE,\n        title: movie?.title,\n      });\n\n      if (response.data) {\n        addToast(\n          <span>\n            {intl.formatMessage(messages.watchlistSuccess, {\n              title: movie?.title,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'success', autoDismiss: true }\n        );\n      }\n    } catch {\n      addToast(intl.formatMessage(messages.watchlistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n\n    setIsUpdating(false);\n    setToggleWatchlist((prevState) => !prevState);\n  };\n\n  const onClickDeleteWatchlistBtn = async (): Promise<void> => {\n    setIsUpdating(true);\n    try {\n      await axios.delete(\n        `/api/v1/watchlist/${movie?.id}?mediaType=${MediaType.MOVIE}`\n      );\n\n      addToast(\n        <span>\n          {intl.formatMessage(messages.watchlistDeleted, {\n            title: movie?.title,\n            strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n          })}\n        </span>,\n        { appearance: 'info', autoDismiss: true }\n      );\n    } catch {\n      addToast(intl.formatMessage(messages.watchlistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      setIsUpdating(false);\n      setToggleWatchlist((prevState) => !prevState);\n    }\n  };\n\n  const onClickHideItemBtn = async (): Promise<void> => {\n    setIsBlocklistUpdating(true);\n\n    try {\n      await axios.post('/api/v1/blocklist', {\n        tmdbId: movie?.id,\n        mediaType: 'movie',\n        title: movie?.title,\n        user: user?.id,\n      });\n\n      addToast(\n        <span>\n          {intl.formatMessage(globalMessages.blocklistSuccess, {\n            title: movie?.title,\n            strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n          })}\n        </span>,\n        { appearance: 'success', autoDismiss: true }\n      );\n\n      revalidate();\n    } catch (e) {\n      if (e?.response?.status === 412) {\n        addToast(\n          <span>\n            {intl.formatMessage(globalMessages.blocklistDuplicateError, {\n              title: movie?.title,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'info', autoDismiss: true }\n        );\n      } else {\n        addToast(intl.formatMessage(globalMessages.blocklistError), {\n          appearance: 'error',\n          autoDismiss: true,\n        });\n      }\n    }\n\n    setIsBlocklistUpdating(false);\n    closeBlocklistModal();\n  };\n\n  const showHideButton = hasPermission([Permission.MANAGE_BLOCKLIST], {\n    type: 'or',\n  });\n\n  return (\n    <div\n      className=\"media-page\"\n      style={{\n        height: 493,\n      }}\n    >\n      {data.backdropPath && (\n        <div className=\"media-page-bg-image\">\n          <CachedImage\n            type=\"tmdb\"\n            alt=\"\"\n            src={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data.backdropPath}`}\n            style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n            fill\n            priority\n          />\n          <div\n            className=\"absolute inset-0\"\n            style={{\n              backgroundImage:\n                'linear-gradient(180deg, rgba(17, 24, 39, 0.47) 0%, rgba(17, 24, 39, 1) 100%)',\n            }}\n          />\n        </div>\n      )}\n      <PageTitle title={data.title} />\n      <IssueModal\n        onCancel={() => setShowIssueModal(false)}\n        show={showIssueModal}\n        mediaType=\"movie\"\n        tmdbId={data.id}\n      />\n      <ManageSlideOver\n        data={data}\n        mediaType=\"movie\"\n        onClose={() => {\n          setShowManager(false);\n          router.push({\n            pathname: router.pathname,\n            query: { movieId: router.query.movieId },\n          });\n        }}\n        revalidate={() => revalidate()}\n        show={showManager}\n      />\n      <BlocklistModal\n        tmdbId={data.id}\n        type=\"movie\"\n        show={showBlocklistModal}\n        onCancel={closeBlocklistModal}\n        onComplete={onClickHideItemBtn}\n        isUpdating={isBlocklistUpdating}\n      />\n      <div className=\"media-header\">\n        <div className=\"media-poster\">\n          <CachedImage\n            type=\"tmdb\"\n            src={\n              data.posterPath\n                ? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${data.posterPath}`\n                : '/images/seerr_poster_not_found.png'\n            }\n            alt=\"\"\n            sizes=\"100vw\"\n            style={{ width: '100%', height: 'auto' }}\n            width={600}\n            height={900}\n            priority\n          />\n        </div>\n        <div className=\"media-title\">\n          <div className=\"media-status\">\n            <StatusBadge\n              status={data.mediaInfo?.status}\n              downloadItem={data.mediaInfo?.downloadStatus}\n              title={data.title}\n              inProgress={(data.mediaInfo?.downloadStatus ?? []).length > 0}\n              tmdbId={data.mediaInfo?.tmdbId}\n              mediaType=\"movie\"\n              plexUrl={plexUrl}\n              serviceUrl={data.mediaInfo?.serviceUrl}\n            />\n            {settings.currentSettings.movie4kEnabled &&\n              hasPermission(\n                [\n                  Permission.MANAGE_REQUESTS,\n                  Permission.REQUEST_4K,\n                  Permission.REQUEST_4K_MOVIE,\n                ],\n                {\n                  type: 'or',\n                }\n              ) && (\n                <StatusBadge\n                  status={data.mediaInfo?.status4k}\n                  downloadItem={data.mediaInfo?.downloadStatus4k}\n                  title={data.title}\n                  is4k\n                  inProgress={\n                    (data.mediaInfo?.downloadStatus4k ?? []).length > 0\n                  }\n                  tmdbId={data.mediaInfo?.tmdbId}\n                  mediaType=\"movie\"\n                  plexUrl={plexUrl4k}\n                  serviceUrl={data.mediaInfo?.serviceUrl4k}\n                />\n              )}\n          </div>\n          <h1 data-testid=\"media-title\">\n            {data.title}{' '}\n            {data.releaseDate && (\n              <span className=\"media-year\">\n                ({data.releaseDate.slice(0, 4)})\n              </span>\n            )}\n          </h1>\n          <span className=\"media-attributes\">\n            {movieAttributes.length > 0 &&\n              movieAttributes\n                .map((t, k) => <span key={k}>{t}</span>)\n                .reduce((prev, curr) => (\n                  <>\n                    {prev}\n                    <span>|</span>\n                    {curr}\n                  </>\n                ))}\n          </span>\n        </div>\n        <div className=\"media-actions\">\n          {showHideButton &&\n            data?.mediaInfo?.status !== MediaStatus.PROCESSING &&\n            data?.mediaInfo?.status !== MediaStatus.AVAILABLE &&\n            data?.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE &&\n            data?.mediaInfo?.status !== MediaStatus.PENDING &&\n            data?.mediaInfo?.status !== MediaStatus.BLOCKLISTED && (\n              <Tooltip\n                content={intl.formatMessage(globalMessages.addToBlocklist)}\n              >\n                <Button\n                  buttonType={'ghost'}\n                  className=\"z-40 mr-2\"\n                  buttonSize={'md'}\n                  onClick={() => setShowBlocklistModal(true)}\n                >\n                  <EyeSlashIcon />\n                </Button>\n              </Tooltip>\n            )}\n          {data?.mediaInfo?.status !== MediaStatus.BLOCKLISTED &&\n            user?.userType !== UserType.PLEX && (\n              <>\n                {toggleWatchlist ? (\n                  <Tooltip\n                    content={intl.formatMessage(messages.addtowatchlist)}\n                  >\n                    <Button\n                      buttonType={'ghost'}\n                      className=\"z-40 mr-2\"\n                      buttonSize={'md'}\n                      onClick={onClickWatchlistBtn}\n                    >\n                      {isUpdating ? (\n                        <Spinner />\n                      ) : (\n                        <StarIcon className={'text-amber-300'} />\n                      )}\n                    </Button>\n                  </Tooltip>\n                ) : (\n                  <Tooltip\n                    content={intl.formatMessage(messages.removefromwatchlist)}\n                  >\n                    <Button\n                      className=\"z-40 mr-2\"\n                      buttonSize={'md'}\n                      onClick={onClickDeleteWatchlistBtn}\n                    >\n                      {isUpdating ? <Spinner /> : <MinusCircleIcon />}\n                    </Button>\n                  </Tooltip>\n                )}\n              </>\n            )}\n          <div className=\"z-20\">\n            <PlayButton links={mediaLinks} />\n          </div>\n          <RequestButton\n            mediaType=\"movie\"\n            media={data.mediaInfo}\n            tmdbId={data.id}\n            onUpdate={() => revalidate()}\n          />\n          {(data.mediaInfo?.status === MediaStatus.AVAILABLE ||\n            (settings.currentSettings.movie4kEnabled &&\n              hasPermission(\n                [Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE],\n                {\n                  type: 'or',\n                }\n              ) &&\n              data.mediaInfo?.status4k === MediaStatus.AVAILABLE)) &&\n            hasPermission(\n              [Permission.CREATE_ISSUES, Permission.MANAGE_ISSUES],\n              {\n                type: 'or',\n              }\n            ) && (\n              <Tooltip content={intl.formatMessage(messages.reportissue)}>\n                <Button\n                  buttonType=\"warning\"\n                  onClick={() => setShowIssueModal(true)}\n                  className=\"ml-2 first:ml-0\"\n                >\n                  <ExclamationTriangleIcon />\n                </Button>\n              </Tooltip>\n            )}\n          {hasPermission(Permission.MANAGE_REQUESTS) &&\n            data.mediaInfo &&\n            (data.mediaInfo.jellyfinMediaId ||\n              data.mediaInfo.jellyfinMediaId4k ||\n              data.mediaInfo.status !== MediaStatus.UNKNOWN ||\n              data.mediaInfo.status4k !== MediaStatus.UNKNOWN) && (\n              <Tooltip content={intl.formatMessage(messages.managemovie)}>\n                <Button\n                  buttonType=\"ghost\"\n                  onClick={() => setShowManager(true)}\n                  className=\"relative ml-2 first:ml-0\"\n                >\n                  <CogIcon className=\"!mr-0\" />\n                  {hasPermission(\n                    [Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES],\n                    {\n                      type: 'or',\n                    }\n                  ) &&\n                    (\n                      data.mediaInfo?.issues.filter(\n                        (issue) => issue.status === IssueStatus.OPEN\n                      ) ?? []\n                    ).length > 0 && (\n                      <>\n                        <div className=\"absolute -right-1 -top-1 h-3 w-3 rounded-full bg-red-600\" />\n                        <div className=\"absolute -right-1 -top-1 h-3 w-3 animate-ping rounded-full bg-red-600\" />\n                      </>\n                    )}\n                </Button>\n              </Tooltip>\n            )}\n        </div>\n      </div>\n      <div className=\"media-overview\">\n        <div className=\"media-overview-left\">\n          {data.tagline && <div className=\"tagline\">{data.tagline}</div>}\n          <h2>{intl.formatMessage(messages.overview)}</h2>\n          <p>\n            {data.overview\n              ? data.overview\n              : intl.formatMessage(messages.overviewunavailable)}\n          </p>\n          {sortedCrew.length > 0 && (\n            <>\n              <ul className=\"media-crew\">\n                {sortedCrew.slice(0, 6).map((person) => (\n                  <li key={`crew-${person.job}-${person.id}`}>\n                    <span>{person.job}</span>\n                    <Link href={`/person/${person.id}`} className=\"crew-name\">\n                      {person.name}\n                    </Link>\n                  </li>\n                ))}\n              </ul>\n              <div className=\"mt-4 flex justify-end\">\n                <Link\n                  href={`/movie/${data.id}/crew`}\n                  className=\"flex items-center text-gray-400 transition duration-300 hover:text-gray-100\"\n                >\n                  <span>{intl.formatMessage(messages.viewfullcrew)}</span>\n                  <ArrowRightCircleIcon className=\"ml-1.5 inline-block h-5 w-5\" />\n                </Link>\n              </div>\n            </>\n          )}\n          {data.keywords.length > 0 && (\n            <div className=\"mt-6\">\n              {data.keywords.map((keyword) => (\n                <Link\n                  href={`/discover/movies?keywords=${keyword.id}`}\n                  key={`keyword-id-${keyword.id}`}\n                  className=\"mb-2 mr-2 inline-flex last:mr-0\"\n                >\n                  <Tag>{keyword.name}</Tag>\n                </Link>\n              ))}\n            </div>\n          )}\n        </div>\n        <div className=\"media-overview-right\">\n          {data.collection && (\n            <div className=\"mb-6\">\n              <Link href={`/collection/${data.collection.id}`}>\n                <div className=\"group relative z-0 scale-100 transform-gpu cursor-pointer overflow-hidden rounded-lg bg-gray-800 bg-cover bg-center shadow-md ring-1 ring-gray-700 transition duration-300 hover:scale-105 hover:ring-gray-500\">\n                  <div className=\"absolute inset-0 z-0\">\n                    <CachedImage\n                      type=\"tmdb\"\n                      src={`https://image.tmdb.org/t/p/w1440_and_h320_multi_faces/${data.collection.backdropPath}`}\n                      alt=\"\"\n                      style={{\n                        width: '100%',\n                        height: '100%',\n                        objectFit: 'cover',\n                      }}\n                      fill\n                    />\n                    <div\n                      className=\"absolute inset-0\"\n                      style={{\n                        backgroundImage:\n                          'linear-gradient(180deg, rgba(31, 41, 55, 0.47) 0%, rgba(31, 41, 55, 0.80) 100%)',\n                      }}\n                    />\n                  </div>\n                  <div className=\"relative z-10 flex h-full items-center justify-between p-4 text-gray-200 transition duration-300 group-hover:text-white\">\n                    <div>{data.collection.name}</div>\n                    <Button buttonSize=\"sm\">\n                      {intl.formatMessage(globalMessages.view)}\n                    </Button>\n                  </div>\n                </div>\n              </Link>\n            </div>\n          )}\n          <div className=\"media-facts\">\n            {(!!data.voteCount ||\n              (ratingData?.rt?.criticsRating &&\n                typeof ratingData?.rt?.criticsScore === 'number') ||\n              (ratingData?.rt?.audienceRating &&\n                !!ratingData?.rt?.audienceScore) ||\n              ratingData?.imdb?.criticsScore) && (\n              <div className=\"media-ratings\">\n                {ratingData?.rt?.criticsRating &&\n                  typeof ratingData?.rt?.criticsScore === 'number' && (\n                    <Tooltip\n                      content={intl.formatMessage(messages.rtcriticsscore)}\n                    >\n                      <a\n                        href={ratingData.rt.url}\n                        className=\"media-rating\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {ratingData.rt.criticsRating === 'Rotten' ? (\n                          <RTRotten className=\"w-6\" />\n                        ) : (\n                          <RTFresh className=\"w-6\" />\n                        )}\n                        <span>{ratingData.rt.criticsScore}%</span>\n                      </a>\n                    </Tooltip>\n                  )}\n                {ratingData?.rt?.audienceRating &&\n                  !!ratingData?.rt?.audienceScore && (\n                    <Tooltip\n                      content={intl.formatMessage(messages.rtaudiencescore)}\n                    >\n                      <a\n                        href={ratingData.rt.url}\n                        className=\"media-rating\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {ratingData.rt.audienceRating === 'Spilled' ? (\n                          <RTAudRotten className=\"w-6\" />\n                        ) : (\n                          <RTAudFresh className=\"w-6\" />\n                        )}\n                        <span>{ratingData.rt.audienceScore}%</span>\n                      </a>\n                    </Tooltip>\n                  )}\n                {ratingData?.imdb?.criticsScore && (\n                  <Tooltip\n                    content={intl.formatMessage(messages.imdbuserscore, {\n                      formattedCount: intl.formatNumber(\n                        ratingData.imdb.criticsScoreCount,\n                        {\n                          notation: 'compact',\n                          compactDisplay: 'short',\n                          maximumFractionDigits: 1,\n                        }\n                      ),\n                    })}\n                  >\n                    <a\n                      href={ratingData.imdb.url}\n                      className=\"media-rating\"\n                      target=\"_blank\"\n                      rel=\"noreferrer\"\n                    >\n                      <ImdbLogo className=\"mr-1 w-6\" />\n                      <span>{ratingData.imdb.criticsScore}</span>\n                    </a>\n                  </Tooltip>\n                )}\n                {!!data.voteCount && (\n                  <Tooltip content={intl.formatMessage(messages.tmdbuserscore)}>\n                    <a\n                      href={`https://www.themoviedb.org/movie/${data.id}?language=${locale}`}\n                      className=\"media-rating\"\n                      target=\"_blank\"\n                      rel=\"noreferrer\"\n                    >\n                      <TmdbLogo className=\"mr-1 w-6\" />\n                      <span>{Math.round(data.voteAverage * 10)}%</span>\n                    </a>\n                  </Tooltip>\n                )}\n              </div>\n            )}\n            {data.originalTitle &&\n              data.originalLanguage !== locale.slice(0, 2) && (\n                <div className=\"media-fact\">\n                  <span>{intl.formatMessage(messages.originaltitle)}</span>\n                  <span className=\"media-fact-value\">{data.originalTitle}</span>\n                </div>\n              )}\n            <div className=\"media-fact\">\n              <span>{intl.formatMessage(globalMessages.status)}</span>\n              <span className=\"media-fact-value\">{data.status}</span>\n            </div>\n            {filteredReleases && filteredReleases.length > 0 ? (\n              <div className=\"media-fact\">\n                <span>\n                  {intl.formatMessage(messages.releasedate, {\n                    releaseCount: filteredReleases.length,\n                  })}\n                </span>\n                <span className=\"media-fact-value\">\n                  {filteredReleases.map((r, i) => (\n                    <span\n                      className=\"flex items-center justify-end\"\n                      key={`release-date-${i}`}\n                    >\n                      {r.type === 3 ? (\n                        // Theatrical\n                        <Tooltip\n                          content={intl.formatMessage(\n                            messages.theatricalrelease\n                          )}\n                        >\n                          <TicketIcon className=\"h-4 w-4\" />\n                        </Tooltip>\n                      ) : r.type === 4 ? (\n                        // Digital\n                        <Tooltip\n                          content={intl.formatMessage(messages.digitalrelease)}\n                        >\n                          <CloudIcon className=\"h-4 w-4\" />\n                        </Tooltip>\n                      ) : (\n                        // Physical\n                        <Tooltip\n                          content={intl.formatMessage(messages.physicalrelease)}\n                        >\n                          <svg\n                            className=\"h-4 w-4\"\n                            viewBox=\"0 0 24 24\"\n                            xmlns=\"http://www.w3.org/2000/svg\"\n                          >\n                            <path\n                              d=\"m12 2c-5.5242 0-10 4.4758-10 10 0 5.5242 4.4758 10 10 10 5.5242 0 10-4.4758 10-10 0-5.5242-4.4758-10-10-10zm0 18.065c-4.4476 0-8.0645-3.6169-8.0645-8.0645 0-4.4476 3.6169-8.0645 8.0645-8.0645 4.4476 0 8.0645 3.6169 8.0645 8.0645 0 4.4476-3.6169 8.0645-8.0645 8.0645zm0-14.516c-3.5565 0-6.4516 2.8952-6.4516 6.4516h1.2903c0-2.8468 2.3145-5.1613 5.1613-5.1613zm0 2.9032c-1.9597 0-3.5484 1.5887-3.5484 3.5484s1.5887 3.5484 3.5484 3.5484 3.5484-1.5887 3.5484-3.5484-1.5887-3.5484-3.5484-3.5484zm0 4.8387c-0.71371 0-1.2903-0.57661-1.2903-1.2903s0.57661-1.2903 1.2903-1.2903 1.2903 0.57661 1.2903 1.2903-0.57661 1.2903-1.2903 1.2903z\"\n                              fill=\"currentColor\"\n                            />\n                          </svg>\n                        </Tooltip>\n                      )}\n                      <span className=\"ml-1.5\">\n                        {intl.formatDate(r.release_date, {\n                          year: 'numeric',\n                          month: 'long',\n                          day: 'numeric',\n                          timeZone: 'UTC',\n                        })}\n                      </span>\n                    </span>\n                  ))}\n                </span>\n              </div>\n            ) : (\n              data.releaseDate && (\n                <div className=\"media-fact\">\n                  <span>\n                    {intl.formatMessage(messages.releasedate, {\n                      releaseCount: 1,\n                    })}\n                  </span>\n                  <span className=\"media-fact-value\">\n                    {intl.formatDate(data.releaseDate, {\n                      year: 'numeric',\n                      month: 'long',\n                      day: 'numeric',\n                      timeZone: 'UTC',\n                    })}\n                  </span>\n                </div>\n              )\n            )}\n            {data.revenue > 0 && (\n              <div className=\"media-fact\">\n                <span>{intl.formatMessage(messages.revenue)}</span>\n                <span className=\"media-fact-value\">\n                  {intl.formatNumber(data.revenue, {\n                    currency: 'USD',\n                    style: 'currency',\n                  })}\n                </span>\n              </div>\n            )}\n            {data.budget > 0 && (\n              <div className=\"media-fact\">\n                <span>{intl.formatMessage(messages.budget)}</span>\n                <span className=\"media-fact-value\">\n                  {intl.formatNumber(data.budget, {\n                    currency: 'USD',\n                    style: 'currency',\n                  })}\n                </span>\n              </div>\n            )}\n            {data.originalLanguage && (\n              <div className=\"media-fact\">\n                <span>{intl.formatMessage(messages.originallanguage)}</span>\n                <span className=\"media-fact-value\">\n                  <Link\n                    href={`/discover/movies/language/${data.originalLanguage}`}\n                  >\n                    {intl.formatDisplayName(data.originalLanguage, {\n                      type: 'language',\n                      fallback: 'none',\n                    }) ??\n                      data.spokenLanguages.find(\n                        (lng) => lng.iso_639_1 === data.originalLanguage\n                      )?.name}\n                  </Link>\n                </span>\n              </div>\n            )}\n            {data.productionCountries.length > 0 && (\n              <div className=\"media-fact\">\n                <span>\n                  {intl.formatMessage(messages.productioncountries, {\n                    countryCount: data.productionCountries.length,\n                  })}\n                </span>\n                <span className=\"media-fact-value\">\n                  {data.productionCountries.map((c) => {\n                    return (\n                      <span\n                        className=\"flex items-center justify-end\"\n                        key={`prodcountry-${c.iso_3166_1}`}\n                      >\n                        {countries.includes(c.iso_3166_1) && (\n                          <span\n                            className={`mr-1.5 text-xs leading-5 flag:${c.iso_3166_1}`}\n                          />\n                        )}\n                        <span>\n                          {intl.formatDisplayName(c.iso_3166_1, {\n                            type: 'region',\n                            fallback: 'none',\n                          }) ?? c.name}\n                        </span>\n                      </span>\n                    );\n                  })}\n                </span>\n              </div>\n            )}\n            {data.productionCompanies.length > 0 && (\n              <div className=\"media-fact\">\n                <span>\n                  {intl.formatMessage(messages.studio, {\n                    studioCount: data.productionCompanies.length,\n                  })}\n                </span>\n                <span className=\"media-fact-value\">\n                  {data.productionCompanies\n                    .slice(\n                      0,\n                      showAllStudios || showMoreStudios\n                        ? data.productionCompanies.length\n                        : minStudios\n                    )\n                    .map((s) => {\n                      return (\n                        <Link\n                          href={`/discover/movies/studio/${s.id}`}\n                          key={`studio-${s.id}`}\n                          className=\"block\"\n                        >\n                          {s.name}\n                        </Link>\n                      );\n                    })}\n                  {!showAllStudios && (\n                    <button\n                      type=\"button\"\n                      onClick={() => {\n                        setShowMoreStudios(!showMoreStudios);\n                      }}\n                    >\n                      <span className=\"flex items-center\">\n                        {intl.formatMessage(\n                          !showMoreStudios\n                            ? messages.showmore\n                            : messages.showless\n                        )}\n                        {!showMoreStudios ? (\n                          <ChevronDoubleDownIcon className=\"ml-1 h-4 w-4\" />\n                        ) : (\n                          <ChevronDoubleUpIcon className=\"ml-1 h-4 w-4\" />\n                        )}\n                      </span>\n                    </button>\n                  )}\n                </span>\n              </div>\n            )}\n            {!!streamingProviders.length && (\n              <div className=\"media-fact flex-col gap-1\">\n                <span>{intl.formatMessage(messages.streamingproviders)}</span>\n                <span className=\"media-fact-value flex flex-row flex-wrap gap-5\">\n                  {streamingProviders.map((p) => {\n                    return (\n                      <Tooltip content={p.name}>\n                        <span\n                          className=\"opacity-50 transition duration-300 hover:opacity-100\"\n                          key={`provider-${p.id}`}\n                        >\n                          <CachedImage\n                            type=\"tmdb\"\n                            src={'https://image.tmdb.org/t/p/w45/' + p.logoPath}\n                            alt={p.name}\n                            width={32}\n                            height={32}\n                            className=\"rounded-md\"\n                          />\n                        </span>\n                      </Tooltip>\n                    );\n                  })}\n                </span>\n              </div>\n            )}\n            <div className=\"media-fact\">\n              <ExternalLinkBlock\n                mediaType=\"movie\"\n                tmdbId={data.id}\n                tvdbId={data.externalIds.tvdbId}\n                imdbId={data.externalIds.imdbId}\n                rtUrl={ratingData?.rt?.url}\n                mediaUrl={\n                  data.mediaInfo?.mediaUrl ?? data.mediaInfo?.mediaUrl4k\n                }\n              />\n            </div>\n          </div>\n        </div>\n      </div>\n      {data.credits.cast.length > 0 && (\n        <>\n          <div className=\"slider-header\">\n            <Link\n              href=\"/movie/[movieId]/cast\"\n              as={`/movie/${data.id}/cast`}\n              className=\"slider-title\"\n            >\n              <span>{intl.formatMessage(messages.cast)}</span>\n              <ArrowRightCircleIcon />\n            </Link>\n          </div>\n          <Slider\n            sliderKey=\"cast\"\n            isLoading={false}\n            isEmpty={false}\n            items={data.credits.cast.slice(0, 20).map((person) => (\n              <PersonCard\n                key={`cast-item-${person.id}`}\n                personId={person.id}\n                name={person.name}\n                subName={person.character}\n                profilePath={person.profilePath}\n              />\n            ))}\n          />\n        </>\n      )}\n      <MediaSlider\n        sliderKey=\"recommendations\"\n        title={intl.formatMessage(messages.recommendations)}\n        url={`/api/v1/movie/${router.query.movieId}/recommendations`}\n        linkUrl={`/movie/${data.id}/recommendations`}\n        hideWhenEmpty\n      />\n      <MediaSlider\n        sliderKey=\"similar\"\n        title={intl.formatMessage(messages.similar)}\n        url={`/api/v1/movie/${router.query.movieId}/similar`}\n        linkUrl={`/movie/${data.id}/similar`}\n        hideWhenEmpty\n      />\n      <div className=\"extra-bottom-space relative\" />\n    </div>\n  );\n};\n\nexport default MovieDetails;\n"
  },
  {
    "path": "src/components/NotificationTypeSelector/NotificationType/index.tsx",
    "content": "import type { NotificationItem } from '@app/components/NotificationTypeSelector';\nimport { hasNotificationType } from '@app/components/NotificationTypeSelector';\n\ninterface NotificationTypeProps {\n  option: NotificationItem;\n  currentTypes: number;\n  parent?: NotificationItem;\n  onUpdate: (newTypes: number) => void;\n}\n\nconst NotificationType = ({\n  option,\n  currentTypes,\n  onUpdate,\n  parent,\n}: NotificationTypeProps) => {\n  return (\n    <>\n      <div\n        className={`relative mt-4 flex items-start first:mt-0 ${\n          !!parent?.value && hasNotificationType(parent.value, currentTypes)\n            ? 'opacity-50'\n            : ''\n        }`}\n      >\n        <div className=\"flex h-6 items-center\">\n          <input\n            id={option.id}\n            name=\"permissions\"\n            type=\"checkbox\"\n            disabled={\n              !!parent?.value && hasNotificationType(parent.value, currentTypes)\n            }\n            onClick={() => {\n              onUpdate(\n                hasNotificationType(option.value, currentTypes)\n                  ? currentTypes - option.value\n                  : currentTypes + option.value\n              );\n            }}\n            checked={\n              hasNotificationType(option.value, currentTypes) ||\n              (!!parent?.value &&\n                hasNotificationType(parent.value, currentTypes))\n            }\n          />\n        </div>\n        <div className=\"ml-3 text-sm leading-6\">\n          <label htmlFor={option.id} className=\"block\" aria-label={option.name}>\n            <div className=\"flex flex-col\">\n              <span className=\"font-medium text-white\">{option.name}</span>\n              <span className=\"font-normal text-gray-400\">\n                {option.description}\n              </span>\n            </div>\n          </label>\n        </div>\n      </div>\n      {(option.children ?? []).map((child) => (\n        <div key={`notification-type-child-${child.id}`} className=\"mt-4 pl-6\">\n          <NotificationType\n            option={child}\n            currentTypes={currentTypes}\n            onUpdate={(newTypes) => onUpdate(newTypes)}\n            parent={option}\n          />\n        </div>\n      ))}\n    </>\n  );\n};\n\nexport default NotificationType;\n"
  },
  {
    "path": "src/components/NotificationTypeSelector/index.tsx",
    "content": "import NotificationType from '@app/components/NotificationTypeSelector/NotificationType';\nimport useSettings from '@app/hooks/useSettings';\nimport type { User } from '@app/hooks/useUser';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { sortBy } from 'lodash';\nimport { useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.NotificationTypeSelector', {\n  notificationTypes: 'Notification Types',\n  mediarequested: 'Request Pending Approval',\n  mediarequestedDescription:\n    'Send notifications when users submit new media requests which require approval.',\n  usermediarequestedDescription:\n    'Get notified when other users submit new media requests which require approval.',\n  mediaapproved: 'Request Approved',\n  mediaapprovedDescription:\n    'Send notifications when media requests are manually approved.',\n  usermediaapprovedDescription:\n    'Get notified when your media requests are approved.',\n  mediaAutoApproved: 'Request Automatically Approved',\n  mediaAutoApprovedDescription:\n    'Send notifications when users submit new media requests which are automatically approved.',\n  usermediaAutoApprovedDescription:\n    'Get notified when other users submit new media requests which are automatically approved.',\n  mediaavailable: 'Request Available',\n  mediaavailableDescription:\n    'Send notifications when media requests become available.',\n  usermediaavailableDescription:\n    'Get notified when your media requests become available.',\n  mediafailed: 'Request Processing Failed',\n  mediafailedDescription:\n    'Send notifications when media requests fail to be added to Radarr or Sonarr.',\n  usermediafailedDescription:\n    'Get notified when media requests fail to be added to Radarr or Sonarr.',\n  mediadeclined: 'Request Declined',\n  mediadeclinedDescription:\n    'Send notifications when media requests are declined.',\n  usermediadeclinedDescription:\n    'Get notified when your media requests are declined.',\n  issuecreated: 'Issue Reported',\n  issuecreatedDescription: 'Send notifications when issues are reported.',\n  userissuecreatedDescription: 'Get notified when other users report issues.',\n  issuecomment: 'Issue Comment',\n  issuecommentDescription:\n    'Send notifications when issues receive new comments.',\n  userissuecommentDescription:\n    'Get notified when issues you reported receive new comments.',\n  adminissuecommentDescription:\n    'Get notified when other users comment on issues.',\n  issueresolved: 'Issue Resolved',\n  issueresolvedDescription: 'Send notifications when issues are resolved.',\n  userissueresolvedDescription:\n    'Get notified when issues you reported are resolved.',\n  adminissueresolvedDescription:\n    'Get notified when issues are resolved by other users.',\n  issuereopened: 'Issue Reopened',\n  issuereopenedDescription: 'Send notifications when issues are reopened.',\n  userissuereopenedDescription:\n    'Get notified when issues you reported are reopened.',\n  adminissuereopenedDescription:\n    'Get notified when issues are reopened by other users.',\n  mediaautorequested: 'Request Automatically Submitted',\n  mediaautorequestedDescription:\n    'Get notified when new media requests are automatically submitted for items on Your Watchlist.',\n});\n\nexport const hasNotificationType = (\n  types: Notification | Notification[],\n  value: number\n): boolean => {\n  let total: number;\n\n  // If we are not checking any notifications, bail out and return true\n  if (types === 0) {\n    return true;\n  }\n\n  if (Array.isArray(types)) {\n    // Combine all notification values into one\n    total = types.reduce((a, v) => a + v, 0);\n  } else {\n    total = types;\n  }\n\n  // Test notifications don't need to be enabled\n  if (!(value & Notification.TEST_NOTIFICATION)) {\n    value += Notification.TEST_NOTIFICATION;\n  }\n\n  return !!(value & total);\n};\n\nexport enum Notification {\n  NONE = 0,\n  MEDIA_PENDING = 2,\n  MEDIA_APPROVED = 4,\n  MEDIA_AVAILABLE = 8,\n  MEDIA_FAILED = 16,\n  TEST_NOTIFICATION = 32,\n  MEDIA_DECLINED = 64,\n  MEDIA_AUTO_APPROVED = 128,\n  ISSUE_CREATED = 256,\n  ISSUE_COMMENT = 512,\n  ISSUE_RESOLVED = 1024,\n  ISSUE_REOPENED = 2048,\n  MEDIA_AUTO_REQUESTED = 4096,\n}\n\nexport const ALL_NOTIFICATIONS = Object.values(Notification)\n  .filter((v) => !isNaN(Number(v)))\n  .reduce((a, v) => a + Number(v), 0);\n\nexport interface NotificationItem {\n  id: string;\n  name: string;\n  description: string;\n  value: Notification;\n  hasNotifyUser: boolean;\n  children?: NotificationItem[];\n  hidden?: boolean;\n}\n\ninterface NotificationTypeSelectorProps {\n  user?: User;\n  enabledTypes?: number;\n  currentTypes: number;\n  onUpdate: (newTypes: number) => void;\n  error?: string;\n}\n\nconst NotificationTypeSelector = ({\n  user,\n  enabledTypes = ALL_NOTIFICATIONS,\n  currentTypes,\n  onUpdate,\n  error,\n}: NotificationTypeSelectorProps) => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const { hasPermission } = useUser({ id: user?.id });\n  const [allowedTypes, setAllowedTypes] = useState(enabledTypes);\n\n  const availableTypes = useMemo(() => {\n    const allRequestsAutoApproved =\n      user &&\n      // Has Manage Requests perm, which grants all Auto-Approve perms\n      (hasPermission(Permission.MANAGE_REQUESTS) ||\n        // Cannot submit requests of any type\n        !hasPermission(\n          [\n            Permission.REQUEST,\n            Permission.REQUEST_MOVIE,\n            Permission.REQUEST_TV,\n            Permission.REQUEST_4K,\n            Permission.REQUEST_4K_MOVIE,\n            Permission.REQUEST_4K_TV,\n          ],\n          { type: 'or' }\n        ) ||\n        // Cannot submit non-4K movie requests OR has Auto-Approve perms for non-4K movies\n        ((!hasPermission([Permission.REQUEST, Permission.REQUEST_MOVIE], {\n          type: 'or',\n        }) ||\n          hasPermission(\n            [Permission.AUTO_APPROVE, Permission.AUTO_APPROVE_MOVIE],\n            { type: 'or' }\n          )) &&\n          // Cannot submit non-4K series requests OR has Auto-Approve perms for non-4K series\n          (!hasPermission([Permission.REQUEST, Permission.REQUEST_TV], {\n            type: 'or',\n          }) ||\n            hasPermission(\n              [Permission.AUTO_APPROVE, Permission.AUTO_APPROVE_TV],\n              { type: 'or' }\n            )) &&\n          // Cannot submit 4K movie requests OR has Auto-Approve perms for 4K movies\n          (!settings.currentSettings.movie4kEnabled ||\n            !hasPermission(\n              [Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE],\n              { type: 'or' }\n            ) ||\n            hasPermission(\n              [Permission.AUTO_APPROVE_4K, Permission.AUTO_APPROVE_4K_MOVIE],\n              { type: 'or' }\n            )) &&\n          // Cannot submit 4K series requests OR has Auto-Approve perms for 4K series\n          (!settings.currentSettings.series4kEnabled ||\n            !hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_TV], {\n              type: 'or',\n            }) ||\n            hasPermission(\n              [Permission.AUTO_APPROVE_4K, Permission.AUTO_APPROVE_4K_TV],\n              { type: 'or' }\n            ))));\n\n    const types: NotificationItem[] = [\n      {\n        id: 'media-auto-requested',\n        name: intl.formatMessage(messages.mediaautorequested),\n        description: intl.formatMessage(messages.mediaautorequestedDescription),\n        value: Notification.MEDIA_AUTO_REQUESTED,\n        hidden:\n          !user ||\n          (!user.settings?.watchlistSyncMovies &&\n            !user.settings?.watchlistSyncTv) ||\n          !hasPermission(\n            [\n              Permission.AUTO_REQUEST,\n              Permission.AUTO_REQUEST_MOVIE,\n              Permission.AUTO_REQUEST_TV,\n            ],\n            { type: 'or' }\n          ),\n        hasNotifyUser: true,\n      },\n      {\n        id: 'media-requested',\n        name: intl.formatMessage(messages.mediarequested),\n        description: intl.formatMessage(\n          user\n            ? messages.usermediarequestedDescription\n            : messages.mediarequestedDescription\n        ),\n        value: Notification.MEDIA_PENDING,\n        hasNotifyUser: false,\n        hidden: user && !hasPermission(Permission.MANAGE_REQUESTS),\n      },\n      {\n        id: 'media-auto-approved',\n        name: intl.formatMessage(messages.mediaAutoApproved),\n        description: intl.formatMessage(\n          user\n            ? messages.usermediaAutoApprovedDescription\n            : messages.mediaAutoApprovedDescription\n        ),\n        value: Notification.MEDIA_AUTO_APPROVED,\n        hasNotifyUser: false,\n        hidden: user && !hasPermission(Permission.MANAGE_REQUESTS),\n      },\n      {\n        id: 'media-approved',\n        name: intl.formatMessage(messages.mediaapproved),\n        description: intl.formatMessage(\n          user\n            ? messages.usermediaapprovedDescription\n            : messages.mediaapprovedDescription\n        ),\n        value: Notification.MEDIA_APPROVED,\n        hasNotifyUser: true,\n        hidden: allRequestsAutoApproved,\n      },\n      {\n        id: 'media-declined',\n        name: intl.formatMessage(messages.mediadeclined),\n        description: intl.formatMessage(\n          user\n            ? messages.usermediadeclinedDescription\n            : messages.mediadeclinedDescription\n        ),\n        value: Notification.MEDIA_DECLINED,\n        hasNotifyUser: true,\n        hidden: allRequestsAutoApproved,\n      },\n      {\n        id: 'media-available',\n        name: intl.formatMessage(messages.mediaavailable),\n        description: intl.formatMessage(\n          user\n            ? messages.usermediaavailableDescription\n            : messages.mediaavailableDescription\n        ),\n        value: Notification.MEDIA_AVAILABLE,\n        hasNotifyUser: true,\n      },\n      {\n        id: 'media-failed',\n        name: intl.formatMessage(messages.mediafailed),\n        description: intl.formatMessage(\n          user\n            ? messages.usermediafailedDescription\n            : messages.mediafailedDescription\n        ),\n        value: Notification.MEDIA_FAILED,\n        hidden: user && !hasPermission(Permission.MANAGE_REQUESTS),\n        hasNotifyUser: false,\n      },\n      {\n        id: 'issue-created',\n        name: intl.formatMessage(messages.issuecreated),\n        description: intl.formatMessage(\n          user\n            ? messages.userissuecreatedDescription\n            : messages.issuecreatedDescription\n        ),\n        value: Notification.ISSUE_CREATED,\n        hidden: user && !hasPermission(Permission.MANAGE_ISSUES),\n        hasNotifyUser: false,\n      },\n      {\n        id: 'issue-comment',\n        name: intl.formatMessage(messages.issuecomment),\n        description: intl.formatMessage(\n          user\n            ? hasPermission(Permission.MANAGE_ISSUES)\n              ? messages.adminissuecommentDescription\n              : messages.userissuecommentDescription\n            : messages.issuecommentDescription\n        ),\n        value: Notification.ISSUE_COMMENT,\n        hidden:\n          user &&\n          !hasPermission([Permission.MANAGE_ISSUES, Permission.CREATE_ISSUES], {\n            type: 'or',\n          }),\n        hasNotifyUser:\n          !user || hasPermission(Permission.MANAGE_ISSUES) ? false : true,\n      },\n      {\n        id: 'issue-resolved',\n        name: intl.formatMessage(messages.issueresolved),\n        description: intl.formatMessage(\n          user\n            ? hasPermission(Permission.MANAGE_ISSUES)\n              ? messages.adminissueresolvedDescription\n              : messages.userissueresolvedDescription\n            : messages.issueresolvedDescription\n        ),\n        value: Notification.ISSUE_RESOLVED,\n        hidden:\n          user &&\n          !hasPermission([Permission.MANAGE_ISSUES, Permission.CREATE_ISSUES], {\n            type: 'or',\n          }),\n        hasNotifyUser:\n          !user || hasPermission(Permission.MANAGE_ISSUES) ? false : true,\n      },\n      {\n        id: 'issue-reopened',\n        name: intl.formatMessage(messages.issuereopened),\n        description: intl.formatMessage(\n          user\n            ? hasPermission(Permission.MANAGE_ISSUES)\n              ? messages.adminissuereopenedDescription\n              : messages.userissuereopenedDescription\n            : messages.issuereopenedDescription\n        ),\n        value: Notification.ISSUE_REOPENED,\n        hidden:\n          user &&\n          !hasPermission([Permission.MANAGE_ISSUES, Permission.CREATE_ISSUES], {\n            type: 'or',\n          }),\n        hasNotifyUser:\n          !user || hasPermission(Permission.MANAGE_ISSUES) ? false : true,\n      },\n    ];\n\n    const filteredTypes = types.filter(\n      (type) => !type.hidden && hasNotificationType(type.value, enabledTypes)\n    );\n\n    const newAllowedTypes = filteredTypes.reduce((a, v) => a + v.value, 0);\n    if (newAllowedTypes !== allowedTypes) {\n      setAllowedTypes(newAllowedTypes);\n    }\n\n    return user\n      ? sortBy(filteredTypes, 'hasNotifyUser', 'DESC')\n      : filteredTypes;\n  }, [user, hasPermission, settings, intl, allowedTypes, enabledTypes]);\n\n  if (!availableTypes.length) {\n    return null;\n  }\n\n  return (\n    <div role=\"group\" aria-labelledby=\"group-label\" className=\"form-group\">\n      <div className=\"form-row\">\n        <span id=\"group-label\" className=\"group-label\">\n          {intl.formatMessage(messages.notificationTypes)}\n          {!user && <span className=\"label-required\">*</span>}\n        </span>\n        <div className=\"form-input-area\">\n          <div className=\"max-w-lg\">\n            {availableTypes.map((type) => (\n              <NotificationType\n                key={`notification-type-${type.id}`}\n                option={type}\n                currentTypes={currentTypes}\n                onUpdate={onUpdate}\n              />\n            ))}\n          </div>\n          {error && <div className=\"error\">{error}</div>}\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default NotificationTypeSelector;\n"
  },
  {
    "path": "src/components/PWAHeader/index.tsx",
    "content": "interface PWAHeaderProps {\n  applicationTitle?: string;\n}\n\nconst PWAHeader = ({ applicationTitle = 'Seerr' }: PWAHeaderProps) => {\n  return (\n    <>\n      <link\n        rel=\"apple-touch-icon\"\n        sizes=\"180x180\"\n        href=\"/apple-touch-icon.png\"\n      />\n      <link\n        rel=\"icon\"\n        type=\"image/png\"\n        sizes=\"32x32\"\n        href=\"/favicon-32x32.png\"\n      />\n      <link\n        rel=\"icon\"\n        type=\"image/png\"\n        sizes=\"16x16\"\n        href=\"/favicon-16x16.png\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2048-2732.jpg\"\n        media=\"(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2732-2048.jpg\"\n        media=\"(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1668-2388.jpg\"\n        media=\"(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2388-1668.jpg\"\n        media=\"(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1536-2048.jpg\"\n        media=\"(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2048-1536.jpg\"\n        media=\"(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1668-2224.jpg\"\n        media=\"(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2224-1668.jpg\"\n        media=\"(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1620-2160.jpg\"\n        media=\"(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2160-1620.jpg\"\n        media=\"(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1284-2778.jpg\"\n        media=\"(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2778-1284.jpg\"\n        media=\"(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1170-2532.jpg\"\n        media=\"(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2532-1170.jpg\"\n        media=\"(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1125-2436.jpg\"\n        media=\"(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2436-1125.jpg\"\n        media=\"(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1242-2688.jpg\"\n        media=\"(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2688-1242.jpg\"\n        media=\"(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-828-1792.jpg\"\n        media=\"(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1792-828.jpg\"\n        media=\"(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1242-2208.jpg\"\n        media=\"(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-2208-1242.jpg\"\n        media=\"(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-750-1334.jpg\"\n        media=\"(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1334-750.jpg\"\n        media=\"(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-640-1136.jpg\"\n        media=\"(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)\"\n      />\n      <link\n        rel=\"apple-touch-startup-image\"\n        href=\"/apple-splash-1136-640.jpg\"\n        media=\"(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)\"\n      />\n      <meta\n        name=\"apple-mobile-web-app-status-bar-style\"\n        content=\"black-translucent\"\n      />\n      <link\n        rel=\"manifest\"\n        href=\"/site.webmanifest\"\n        crossOrigin=\"use-credentials\"\n      />\n      <meta name=\"apple-mobile-web-app-title\" content={applicationTitle} />\n      <meta\n        name=\"description\"\n        content=\"Request and Media Discovery Application\"\n      />\n      <meta name=\"format-detection\" content=\"telephone=no\" />\n      <meta name=\"mobile-web-app-capable\" content=\"yes\" />\n      <meta name=\"theme-color\" content=\"#1f2937\" />\n      <meta name=\"application-name\" content={applicationTitle} />\n    </>\n  );\n};\n\nexport default PWAHeader;\n"
  },
  {
    "path": "src/components/PermissionEdit/index.tsx",
    "content": "import type { PermissionItem } from '@app/components/PermissionOption';\nimport PermissionOption from '@app/components/PermissionOption';\nimport useSettings from '@app/hooks/useSettings';\nimport type { User } from '@app/hooks/useUser';\nimport { Permission } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { MediaServerType } from '@server/constants/server';\nimport { useIntl } from 'react-intl';\n\nexport const messages = defineMessages('components.PermissionEdit', {\n  admin: 'Admin',\n  adminDescription:\n    'Full administrator access. Bypasses all other permission checks.',\n  users: 'Manage Users',\n  usersDescription:\n    'Grant permission to manage users. Users with this permission cannot modify users with or grant the Admin privilege.',\n  managerequests: 'Manage Requests',\n  managerequestsDescription:\n    'Grant permission to manage media requests. All requests made by a user with this permission will be automatically approved.',\n  request: 'Request',\n  requestDescription: 'Grant permission to submit requests for non-4K media.',\n  requestMovies: 'Request Movies',\n  requestMoviesDescription:\n    'Grant permission to submit requests for non-4K movies.',\n  requestTv: 'Request Series',\n  requestTvDescription:\n    'Grant permission to submit requests for non-4K series.',\n  autoapprove: 'Auto-Approve',\n  autoapproveDescription:\n    'Grant automatic approval for all non-4K media requests.',\n  autoapproveMovies: 'Auto-Approve Movies',\n  autoapproveMoviesDescription:\n    'Grant automatic approval for non-4K movie requests.',\n  autoapproveSeries: 'Auto-Approve Series',\n  autoapproveSeriesDescription:\n    'Grant automatic approval for non-4K series requests.',\n  autoapprove4k: 'Auto-Approve 4K',\n  autoapprove4kDescription:\n    'Grant automatic approval for all 4K media requests.',\n  autoapprove4kMovies: 'Auto-Approve 4K Movies',\n  autoapprove4kMoviesDescription:\n    'Grant automatic approval for 4K movie requests.',\n  autoapprove4kSeries: 'Auto-Approve 4K Series',\n  autoapprove4kSeriesDescription:\n    'Grant automatic approval for 4K series requests.',\n  request4k: 'Request 4K',\n  request4kDescription: 'Grant permission to submit requests for 4K media.',\n  request4kMovies: 'Request 4K Movies',\n  request4kMoviesDescription:\n    'Grant permission to submit requests for 4K movies.',\n  request4kTv: 'Request 4K Series',\n  request4kTvDescription: 'Grant permission to submit requests for 4K series.',\n  advancedrequest: 'Advanced Requests',\n  advancedrequestDescription:\n    'Grant permission to modify advanced media request options.',\n  autorequest: 'Auto-Request',\n  autorequestDescription:\n    'Grant permission to automatically submit requests for non-4K media via Plex Watchlist.',\n  autorequestMovies: 'Auto-Request Movies',\n  autorequestMoviesDescription:\n    'Grant permission to automatically submit requests for non-4K movies via Plex Watchlist.',\n  autorequestSeries: 'Auto-Request Series',\n  autorequestSeriesDescription:\n    'Grant permission to automatically submit requests for non-4K series via Plex Watchlist.',\n  viewrequests: 'View Requests',\n  viewrequestsDescription:\n    'Grant permission to view media requests submitted by other users.',\n  manageissues: 'Manage Issues',\n  manageissuesDescription: 'Grant permission to manage media issues.',\n  createissues: 'Report Issues',\n  createissuesDescription: 'Grant permission to report media issues.',\n  viewissues: 'View Issues',\n  viewissuesDescription:\n    'Grant permission to view media issues reported by other users.',\n  viewrecent: 'View Recently Added',\n  viewrecentDescription:\n    'Grant permission to view the list of recently added media.',\n  viewwatchlists: 'View {mediaServerName} Watchlists',\n  viewwatchlistsDescription:\n    \"Grant permission to view other users' {mediaServerName} Watchlists.\",\n  manageblocklist: 'Manage Blocklist',\n  manageblocklistDescription: 'Grant permission to manage blocklisted media.',\n  blocklistedItems: 'Blocklist media.',\n  blocklistedItemsDescription: 'Grant permission to blocklist media.',\n  viewblocklistedItems: 'View blocklisted media.',\n  viewblocklistedItemsDescription:\n    'Grant permission to view blocklisted media.',\n});\n\ninterface PermissionEditProps {\n  actingUser?: User;\n  currentUser?: User;\n  currentPermission: number;\n  onUpdate: (newPermissions: number) => void;\n}\n\nexport const PermissionEdit = ({\n  actingUser,\n  currentUser,\n  currentPermission,\n  onUpdate,\n}: PermissionEditProps) => {\n  const intl = useIntl();\n  const settings = useSettings();\n\n  const permissionList: PermissionItem[] = [\n    {\n      id: 'admin',\n      name: intl.formatMessage(messages.admin),\n      description: intl.formatMessage(messages.adminDescription),\n      permission: Permission.ADMIN,\n    },\n    {\n      id: 'users',\n      name: intl.formatMessage(messages.users),\n      description: intl.formatMessage(messages.usersDescription),\n      permission: Permission.MANAGE_USERS,\n    },\n    {\n      id: 'managerequest',\n      name: intl.formatMessage(messages.managerequests),\n      description: intl.formatMessage(messages.managerequestsDescription),\n      permission: Permission.MANAGE_REQUESTS,\n      children: [\n        {\n          id: 'advancedrequest',\n          name: intl.formatMessage(messages.advancedrequest),\n          description: intl.formatMessage(messages.advancedrequestDescription),\n          permission: Permission.REQUEST_ADVANCED,\n        },\n        {\n          id: 'viewrequests',\n          name: intl.formatMessage(messages.viewrequests),\n          description: intl.formatMessage(messages.viewrequestsDescription),\n          permission: Permission.REQUEST_VIEW,\n        },\n        {\n          id: 'viewrecent',\n          name: intl.formatMessage(messages.viewrecent),\n          description: intl.formatMessage(messages.viewrecentDescription),\n          permission: Permission.RECENT_VIEW,\n        },\n        {\n          id: 'viewwatchlists',\n          name: intl.formatMessage(messages.viewwatchlists, {\n            mediaServerName:\n              settings.currentSettings.mediaServerType === MediaServerType.PLEX\n                ? 'Plex'\n                : settings.currentSettings.mediaServerType ===\n                    MediaServerType.JELLYFIN\n                  ? 'Jellyfin'\n                  : 'Emby',\n          }),\n          description: intl.formatMessage(messages.viewwatchlistsDescription, {\n            mediaServerName:\n              settings.currentSettings.mediaServerType === MediaServerType.PLEX\n                ? 'Plex'\n                : settings.currentSettings.mediaServerType ===\n                    MediaServerType.JELLYFIN\n                  ? 'Jellyfin'\n                  : 'Emby',\n          }),\n          permission: Permission.WATCHLIST_VIEW,\n        },\n      ],\n    },\n    {\n      id: 'request',\n      name: intl.formatMessage(messages.request),\n      description: intl.formatMessage(messages.requestDescription),\n      permission: Permission.REQUEST,\n      children: [\n        {\n          id: 'request-movies',\n          name: intl.formatMessage(messages.requestMovies),\n          description: intl.formatMessage(messages.requestMoviesDescription),\n          permission: Permission.REQUEST_MOVIE,\n        },\n        {\n          id: 'request-tv',\n          name: intl.formatMessage(messages.requestTv),\n          description: intl.formatMessage(messages.requestTvDescription),\n          permission: Permission.REQUEST_TV,\n        },\n      ],\n    },\n    {\n      id: 'autoapprove',\n      name: intl.formatMessage(messages.autoapprove),\n      description: intl.formatMessage(messages.autoapproveDescription),\n      permission: Permission.AUTO_APPROVE,\n      requires: [{ permissions: [Permission.REQUEST] }],\n      children: [\n        {\n          id: 'autoapprovemovies',\n          name: intl.formatMessage(messages.autoapproveMovies),\n          description: intl.formatMessage(\n            messages.autoapproveMoviesDescription\n          ),\n          permission: Permission.AUTO_APPROVE_MOVIE,\n          requires: [\n            {\n              permissions: [Permission.REQUEST, Permission.REQUEST_MOVIE],\n              type: 'or',\n            },\n          ],\n        },\n        {\n          id: 'autoapprovetv',\n          name: intl.formatMessage(messages.autoapproveSeries),\n          description: intl.formatMessage(\n            messages.autoapproveSeriesDescription\n          ),\n          permission: Permission.AUTO_APPROVE_TV,\n          requires: [\n            {\n              permissions: [Permission.REQUEST, Permission.REQUEST_TV],\n              type: 'or',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      id: 'autorequest',\n      name: intl.formatMessage(messages.autorequest),\n      description: intl.formatMessage(messages.autorequestDescription),\n      permission: Permission.AUTO_REQUEST,\n      requires: [{ permissions: [Permission.REQUEST] }],\n      children: [\n        {\n          id: 'autorequestmovies',\n          name: intl.formatMessage(messages.autorequestMovies),\n          description: intl.formatMessage(\n            messages.autorequestMoviesDescription\n          ),\n          permission: Permission.AUTO_REQUEST_MOVIE,\n          requires: [\n            {\n              permissions: [Permission.REQUEST, Permission.REQUEST_MOVIE],\n              type: 'or',\n            },\n          ],\n        },\n        {\n          id: 'autorequesttv',\n          name: intl.formatMessage(messages.autorequestSeries),\n          description: intl.formatMessage(\n            messages.autorequestSeriesDescription\n          ),\n          permission: Permission.AUTO_REQUEST_TV,\n          requires: [\n            {\n              permissions: [Permission.REQUEST, Permission.REQUEST_TV],\n              type: 'or',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      id: 'request4k',\n      name: intl.formatMessage(messages.request4k),\n      description: intl.formatMessage(messages.request4kDescription),\n      permission: Permission.REQUEST_4K,\n      children: [\n        {\n          id: 'request4k-movies',\n          name: intl.formatMessage(messages.request4kMovies),\n          description: intl.formatMessage(messages.request4kMoviesDescription),\n          permission: Permission.REQUEST_4K_MOVIE,\n        },\n        {\n          id: 'request4k-tv',\n          name: intl.formatMessage(messages.request4kTv),\n          description: intl.formatMessage(messages.request4kTvDescription),\n          permission: Permission.REQUEST_4K_TV,\n        },\n      ],\n    },\n    {\n      id: 'autoapprove4k',\n      name: intl.formatMessage(messages.autoapprove4k),\n      description: intl.formatMessage(messages.autoapprove4kDescription),\n      permission: Permission.AUTO_APPROVE_4K,\n      requires: [\n        {\n          permissions: [Permission.REQUEST_4K],\n        },\n      ],\n      children: [\n        {\n          id: 'autoapprove4k-movies',\n          name: intl.formatMessage(messages.autoapprove4kMovies),\n          description: intl.formatMessage(\n            messages.autoapprove4kMoviesDescription\n          ),\n          permission: Permission.AUTO_APPROVE_4K_MOVIE,\n          requires: [\n            {\n              permissions: [Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE],\n              type: 'or',\n            },\n          ],\n        },\n        {\n          id: 'autoapprove4k-tv',\n          name: intl.formatMessage(messages.autoapprove4kSeries),\n          description: intl.formatMessage(\n            messages.autoapprove4kSeriesDescription\n          ),\n          permission: Permission.AUTO_APPROVE_4K_TV,\n          requires: [\n            {\n              permissions: [Permission.REQUEST_4K, Permission.REQUEST_4K_TV],\n              type: 'or',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      id: 'manageissues',\n      name: intl.formatMessage(messages.manageissues),\n      description: intl.formatMessage(messages.manageissuesDescription),\n      permission: Permission.MANAGE_ISSUES,\n      children: [\n        {\n          id: 'createissues',\n          name: intl.formatMessage(messages.createissues),\n          description: intl.formatMessage(messages.createissuesDescription),\n          permission: Permission.CREATE_ISSUES,\n        },\n        {\n          id: 'viewissues',\n          name: intl.formatMessage(messages.viewissues),\n          description: intl.formatMessage(messages.viewissuesDescription),\n          permission: Permission.VIEW_ISSUES,\n        },\n      ],\n    },\n    {\n      id: 'manageblocklist',\n      name: intl.formatMessage(messages.manageblocklist),\n      description: intl.formatMessage(messages.manageblocklistDescription),\n      permission: Permission.MANAGE_BLOCKLIST,\n      children: [\n        {\n          id: 'viewblocklisteditems',\n          name: intl.formatMessage(messages.viewblocklistedItems),\n          description: intl.formatMessage(\n            messages.viewblocklistedItemsDescription\n          ),\n          permission: Permission.VIEW_BLOCKLIST,\n        },\n      ],\n    },\n  ];\n\n  return (\n    <>\n      {permissionList.map((permissionItem) => (\n        <PermissionOption\n          key={`permission-option-${permissionItem.id}`}\n          option={permissionItem}\n          actingUser={actingUser}\n          currentUser={currentUser}\n          currentPermission={currentPermission}\n          onUpdate={(newPermission) => onUpdate(newPermission)}\n        />\n      ))}\n    </>\n  );\n};\n\nexport default PermissionEdit;\n"
  },
  {
    "path": "src/components/PermissionOption/index.tsx",
    "content": "import useSettings from '@app/hooks/useSettings';\nimport type { User } from '@app/hooks/useUser';\nimport { Permission } from '@app/hooks/useUser';\nimport { hasPermission } from '@server/lib/permissions';\n\nexport interface PermissionItem {\n  id: string;\n  name: string;\n  description: string;\n  permission: Permission;\n  children?: PermissionItem[];\n  requires?: PermissionRequirement[];\n}\n\ninterface PermissionRequirement {\n  permissions: Permission[];\n  type?: 'and' | 'or';\n}\n\ninterface PermissionOptionProps {\n  option: PermissionItem;\n  actingUser?: User;\n  currentUser?: User;\n  currentPermission: number;\n  parent?: PermissionItem;\n  onUpdate: (newPermissions: number) => void;\n}\n\nconst PermissionOption = ({\n  option,\n  actingUser,\n  currentUser,\n  currentPermission,\n  onUpdate,\n  parent,\n}: PermissionOptionProps) => {\n  const settings = useSettings();\n\n  const autoApprovePermissions = [\n    Permission.AUTO_APPROVE,\n    Permission.AUTO_APPROVE_MOVIE,\n    Permission.AUTO_APPROVE_TV,\n    Permission.AUTO_APPROVE_4K,\n    Permission.AUTO_APPROVE_4K_MOVIE,\n    Permission.AUTO_APPROVE_4K_TV,\n  ];\n\n  let disabled = false;\n  let checked = hasPermission(option.permission, currentPermission);\n\n  if (\n    // Permissions for user ID 1 (Plex server owner) cannot be changed\n    (currentUser && currentUser.id === 1) ||\n    // Admin permission automatically bypasses/grants all other permissions\n    (option.permission !== Permission.ADMIN &&\n      hasPermission(Permission.ADMIN, currentPermission)) ||\n    // Manage Requests permission automatically grants all Auto-Approve permissions\n    (autoApprovePermissions.includes(option.permission) &&\n      hasPermission(Permission.MANAGE_REQUESTS, currentPermission)) ||\n    // Selecting a parent permission automatically selects all children\n    (!!parent?.permission &&\n      hasPermission(parent.permission, currentPermission))\n  ) {\n    disabled = true;\n    checked = true;\n  }\n\n  if (\n    // Only the owner can modify the Admin permission\n    actingUser?.id !== 1 &&\n    option.permission === Permission.ADMIN\n  ) {\n    disabled = true;\n  }\n\n  if (\n    // Some permissions are dependent on others; check requirements are fulfilled\n    (option.requires &&\n      !option.requires.every((requirement) =>\n        hasPermission(requirement.permissions, currentPermission, {\n          type: requirement.type ?? 'and',\n        })\n      )) ||\n    // Request 4K and Auto-Approve 4K require both 4K movie & 4K series requests to be enabled\n    ((option.permission === Permission.REQUEST_4K ||\n      option.permission === Permission.AUTO_APPROVE_4K) &&\n      (!settings.currentSettings.movie4kEnabled ||\n        !settings.currentSettings.series4kEnabled)) ||\n    // Request 4K Movie and Auto-Approve 4K Movie require 4K movie requests to be enabled\n    ((option.permission === Permission.REQUEST_4K_MOVIE ||\n      option.permission === Permission.AUTO_APPROVE_4K_MOVIE) &&\n      !settings.currentSettings.movie4kEnabled) ||\n    // Request 4K Series and Auto-Approve 4K Series require 4K series requests to be enabled\n    ((option.permission === Permission.REQUEST_4K_TV ||\n      option.permission === Permission.AUTO_APPROVE_4K_TV) &&\n      !settings.currentSettings.series4kEnabled)\n  ) {\n    disabled = true;\n    checked = false;\n  }\n\n  return (\n    <>\n      <div\n        className={`relative mt-4 flex items-start first:mt-0 ${\n          disabled ? 'opacity-50' : ''\n        }`}\n      >\n        <div className=\"flex h-6 items-center\">\n          <input\n            id={option.id}\n            name=\"permissions\"\n            type=\"checkbox\"\n            disabled={disabled}\n            onChange={() => {\n              onUpdate(\n                hasPermission(option.permission, currentPermission)\n                  ? currentPermission - option.permission\n                  : currentPermission + option.permission\n              );\n            }}\n            checked={checked}\n          />\n        </div>\n        <div className=\"ml-3 text-sm leading-6\">\n          <label htmlFor={option.id} className=\"block\" aria-label={option.name}>\n            <div className=\"flex flex-col\">\n              <span className=\"font-medium text-white\">{option.name}</span>\n              <span className=\"font-normal text-gray-400\">\n                {option.description}\n              </span>\n            </div>\n          </label>\n        </div>\n      </div>\n      {(option.children ?? []).map((child) => (\n        <div key={`permission-child-${child.id}`} className=\"mt-4 pl-10\">\n          <PermissionOption\n            option={child}\n            currentPermission={currentPermission}\n            onUpdate={(newPermission) => onUpdate(newPermission)}\n            parent={option}\n          />\n        </div>\n      ))}\n    </>\n  );\n};\n\nexport default PermissionOption;\n"
  },
  {
    "path": "src/components/PersonCard/index.tsx",
    "content": "import CachedImage from '@app/components/Common/CachedImage';\nimport { UserCircleIcon } from '@heroicons/react/24/solid';\nimport Link from 'next/link';\nimport { useState } from 'react';\n\ninterface PersonCardProps {\n  personId: number;\n  name: string;\n  subName?: string;\n  profilePath?: string;\n  canExpand?: boolean;\n}\n\nconst PersonCard = ({\n  personId,\n  name,\n  subName,\n  profilePath,\n  canExpand = false,\n}: PersonCardProps) => {\n  const [isHovered, setHovered] = useState(false);\n\n  return (\n    <Link\n      href={`/person/${personId}`}\n      className={canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'}\n      onMouseEnter={() => {\n        setHovered(true);\n      }}\n      onMouseLeave={() => setHovered(false)}\n      onKeyDown={(e) => {\n        if (e.key === 'Enter') {\n          setHovered(true);\n        }\n      }}\n      role=\"link\"\n      tabIndex={0}\n    >\n      <div\n        className={`relative ${\n          canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'\n        } transform-gpu cursor-pointer rounded-xl text-white shadow ring-1 transition duration-150 ease-in-out ${\n          isHovered\n            ? 'scale-105 bg-gray-700 ring-gray-500'\n            : 'scale-100 bg-gray-800 ring-gray-700'\n        }`}\n      >\n        <div style={{ paddingBottom: '150%' }}>\n          <div className=\"absolute inset-0 flex h-full w-full flex-col items-center p-2\">\n            <div className=\"relative mb-4 mt-2 flex h-1/2 w-full justify-center\">\n              {profilePath ? (\n                <div className=\"relative h-full w-3/4 overflow-hidden rounded-full ring-1 ring-gray-700\">\n                  <CachedImage\n                    type=\"tmdb\"\n                    src={`https://image.tmdb.org/t/p/w600_and_h900_bestv2${profilePath}`}\n                    alt=\"\"\n                    style={{\n                      width: '100%',\n                      height: '100%',\n                      objectFit: 'cover',\n                    }}\n                    fill\n                  />\n                </div>\n              ) : (\n                <UserCircleIcon className=\"h-full\" />\n              )}\n            </div>\n            <div className=\"w-full truncate text-center font-bold\">{name}</div>\n            {subName && (\n              <div\n                className=\"overflow-hidden whitespace-normal text-center text-sm text-gray-300\"\n                style={{\n                  WebkitLineClamp: 2,\n                  display: '-webkit-box',\n                  overflow: 'hidden',\n                  WebkitBoxOrient: 'vertical',\n                }}\n              >\n                {subName}\n              </div>\n            )}\n            <div\n              className={`absolute bottom-0 left-0 right-0 h-12 rounded-b-xl bg-gradient-to-t ${\n                isHovered ? 'from-gray-800' : 'from-gray-900'\n              }`}\n            />\n          </div>\n        </div>\n      </div>\n    </Link>\n  );\n};\n\nexport default PersonCard;\n"
  },
  {
    "path": "src/components/PersonDetails/index.tsx",
    "content": "import Ellipsis from '@app/assets/ellipsis.svg';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport ImageFader from '@app/components/Common/ImageFader';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport TitleCard from '@app/components/TitleCard';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { CircleStackIcon } from '@heroicons/react/24/solid';\nimport type { PersonCombinedCreditsResponse } from '@server/interfaces/api/personInterfaces';\nimport type { PersonDetails as PersonDetailsType } from '@server/models/Person';\nimport { groupBy } from 'lodash';\nimport { useRouter } from 'next/router';\nimport { useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport TruncateMarkup from 'react-truncate-markup';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.PersonDetails', {\n  birthdate: 'Born {birthdate}',\n  lifespan: '{birthdate} – {deathdate}',\n  alsoknownas: 'Also Known As: {names}',\n  appearsin: 'Appearances',\n  crewmember: 'Crew',\n  ascharacter: 'as {character}',\n});\n\ntype MediaType = 'all' | 'movie' | 'tv';\n\nconst PersonDetails = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const [currentMediaType, setCurrentMediaType] = useState<string>('all');\n  const { data, error } = useSWR<PersonDetailsType>(\n    `/api/v1/person/${router.query.personId}`\n  );\n  const [showBio, setShowBio] = useState(false);\n\n  const { data: combinedCredits, error: errorCombinedCredits } =\n    useSWR<PersonCombinedCreditsResponse>(\n      `/api/v1/person/${router.query.personId}/combined_credits`\n    );\n\n  const sortedCast = useMemo(() => {\n    const filtered = (combinedCredits?.cast ?? []).filter(\n      (media) =>\n        currentMediaType === 'all' || media.mediaType === currentMediaType\n    );\n    const grouped = groupBy(filtered, 'id');\n\n    const reduced = Object.values(grouped).map((objs) => ({\n      ...objs[0],\n      character: objs.map((pos) => pos.character).join(', '),\n    }));\n\n    return reduced.sort((a, b) => {\n      const aVotes = a.voteCount ?? 0;\n      const bVotes = b.voteCount ?? 0;\n      if (aVotes > bVotes) {\n        return -1;\n      }\n      return 1;\n    });\n  }, [combinedCredits, currentMediaType]);\n\n  const sortedCrew = useMemo(() => {\n    const filtered = (combinedCredits?.crew ?? []).filter(\n      (media) =>\n        currentMediaType === 'all' || media.mediaType === currentMediaType\n    );\n    const grouped = groupBy(filtered, 'id');\n\n    const reduced = Object.values(grouped).map((objs) => ({\n      ...objs[0],\n      job: objs.map((pos) => pos.job).join(', '),\n    }));\n\n    return reduced.sort((a, b) => {\n      const aVotes = a.voteCount ?? 0;\n      const bVotes = b.voteCount ?? 0;\n      if (aVotes > bVotes) {\n        return -1;\n      }\n      return 1;\n    });\n  }, [combinedCredits, currentMediaType]);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  const personAttributes: string[] = [];\n\n  if (data.birthday) {\n    if (data.deathday) {\n      personAttributes.push(\n        intl.formatMessage(messages.lifespan, {\n          birthdate: intl.formatDate(data.birthday, {\n            year: 'numeric',\n            month: 'long',\n            day: 'numeric',\n            timeZone: 'UTC',\n          }),\n          deathdate: intl.formatDate(data.deathday, {\n            year: 'numeric',\n            month: 'long',\n            day: 'numeric',\n            timeZone: 'UTC',\n          }),\n        })\n      );\n    } else {\n      personAttributes.push(\n        intl.formatMessage(messages.birthdate, {\n          birthdate: intl.formatDate(data.birthday, {\n            year: 'numeric',\n            month: 'long',\n            day: 'numeric',\n            timeZone: 'UTC',\n          }),\n        })\n      );\n    }\n  }\n\n  if (data.placeOfBirth) {\n    personAttributes.push(data.placeOfBirth);\n  }\n\n  const isLoading = !combinedCredits && !errorCombinedCredits;\n\n  const mediaTypePicker = (\n    <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0\">\n      <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n        <CircleStackIcon className=\"h-6 w-6\" />\n      </span>\n      <select\n        id=\"mediaType\"\n        name=\"mediaType\"\n        onChange={(e) => {\n          setCurrentMediaType(e.target.value as MediaType);\n        }}\n        value={currentMediaType}\n        className=\"rounded-r-only\"\n      >\n        <option value=\"all\">{intl.formatMessage(globalMessages.all)}</option>\n        <option value=\"movie\">\n          {intl.formatMessage(globalMessages.movies)}\n        </option>\n        <option value=\"tv\">{intl.formatMessage(globalMessages.tvshows)}</option>\n      </select>\n    </div>\n  );\n\n  const cast = (sortedCast ?? []).length > 0 && (\n    <>\n      <div className=\"slider-header\">\n        <div className=\"slider-title\">\n          <span>{intl.formatMessage(messages.appearsin)}</span>\n        </div>\n      </div>\n      <ul className=\"cards-vertical\">\n        {sortedCast?.map((media, index) => {\n          return (\n            <li key={`list-cast-item-${media.id}-${index}`}>\n              <TitleCard\n                key={media.id}\n                id={media.id}\n                title={media.mediaType === 'movie' ? media.title : media.name}\n                userScore={media.voteAverage}\n                year={\n                  media.mediaType === 'movie'\n                    ? media.releaseDate\n                    : media.firstAirDate\n                }\n                image={media.posterPath}\n                summary={media.overview}\n                mediaType={media.mediaType as 'movie' | 'tv'}\n                status={media.mediaInfo?.status}\n                canExpand\n              />\n              {media.character && (\n                <div className=\"mt-2 w-full truncate text-center text-xs text-gray-300\">\n                  {intl.formatMessage(messages.ascharacter, {\n                    character: media.character,\n                  })}\n                </div>\n              )}\n            </li>\n          );\n        })}\n      </ul>\n    </>\n  );\n\n  const crew = (sortedCrew ?? []).length > 0 && (\n    <>\n      <div className=\"slider-header\">\n        <div className=\"slider-title\">\n          <span>{intl.formatMessage(messages.crewmember)}</span>\n        </div>\n      </div>\n      <ul className=\"cards-vertical\">\n        {sortedCrew?.map((media, index) => {\n          return (\n            <li key={`list-crew-item-${media.id}-${index}`}>\n              <TitleCard\n                key={media.id}\n                id={media.id}\n                title={media.mediaType === 'movie' ? media.title : media.name}\n                userScore={media.voteAverage}\n                year={\n                  media.mediaType === 'movie'\n                    ? media.releaseDate\n                    : media.firstAirDate\n                }\n                image={media.posterPath}\n                summary={media.overview}\n                mediaType={media.mediaType as 'movie' | 'tv'}\n                status={media.mediaInfo?.status}\n                canExpand\n              />\n              {media.job && (\n                <div className=\"mt-2 w-full truncate text-center text-xs text-gray-300\">\n                  {media.job}\n                </div>\n              )}\n            </li>\n          );\n        })}\n      </ul>\n    </>\n  );\n\n  return (\n    <>\n      <PageTitle title={data.name} />\n      {(sortedCrew || sortedCast) && (\n        <div className=\"absolute left-0 right-0 top-0 z-0 h-96\">\n          <ImageFader\n            isDarker\n            backgroundImages={[...(sortedCast ?? []), ...(sortedCrew ?? [])]\n              .filter((media) => media.backdropPath)\n              .map(\n                (media) =>\n                  `https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${media.backdropPath}`\n              )\n              .slice(0, 6)}\n          />\n        </div>\n      )}\n      <div\n        className={`relative z-10 mb-8 mt-4 flex flex-col items-center lg:flex-row ${\n          data.biography ? 'lg:items-start' : ''\n        }`}\n      >\n        {data.profilePath && (\n          <div className=\"relative mb-6 mr-0 h-36 w-36 flex-shrink-0 overflow-hidden rounded-full ring-1 ring-gray-700 lg:mb-0 lg:mr-6 lg:h-44 lg:w-44\">\n            <CachedImage\n              type=\"tmdb\"\n              src={`https://image.tmdb.org/t/p/w600_and_h900_bestv2${data.profilePath}`}\n              alt=\"\"\n              style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n              fill\n            />\n          </div>\n        )}\n        <div className=\"w-full text-center text-gray-300 lg:text-left\">\n          <div className=\"flex w-full items-center justify-center lg:justify-between\">\n            <h1 className=\"text-3xl text-white lg:text-4xl\">{data.name}</h1>\n            <div className=\"hidden flex-shrink-0 lg:block\">\n              {mediaTypePicker}\n            </div>\n          </div>\n          <div className=\"mb-2 mt-1 space-y-1 text-xs text-white sm:text-sm lg:text-base\">\n            <div>{personAttributes.join(' | ')}</div>\n            {(data.alsoKnownAs ?? []).length > 0 && (\n              <div>\n                {intl.formatMessage(messages.alsoknownas, {\n                  names: (data.alsoKnownAs ?? []).reduce((prev, curr) =>\n                    intl.formatMessage(globalMessages.delimitedlist, {\n                      a: prev,\n                      b: curr,\n                    })\n                  ),\n                })}\n              </div>\n            )}\n          </div>\n          <div className=\"lg:hidden\">{mediaTypePicker}</div>\n          {data.biography && (\n            <div className=\"relative text-left\">\n              {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}\n              <div\n                className=\"group outline-none ring-0\"\n                onClick={() => setShowBio((show) => !show)}\n                role=\"button\"\n                tabIndex={-1}\n              >\n                <TruncateMarkup\n                  lines={showBio ? 200 : 6}\n                  ellipsis={\n                    <Ellipsis className=\"relative -top-0.5 ml-2 inline-block opacity-70 transition duration-300 group-hover:opacity-100\" />\n                  }\n                >\n                  <p className=\"pt-2 text-sm lg:text-base\">{data.biography}</p>\n                </TruncateMarkup>\n              </div>\n            </div>\n          )}\n        </div>\n      </div>\n      {data.knownForDepartment === 'Acting' ? [cast, crew] : [crew, cast]}\n      {isLoading && <LoadingSpinner />}\n    </>\n  );\n};\n\nexport default PersonDetails;\n"
  },
  {
    "path": "src/components/QuotaSelector/index.tsx",
    "content": "import defineMessages from '@app/utils/defineMessages';\nimport React, { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.QuotaSelector', {\n  movieRequests:\n    '{quotaLimit} <quotaUnits>{movies} per {quotaDays} {days}</quotaUnits>',\n  tvRequests:\n    '{quotaLimit} <quotaUnits>{seasons} per {quotaDays} {days}</quotaUnits>',\n  movies: '{count, plural, one {movie} other {movies}}',\n  seasons: '{count, plural, one {season} other {seasons}}',\n  days: '{count, plural, one {day} other {days}}',\n  unlimited: 'Unlimited',\n});\n\ninterface QuotaSelectorProps {\n  mediaType: 'movie' | 'tv';\n  defaultDays?: number;\n  defaultLimit?: number;\n  dayOverride?: number;\n  limitOverride?: number;\n  dayFieldName: string;\n  limitFieldName: string;\n  isDisabled?: boolean;\n  onChange: (fieldName: string, value: number) => void;\n}\n\nconst QuotaSelector = ({\n  mediaType,\n  dayFieldName,\n  limitFieldName,\n  defaultDays = 7,\n  defaultLimit = 0,\n  dayOverride,\n  limitOverride,\n  isDisabled = false,\n  onChange,\n}: QuotaSelectorProps) => {\n  const initialDays = defaultDays ?? 7;\n  const initialLimit = defaultLimit ?? 0;\n  const [quotaDays, setQuotaDays] = useState(initialDays);\n  const [quotaLimit, setQuotaLimit] = useState(initialLimit);\n  const intl = useIntl();\n\n  useEffect(() => {\n    onChange(dayFieldName, quotaDays);\n  }, [dayFieldName, onChange, quotaDays]);\n\n  useEffect(() => {\n    onChange(limitFieldName, quotaLimit);\n  }, [limitFieldName, onChange, quotaLimit]);\n\n  return (\n    <div className={`${isDisabled ? 'opacity-50' : ''}`}>\n      {intl.formatMessage(\n        mediaType === 'movie' ? messages.movieRequests : messages.tvRequests,\n        {\n          quotaLimit: (\n            <select\n              className=\"short inline\"\n              value={limitOverride ?? quotaLimit}\n              onChange={(e) => setQuotaLimit(Number(e.target.value))}\n              disabled={isDisabled}\n            >\n              <option value=\"0\">\n                {intl.formatMessage(messages.unlimited)}\n              </option>\n              {[...Array(100)].map((_item, i) => (\n                <option value={i + 1} key={`${mediaType}-limit-${i + 1}`}>\n                  {i + 1}\n                </option>\n              ))}\n            </select>\n          ),\n          quotaDays: (\n            <select\n              className=\"short inline\"\n              value={dayOverride ?? quotaDays}\n              onChange={(e) => setQuotaDays(Number(e.target.value))}\n              disabled={isDisabled}\n            >\n              {[...Array(100)].map((_item, i) => (\n                <option value={i + 1} key={`${mediaType}-days-${i + 1}`}>\n                  {i + 1}\n                </option>\n              ))}\n            </select>\n          ),\n          movies: intl.formatMessage(messages.movies, { count: quotaLimit }),\n          seasons: intl.formatMessage(messages.seasons, { count: quotaLimit }),\n          days: intl.formatMessage(messages.days, { count: quotaDays }),\n          quotaUnits: function quotaUnits(msg) {\n            return (\n              <span className={limitOverride || quotaLimit ? '' : 'hidden'}>\n                {msg}\n              </span>\n            );\n          },\n        }\n      )}\n    </div>\n  );\n};\n\nexport default React.memo(QuotaSelector);\n"
  },
  {
    "path": "src/components/RegionSelector/index.tsx",
    "content": "import useSettings from '@app/hooks/useSettings';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Listbox, Transition } from '@headlessui/react';\nimport { CheckIcon, ChevronDownIcon } from '@heroicons/react/24/solid';\nimport type { Region } from '@server/lib/settings';\nimport { countries } from 'country-flag-icons';\nimport 'country-flag-icons/3x2/flags.css';\nimport { sortBy } from 'lodash';\nimport { useEffect, useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.RegionSelector', {\n  regionDefault: 'All Regions',\n  regionServerDefault: 'Default ({region})',\n});\n\ninterface RegionSelectorProps {\n  value: string;\n  name: string;\n  isUserSetting?: boolean;\n  disableAll?: boolean;\n  watchProviders?: boolean;\n  regionType?: 'discover' | 'streaming';\n  onChange?: (fieldName: string, region: string) => void;\n}\n\nconst RegionSelector = ({\n  name,\n  value,\n  isUserSetting = false,\n  disableAll = false,\n  watchProviders = false,\n  regionType = 'discover',\n  onChange,\n}: RegionSelectorProps) => {\n  const { currentSettings } = useSettings();\n  const intl = useIntl();\n  const { data: regions } = useSWR<Region[]>(\n    watchProviders ? '/api/v1/watchproviders/regions' : '/api/v1/regions'\n  );\n  const [selectedRegion, setSelectedRegion] = useState<Region | null>(null);\n\n  const allRegion: Region = useMemo(\n    () => ({\n      iso_3166_1: 'all',\n      english_name: 'All',\n    }),\n    []\n  );\n\n  const sortedRegions = useMemo(() => {\n    regions?.forEach((region) => {\n      region.name =\n        intl.formatDisplayName(region.iso_3166_1, {\n          type: 'region',\n          fallback: 'none',\n        }) ?? region.english_name;\n    });\n\n    return sortBy(regions, 'name');\n  }, [intl, regions]);\n\n  const regionName = (regionCode: string) =>\n    sortedRegions?.find((region) => region.iso_3166_1 === regionCode)?.name ??\n    regionCode;\n\n  const regionValue =\n    regionType === 'discover'\n      ? currentSettings.discoverRegion\n      : currentSettings.streamingRegion;\n\n  useEffect(() => {\n    if (regions && value) {\n      if (value === 'all') {\n        setSelectedRegion(allRegion);\n      } else {\n        const matchedRegion = regions.find(\n          (region) => region.iso_3166_1 === value\n        );\n        setSelectedRegion(matchedRegion ?? null);\n      }\n    }\n  }, [value, regions, allRegion]);\n\n  const handleRegionSelect = (region: Region | null) => {\n    setSelectedRegion(region);\n    onChange?.(name, region?.iso_3166_1 ?? '');\n  };\n\n  return (\n    <div className=\"z-40 w-full\">\n      <Listbox as=\"div\" value={selectedRegion} onChange={handleRegionSelect}>\n        {({ open }) => (\n          <div className=\"relative\">\n            <span className=\"inline-block w-full rounded-md shadow-sm\">\n              <Listbox.Button className=\"focus:shadow-outline-blue relative flex w-full cursor-default items-center rounded-md border border-gray-500 bg-gray-700 py-2 pl-3 pr-10 text-left text-white transition duration-150 ease-in-out focus:border-blue-300 focus:outline-none sm:text-sm sm:leading-5\">\n                {((selectedRegion &&\n                  countries.includes(selectedRegion?.iso_3166_1)) ||\n                  (isUserSetting &&\n                    !selectedRegion &&\n                    regionValue &&\n                    countries.includes(regionValue))) && (\n                  <span className=\"mr-2 h-4 overflow-hidden text-base leading-4\">\n                    <span\n                      className={`flag:${\n                        selectedRegion ? selectedRegion.iso_3166_1 : regionValue\n                      }`}\n                    />\n                  </span>\n                )}\n                <span className=\"block truncate\">\n                  {selectedRegion && selectedRegion.iso_3166_1 !== 'all'\n                    ? regionName(selectedRegion.iso_3166_1)\n                    : isUserSetting && selectedRegion?.iso_3166_1 !== 'all'\n                      ? intl.formatMessage(messages.regionServerDefault, {\n                          region: regionValue\n                            ? regionName(regionValue)\n                            : intl.formatMessage(messages.regionDefault),\n                        })\n                      : intl.formatMessage(messages.regionDefault)}\n                </span>\n                <span className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-500\">\n                  <ChevronDownIcon className=\"h-5 w-5\" />\n                </span>\n              </Listbox.Button>\n            </span>\n\n            <Transition\n              show={open}\n              leave=\"transition-opacity ease-in duration-100\"\n              leaveFrom=\"opacity-100\"\n              leaveTo=\"opacity-0\"\n              className=\"absolute mt-1 w-full rounded-md bg-gray-800 shadow-lg\"\n            >\n              <Listbox.Options\n                static\n                className=\"shadow-xs max-h-60 overflow-auto rounded-md py-1 text-base leading-6 focus:outline-none sm:text-sm sm:leading-5\"\n              >\n                {isUserSetting && (\n                  <Listbox.Option value={null}>\n                    {({ selected, active }) => (\n                      <div\n                        className={`${\n                          active ? 'bg-indigo-600 text-white' : 'text-gray-300'\n                        } relative flex cursor-default select-none items-center py-2 pl-8 pr-4`}\n                      >\n                        <span className=\"mr-2 text-base\">\n                          <span\n                            className={\n                              countries.includes(regionValue)\n                                ? `flag:${regionValue}`\n                                : 'pr-6'\n                            }\n                          />\n                        </span>\n                        <span\n                          className={`${\n                            selected ? 'font-semibold' : 'font-normal'\n                          } block truncate`}\n                        >\n                          {intl.formatMessage(messages.regionServerDefault, {\n                            region: regionValue\n                              ? regionName(regionValue)\n                              : intl.formatMessage(messages.regionDefault),\n                          })}\n                        </span>\n                        {selected && (\n                          <span\n                            className={`${\n                              active ? 'text-white' : 'text-indigo-600'\n                            } absolute inset-y-0 left-0 flex items-center pl-1.5`}\n                          >\n                            <CheckIcon className=\"h-5 w-5\" />\n                          </span>\n                        )}\n                      </div>\n                    )}\n                  </Listbox.Option>\n                )}\n                {!disableAll && (\n                  <Listbox.Option value={isUserSetting ? allRegion : null}>\n                    {({ selected, active }) => (\n                      <div\n                        className={`${\n                          active ? 'bg-indigo-600 text-white' : 'text-gray-300'\n                        } relative cursor-default select-none py-2 pl-8 pr-4`}\n                      >\n                        <span\n                          className={`${\n                            selected ? 'font-semibold' : 'font-normal'\n                          } block truncate pl-8`}\n                        >\n                          {intl.formatMessage(messages.regionDefault)}\n                        </span>\n                        {selected && (\n                          <span\n                            className={`${\n                              active ? 'text-white' : 'text-indigo-600'\n                            } absolute inset-y-0 left-0 flex items-center pl-1.5`}\n                          >\n                            <CheckIcon className=\"h-5 w-5\" />\n                          </span>\n                        )}\n                      </div>\n                    )}\n                  </Listbox.Option>\n                )}\n                {sortedRegions?.map((region) => (\n                  <Listbox.Option key={region.iso_3166_1} value={region}>\n                    {({ selected, active }) => (\n                      <div\n                        className={`${\n                          active ? 'bg-indigo-600 text-white' : 'text-gray-300'\n                        } relative flex cursor-default select-none items-center py-2 pl-8 pr-4`}\n                      >\n                        <span className=\"mr-2 text-base\">\n                          <span\n                            className={\n                              countries.includes(region.iso_3166_1)\n                                ? `flag:${region.iso_3166_1}`\n                                : 'pr-6'\n                            }\n                          />\n                        </span>\n                        <span\n                          className={`${\n                            selected ? 'font-semibold' : 'font-normal'\n                          } block truncate`}\n                        >\n                          {regionName(region.iso_3166_1)}\n                        </span>\n                        {selected && (\n                          <span\n                            className={`${\n                              active ? 'text-white' : 'text-indigo-600'\n                            } absolute inset-y-0 left-0 flex items-center pl-1.5`}\n                          >\n                            <CheckIcon className=\"h-5 w-5\" />\n                          </span>\n                        )}\n                      </div>\n                    )}\n                  </Listbox.Option>\n                ))}\n              </Listbox.Options>\n            </Transition>\n          </div>\n        )}\n      </Listbox>\n    </div>\n  );\n};\n\nexport default RegionSelector;\n"
  },
  {
    "path": "src/components/RequestBlock/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport RequestModal from '@app/components/RequestModal';\nimport useRequestOverride from '@app/hooks/useRequestOverride';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport {\n  CalendarIcon,\n  CheckIcon,\n  EyeIcon,\n  PencilIcon,\n  TrashIcon,\n  UserIcon,\n  XMarkIcon,\n} from '@heroicons/react/24/solid';\nimport { MediaRequestStatus } from '@server/constants/media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport axios from 'axios';\nimport Link from 'next/link';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { mutate } from 'swr';\n\nconst messages = defineMessages('components.RequestBlock', {\n  seasons: '{seasonCount, plural, one {Season} other {Seasons}}',\n  requestoverrides: 'Request Overrides',\n  server: 'Destination Server',\n  profilechanged: 'Quality Profile',\n  rootfolder: 'Root Folder',\n  languageprofile: 'Language Profile',\n  requestdate: 'Request Date',\n  requestedby: 'Requested By',\n  lastmodifiedby: 'Last Modified By',\n  approve: 'Approve Request',\n  decline: 'Decline Request',\n  edit: 'Edit Request',\n  delete: 'Delete Request',\n});\n\ninterface RequestBlockProps {\n  request: MediaRequest;\n  onUpdate?: () => void;\n}\n\nconst RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {\n  const { user } = useUser();\n  const intl = useIntl();\n  const [isUpdating, setIsUpdating] = useState(false);\n  const [showEditModal, setShowEditModal] = useState(false);\n  const { profile, rootFolder, server, languageProfile } =\n    useRequestOverride(request);\n\n  const updateRequest = async (type: 'approve' | 'decline'): Promise<void> => {\n    setIsUpdating(true);\n    await axios.post(`/api/v1/request/${request.id}/${type}`);\n\n    if (onUpdate) {\n      onUpdate();\n      mutate('/api/v1/request/count');\n    }\n    setIsUpdating(false);\n  };\n\n  const deleteRequest = async () => {\n    setIsUpdating(true);\n    await axios.delete(`/api/v1/request/${request.id}`);\n\n    if (onUpdate) {\n      onUpdate();\n      mutate('/api/v1/request/count');\n    }\n\n    setIsUpdating(false);\n  };\n\n  return (\n    <div className=\"block\">\n      <RequestModal\n        show={showEditModal}\n        tmdbId={request.media.tmdbId}\n        type={request.type}\n        is4k={request.is4k}\n        editRequest={request}\n        onCancel={() => setShowEditModal(false)}\n        onComplete={() => {\n          if (onUpdate) {\n            onUpdate();\n          }\n          setShowEditModal(false);\n        }}\n      />\n      <div className=\"px-4 py-3 text-gray-300\">\n        <div className=\"flex items-center justify-between\">\n          <div className=\"mr-6 min-w-0 flex-1 flex-col items-center text-sm leading-5\">\n            <div className=\"white mb-1 flex flex-nowrap\">\n              <span className=\"flex w-40 items-center truncate md:w-auto\">\n                <Tooltip content={intl.formatMessage(messages.requestedby)}>\n                  <UserIcon className=\"mr-1.5 h-5 w-5 min-w-0 flex-shrink-0\" />\n                </Tooltip>\n                <Link\n                  href={\n                    request.requestedBy.id === user?.id\n                      ? '/profile'\n                      : `/users/${request.requestedBy.id}`\n                  }\n                  className=\"flex items-center font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline\"\n                >\n                  <span className=\"avatar-sm\">\n                    <CachedImage\n                      type=\"avatar\"\n                      src={request.requestedBy.avatar}\n                      alt=\"\"\n                      className=\"avatar-sm object-cover\"\n                      width={20}\n                      height={20}\n                    />\n                  </span>\n                  {request.requestedBy.displayName}\n                </Link>\n              </span>\n            </div>\n            {request.modifiedBy && (\n              <div className=\"flex flex-nowrap\">\n                <span className=\"flex w-40 items-center truncate md:w-auto\">\n                  <Tooltip\n                    content={intl.formatMessage(messages.lastmodifiedby)}\n                  >\n                    <EyeIcon className=\"mr-1.5 h-5 w-5 flex-shrink-0\" />\n                  </Tooltip>\n                  <Link\n                    href={\n                      request.modifiedBy.id === user?.id\n                        ? '/profile'\n                        : `/users/${request.modifiedBy.id}`\n                    }\n                    className=\"flex items-center font-semibold text-gray-100 transition duration-300 hover:text-white hover:underline\"\n                  >\n                    <span className=\"avatar-sm\">\n                      <CachedImage\n                        type=\"avatar\"\n                        src={request.modifiedBy.avatar}\n                        alt=\"\"\n                        className=\"avatar-sm object-cover\"\n                        width={20}\n                        height={20}\n                      />\n                    </span>\n                    {request.modifiedBy.displayName}\n                  </Link>\n                </span>\n              </div>\n            )}\n          </div>\n          <div className=\"ml-2 flex flex-shrink-0 flex-wrap\">\n            {request.status === MediaRequestStatus.PENDING && (\n              <>\n                <Tooltip content={intl.formatMessage(messages.approve)}>\n                  <Button\n                    buttonType=\"success\"\n                    className=\"mr-1\"\n                    onClick={() => updateRequest('approve')}\n                    disabled={isUpdating}\n                  >\n                    <CheckIcon className=\"icon-sm\" />\n                  </Button>\n                </Tooltip>\n                <Tooltip content={intl.formatMessage(messages.decline)}>\n                  <Button\n                    buttonType=\"danger\"\n                    className=\"mr-1\"\n                    onClick={() => updateRequest('decline')}\n                    disabled={isUpdating}\n                  >\n                    <XMarkIcon />\n                  </Button>\n                </Tooltip>\n                <Tooltip content={intl.formatMessage(messages.edit)}>\n                  <Button\n                    buttonType=\"warning\"\n                    onClick={() => setShowEditModal(true)}\n                    disabled={isUpdating}\n                  >\n                    <PencilIcon className=\"icon-sm\" />\n                  </Button>\n                </Tooltip>\n              </>\n            )}\n            {request.status !== MediaRequestStatus.PENDING && (\n              <Tooltip content={intl.formatMessage(messages.delete)}>\n                <Button\n                  buttonType=\"danger\"\n                  onClick={() => deleteRequest()}\n                  disabled={isUpdating}\n                >\n                  <TrashIcon className=\"icon-sm\" />\n                </Button>\n              </Tooltip>\n            )}\n          </div>\n        </div>\n        <div className=\"mt-2 sm:flex sm:justify-between\">\n          <div className=\"sm:flex\">\n            <div className=\"mr-6 flex items-center text-sm leading-5\">\n              {request.is4k && (\n                <span className=\"mr-1\">\n                  <Badge badgeType=\"warning\">4K</Badge>\n                </span>\n              )}\n              {request.status === MediaRequestStatus.APPROVED && (\n                <Badge badgeType=\"success\">\n                  {intl.formatMessage(globalMessages.approved)}\n                </Badge>\n              )}\n              {request.status === MediaRequestStatus.DECLINED && (\n                <Badge badgeType=\"danger\">\n                  {intl.formatMessage(globalMessages.declined)}\n                </Badge>\n              )}\n              {request.status === MediaRequestStatus.PENDING && (\n                <Badge badgeType=\"warning\">\n                  {intl.formatMessage(globalMessages.pending)}\n                </Badge>\n              )}\n              {request.status === MediaRequestStatus.FAILED && (\n                <Badge badgeType=\"danger\">\n                  {intl.formatMessage(globalMessages.failed)}\n                </Badge>\n              )}\n              {request.status === MediaRequestStatus.COMPLETED && (\n                <Badge badgeType=\"success\">\n                  {intl.formatMessage(globalMessages.completed)}\n                </Badge>\n              )}\n            </div>\n          </div>\n          <div className=\"mt-2 flex items-center text-sm leading-5 sm:mt-0\">\n            <Tooltip content={intl.formatMessage(messages.requestdate)}>\n              <CalendarIcon className=\"mr-1.5 h-5 w-5 flex-shrink-0\" />\n            </Tooltip>\n            <Tooltip\n              content={intl.formatDate(request.createdAt, {\n                year: 'numeric',\n                month: 'long',\n                day: 'numeric',\n                hour: 'numeric',\n                minute: 'numeric',\n                second: 'numeric',\n              })}\n            >\n              <span>\n                {intl.formatDate(request.createdAt, {\n                  year: 'numeric',\n                  month: 'long',\n                  day: 'numeric',\n                })}\n              </span>\n            </Tooltip>\n          </div>\n        </div>\n        {(request.seasons ?? []).length > 0 && (\n          <div className=\"mt-2 flex flex-col text-sm\">\n            <div className=\"mb-1 font-medium\">\n              {intl.formatMessage(messages.seasons, {\n                seasonCount: request.seasons.length,\n              })}\n            </div>\n            <div>\n              {request.seasons.map((season) => (\n                <span\n                  key={`season-${season.id}`}\n                  className=\"mb-1 mr-2 inline-block\"\n                >\n                  <Badge>\n                    {season.seasonNumber === 0\n                      ? intl.formatMessage(globalMessages.specials)\n                      : season.seasonNumber}\n                  </Badge>\n                </span>\n              ))}\n            </div>\n          </div>\n        )}\n        {(server || profile || rootFolder || languageProfile) && (\n          <>\n            <div className=\"mb-1 mt-4 text-sm\">\n              {intl.formatMessage(messages.requestoverrides)}\n            </div>\n            <ul className=\"divide-y divide-gray-700 rounded-md bg-gray-800 px-2 text-xs\">\n              {server && (\n                <li className=\"flex justify-between px-1 py-2\">\n                  <span className=\"font-bold\">\n                    {intl.formatMessage(messages.server)}\n                  </span>\n                  <span>{server}</span>\n                </li>\n              )}\n              {profile && (\n                <li className=\"flex justify-between px-1 py-2\">\n                  <span className=\"font-bold\">\n                    {intl.formatMessage(messages.profilechanged)}\n                  </span>\n                  <span>{profile}</span>\n                </li>\n              )}\n              {rootFolder && (\n                <li className=\"flex justify-between px-1 py-2\">\n                  <span className=\"mr-2 font-bold\">\n                    {intl.formatMessage(messages.rootfolder)}\n                  </span>\n                  <span>{rootFolder}</span>\n                </li>\n              )}\n              {languageProfile && (\n                <li className=\"flex justify-between px-1 py-2\">\n                  <span className=\"mr-2 font-bold\">\n                    {intl.formatMessage(messages.languageprofile)}\n                  </span>\n                  <span>{languageProfile}</span>\n                </li>\n              )}\n            </ul>\n          </>\n        )}\n      </div>\n    </div>\n  );\n};\n\nexport default RequestBlock;\n"
  },
  {
    "path": "src/components/RequestButton/index.tsx",
    "content": "import ButtonWithDropdown from '@app/components/Common/ButtonWithDropdown';\nimport RequestModal from '@app/components/RequestModal';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownTrayIcon } from '@heroicons/react/24/outline';\nimport {\n  CheckIcon,\n  InformationCircleIcon,\n  XMarkIcon,\n} from '@heroicons/react/24/solid';\nimport { MediaRequestStatus, MediaStatus } from '@server/constants/media';\nimport type Media from '@server/entity/Media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport axios from 'axios';\nimport { useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { mutate } from 'swr';\n\nconst messages = defineMessages('components.RequestButton', {\n  viewrequest: 'View Request',\n  viewrequest4k: 'View 4K Request',\n  requestmore: 'Request More',\n  requestmore4k: 'Request More in 4K',\n  approverequest: 'Approve Request',\n  approverequest4k: 'Approve 4K Request',\n  declinerequest: 'Decline Request',\n  declinerequest4k: 'Decline 4K Request',\n  approverequests:\n    'Approve {requestCount, plural, one {Request} other {{requestCount} Requests}}',\n  declinerequests:\n    'Decline {requestCount, plural, one {Request} other {{requestCount} Requests}}',\n  approve4krequests:\n    'Approve {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}',\n  decline4krequests:\n    'Decline {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}',\n});\n\ninterface ButtonOption {\n  id: string;\n  text: string;\n  action: () => void;\n  svg?: React.ReactNode;\n}\n\ninterface RequestButtonProps {\n  mediaType: 'movie' | 'tv';\n  onUpdate: () => void;\n  tmdbId: number;\n  media?: Media;\n  isShowComplete?: boolean;\n  is4kShowComplete?: boolean;\n}\n\nconst RequestButton = ({\n  tmdbId,\n  onUpdate,\n  media,\n  mediaType,\n  isShowComplete = false,\n  is4kShowComplete = false,\n}: RequestButtonProps) => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const { user, hasPermission } = useUser();\n  const [showRequestModal, setShowRequestModal] = useState(false);\n  const [showRequest4kModal, setShowRequest4kModal] = useState(false);\n  const [editRequest, setEditRequest] = useState(false);\n\n  // All pending requests\n  const activeRequests = media?.requests.filter(\n    (request) => request.status === MediaRequestStatus.PENDING && !request.is4k\n  );\n  const active4kRequests = media?.requests.filter(\n    (request) => request.status === MediaRequestStatus.PENDING && request.is4k\n  );\n\n  // Current user's pending request, or the first pending request\n  const activeRequest = useMemo(() => {\n    return activeRequests && activeRequests.length > 0\n      ? (activeRequests.find(\n          (request) => request.requestedBy.id === user?.id\n        ) ?? activeRequests[0])\n      : undefined;\n  }, [activeRequests, user]);\n  const active4kRequest = useMemo(() => {\n    return active4kRequests && active4kRequests.length > 0\n      ? (active4kRequests.find(\n          (request) => request.requestedBy.id === user?.id\n        ) ?? active4kRequests[0])\n      : undefined;\n  }, [active4kRequests, user]);\n\n  const modifyRequest = async (\n    request: MediaRequest,\n    type: 'approve' | 'decline'\n  ) => {\n    const response = await axios.post(`/api/v1/request/${request.id}/${type}`);\n\n    if (response) {\n      onUpdate();\n      mutate('/api/v1/request/count');\n    }\n  };\n\n  const modifyRequests = async (\n    requests: MediaRequest[],\n    type: 'approve' | 'decline'\n  ): Promise<void> => {\n    if (!requests) {\n      return;\n    }\n\n    await Promise.all(\n      requests.map(async (request) => {\n        return axios.post(`/api/v1/request/${request.id}/${type}`);\n      })\n    );\n\n    onUpdate();\n    mutate('/api/v1/request/count');\n  };\n\n  const buttons: ButtonOption[] = [];\n\n  // If there are pending requests, show request management options first\n  if (activeRequest || active4kRequest) {\n    if (\n      activeRequest &&\n      (activeRequest.requestedBy.id === user?.id ||\n        (activeRequests?.length === 1 &&\n          hasPermission(Permission.MANAGE_REQUESTS)))\n    ) {\n      buttons.push({\n        id: 'active-request',\n        text: intl.formatMessage(messages.viewrequest),\n        action: () => {\n          setEditRequest(true);\n          setShowRequestModal(true);\n        },\n        svg: <InformationCircleIcon />,\n      });\n    }\n\n    if (\n      activeRequest &&\n      hasPermission(Permission.MANAGE_REQUESTS) &&\n      mediaType === 'movie'\n    ) {\n      buttons.push(\n        {\n          id: 'approve-request',\n          text: intl.formatMessage(messages.approverequest),\n          action: () => {\n            modifyRequest(activeRequest, 'approve');\n          },\n          svg: <CheckIcon />,\n        },\n        {\n          id: 'decline-request',\n          text: intl.formatMessage(messages.declinerequest),\n          action: () => {\n            modifyRequest(activeRequest, 'decline');\n          },\n          svg: <XMarkIcon />,\n        }\n      );\n    } else if (\n      activeRequests &&\n      activeRequests.length > 0 &&\n      hasPermission(Permission.MANAGE_REQUESTS) &&\n      mediaType === 'tv'\n    ) {\n      buttons.push(\n        {\n          id: 'approve-request-batch',\n          text: intl.formatMessage(messages.approverequests, {\n            requestCount: activeRequests.length,\n          }),\n          action: () => {\n            modifyRequests(activeRequests, 'approve');\n          },\n          svg: <CheckIcon />,\n        },\n        {\n          id: 'decline-request-batch',\n          text: intl.formatMessage(messages.declinerequests, {\n            requestCount: activeRequests.length,\n          }),\n          action: () => {\n            modifyRequests(activeRequests, 'decline');\n          },\n          svg: <XMarkIcon />,\n        }\n      );\n    }\n\n    if (\n      active4kRequest &&\n      (active4kRequest.requestedBy.id === user?.id ||\n        (active4kRequests?.length === 1 &&\n          hasPermission(Permission.MANAGE_REQUESTS)))\n    ) {\n      buttons.push({\n        id: 'active-4k-request',\n        text: intl.formatMessage(messages.viewrequest4k),\n        action: () => {\n          setEditRequest(true);\n          setShowRequest4kModal(true);\n        },\n        svg: <InformationCircleIcon />,\n      });\n    }\n\n    if (\n      active4kRequest &&\n      hasPermission(Permission.MANAGE_REQUESTS) &&\n      mediaType === 'movie'\n    ) {\n      buttons.push(\n        {\n          id: 'approve-4k-request',\n          text: intl.formatMessage(messages.approverequest4k),\n          action: () => {\n            modifyRequest(active4kRequest, 'approve');\n          },\n          svg: <CheckIcon />,\n        },\n        {\n          id: 'decline-4k-request',\n          text: intl.formatMessage(messages.declinerequest4k),\n          action: () => {\n            modifyRequest(active4kRequest, 'decline');\n          },\n          svg: <XMarkIcon />,\n        }\n      );\n    } else if (\n      active4kRequests &&\n      active4kRequests.length > 0 &&\n      hasPermission(Permission.MANAGE_REQUESTS) &&\n      mediaType === 'tv'\n    ) {\n      buttons.push(\n        {\n          id: 'approve-4k-request-batch',\n          text: intl.formatMessage(messages.approve4krequests, {\n            requestCount: active4kRequests.length,\n          }),\n          action: () => {\n            modifyRequests(active4kRequests, 'approve');\n          },\n          svg: <CheckIcon />,\n        },\n        {\n          id: 'decline-4k-request-batch',\n          text: intl.formatMessage(messages.decline4krequests, {\n            requestCount: active4kRequests.length,\n          }),\n          action: () => {\n            modifyRequests(active4kRequests, 'decline');\n          },\n          svg: <XMarkIcon />,\n        }\n      );\n    }\n  }\n\n  // Standard request button\n  if (\n    (!media ||\n      media.status === MediaStatus.UNKNOWN ||\n      (media.status === MediaStatus.DELETED && !activeRequest)) &&\n    hasPermission(\n      [\n        Permission.REQUEST,\n        mediaType === 'movie'\n          ? Permission.REQUEST_MOVIE\n          : Permission.REQUEST_TV,\n      ],\n      { type: 'or' }\n    )\n  ) {\n    buttons.push({\n      id: 'request',\n      text: intl.formatMessage(globalMessages.request),\n      action: () => {\n        setEditRequest(false);\n        setShowRequestModal(true);\n      },\n      svg: <ArrowDownTrayIcon />,\n    });\n  } else if (\n    mediaType === 'tv' &&\n    (!activeRequest || activeRequest.requestedBy.id !== user?.id) &&\n    hasPermission([Permission.REQUEST, Permission.REQUEST_TV], {\n      type: 'or',\n    }) &&\n    media &&\n    media.status !== MediaStatus.BLOCKLISTED &&\n    !isShowComplete\n  ) {\n    buttons.push({\n      id: 'request-more',\n      text: intl.formatMessage(messages.requestmore),\n      action: () => {\n        setEditRequest(false);\n        setShowRequestModal(true);\n      },\n      svg: <ArrowDownTrayIcon />,\n    });\n  }\n\n  // 4K request button\n  if (\n    (!media ||\n      media.status4k === MediaStatus.UNKNOWN ||\n      (media.status4k === MediaStatus.DELETED && !active4kRequest)) &&\n    hasPermission(\n      [\n        Permission.REQUEST_4K,\n        mediaType === 'movie'\n          ? Permission.REQUEST_4K_MOVIE\n          : Permission.REQUEST_4K_TV,\n      ],\n      { type: 'or' }\n    ) &&\n    ((settings.currentSettings.movie4kEnabled && mediaType === 'movie') ||\n      (settings.currentSettings.series4kEnabled && mediaType === 'tv'))\n  ) {\n    buttons.push({\n      id: 'request4k',\n      text: intl.formatMessage(globalMessages.request4k),\n      action: () => {\n        setEditRequest(false);\n        setShowRequest4kModal(true);\n      },\n      svg: <ArrowDownTrayIcon />,\n    });\n  } else if (\n    mediaType === 'tv' &&\n    (!active4kRequest || active4kRequest.requestedBy.id !== user?.id) &&\n    hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_TV], {\n      type: 'or',\n    }) &&\n    media &&\n    media.status4k !== MediaStatus.BLOCKLISTED &&\n    !is4kShowComplete &&\n    settings.currentSettings.series4kEnabled\n  ) {\n    buttons.push({\n      id: 'request-more-4k',\n      text: intl.formatMessage(messages.requestmore4k),\n      action: () => {\n        setEditRequest(false);\n        setShowRequest4kModal(true);\n      },\n      svg: <ArrowDownTrayIcon />,\n    });\n  }\n\n  const [buttonOne, ...others] = buttons;\n\n  if (!buttonOne) {\n    return null;\n  }\n\n  return (\n    <>\n      <RequestModal\n        tmdbId={tmdbId}\n        show={showRequestModal}\n        type={mediaType}\n        editRequest={editRequest ? activeRequest : undefined}\n        onComplete={() => {\n          onUpdate();\n          setShowRequestModal(false);\n        }}\n        onCancel={() => setShowRequestModal(false)}\n      />\n      <RequestModal\n        tmdbId={tmdbId}\n        show={showRequest4kModal}\n        type={mediaType}\n        editRequest={editRequest ? active4kRequest : undefined}\n        is4k\n        onComplete={() => {\n          onUpdate();\n          setShowRequest4kModal(false);\n        }}\n        onCancel={() => setShowRequest4kModal(false)}\n      />\n      <ButtonWithDropdown\n        text={\n          <>\n            {buttonOne.svg}\n            <span>{buttonOne.text}</span>\n          </>\n        }\n        onClick={buttonOne.action}\n        className=\"ml-2\"\n      >\n        {others && others.length > 0\n          ? others.map((button) => (\n              <ButtonWithDropdown.Item\n                onClick={button.action}\n                key={`request-option-${button.id}`}\n              >\n                {button.svg}\n                <span>{button.text}</span>\n              </ButtonWithDropdown.Item>\n            ))\n          : null}\n      </ButtonWithDropdown>\n    </>\n  );\n};\n\nexport default RequestButton;\n"
  },
  {
    "path": "src/components/RequestCard/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport RequestModal from '@app/components/RequestModal';\nimport StatusBadge from '@app/components/StatusBadge';\nimport useDeepLinks from '@app/hooks/useDeepLinks';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { refreshIntervalHelper } from '@app/utils/refreshIntervalHelper';\nimport { withProperties } from '@app/utils/typeHelpers';\nimport {\n  ArrowPathIcon,\n  CheckIcon,\n  PencilIcon,\n  TrashIcon,\n  XMarkIcon,\n} from '@heroicons/react/24/solid';\nimport { MediaRequestStatus, MediaStatus } from '@server/constants/media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport type { NonFunctionProperties } from '@server/interfaces/api/common';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport axios from 'axios';\nimport Link from 'next/link';\nimport { useEffect, useState } from 'react';\nimport { useInView } from 'react-intersection-observer';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\n\nconst messages = defineMessages('components.RequestCard', {\n  seasons: '{seasonCount, plural, one {Season} other {Seasons}}',\n  failedretry: 'Something went wrong while retrying the request.',\n  mediaerror: '{mediaType} Not Found',\n  tmdbid: 'TMDB ID',\n  tvdbid: 'TheTVDB ID',\n  approverequest: 'Approve Request',\n  declinerequest: 'Decline Request',\n  editrequest: 'Edit Request',\n  cancelrequest: 'Cancel Request',\n  deleterequest: 'Delete Request',\n  unknowntitle: 'Unknown Title',\n});\n\nconst isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {\n  return (movie as MovieDetails).title !== undefined;\n};\n\nconst RequestCardPlaceholder = () => {\n  return (\n    <div className=\"relative w-72 animate-pulse rounded-xl bg-gray-700 p-4 sm:w-96\">\n      <div className=\"w-20 sm:w-28\">\n        <div className=\"w-full\" style={{ paddingBottom: '150%' }} />\n      </div>\n    </div>\n  );\n};\n\ninterface RequestCardErrorProps {\n  requestData?: NonFunctionProperties<MediaRequest>;\n}\n\nconst RequestCardError = ({ requestData }: RequestCardErrorProps) => {\n  const { hasPermission } = useUser();\n  const intl = useIntl();\n\n  const { mediaUrl: plexUrl, mediaUrl4k: plexUrl4k } = useDeepLinks({\n    mediaUrl: requestData?.media?.mediaUrl,\n    mediaUrl4k: requestData?.media?.mediaUrl4k,\n    iOSPlexUrl: requestData?.media?.iOSPlexUrl,\n    iOSPlexUrl4k: requestData?.media?.iOSPlexUrl4k,\n  });\n\n  const deleteRequest = async () => {\n    await axios.delete(`/api/v1/media/${requestData?.media.id}`);\n    mutate('/api/v1/media?filter=allavailable&take=20&sort=mediaAdded');\n    mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');\n    mutate('/api/v1/request/count');\n  };\n\n  return (\n    <div\n      className=\"relative flex w-72 overflow-hidden rounded-xl bg-gray-800 p-4 text-gray-400 shadow ring-1 ring-red-500 sm:w-96\"\n      data-testid=\"request-card\"\n    >\n      <div className=\"w-20 sm:w-28\">\n        <div className=\"w-full\" style={{ paddingBottom: '150%' }}>\n          <div className=\"absolute inset-0 z-10 flex min-w-0 flex-1 flex-col p-4\">\n            <div\n              className=\"whitespace-normal text-base font-bold text-white sm:text-lg\"\n              data-testid=\"request-card-title\"\n            >\n              {intl.formatMessage(messages.mediaerror, {\n                mediaType: intl.formatMessage(\n                  requestData?.type\n                    ? requestData?.type === 'movie'\n                      ? globalMessages.movie\n                      : globalMessages.tvshow\n                    : globalMessages.request\n                ),\n              })}\n            </div>\n            {requestData && (\n              <>\n                {hasPermission(\n                  [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n                  { type: 'or' }\n                ) && (\n                  <div className=\"card-field !hidden sm:!block\">\n                    <Link\n                      href={`/users/${requestData.requestedBy.id}`}\n                      className=\"group flex items-center\"\n                    >\n                      <span className=\"avatar-sm\">\n                        <CachedImage\n                          type=\"avatar\"\n                          src={requestData.requestedBy.avatar}\n                          alt=\"\"\n                          className=\"avatar-sm object-cover\"\n                          width={20}\n                          height={20}\n                        />\n                      </span>\n                      <span className=\"truncate group-hover:underline\">\n                        {requestData.requestedBy.displayName}\n                      </span>\n                    </Link>\n                  </div>\n                )}\n                <div className=\"mt-2 flex items-center text-sm sm:mt-1\">\n                  <span className=\"mr-2 hidden font-bold sm:block\">\n                    {intl.formatMessage(globalMessages.status)}\n                  </span>\n                  {requestData.status === MediaRequestStatus.DECLINED ||\n                  requestData.status === MediaRequestStatus.FAILED ? (\n                    <Badge badgeType=\"danger\">\n                      {requestData.status === MediaRequestStatus.DECLINED\n                        ? intl.formatMessage(globalMessages.declined)\n                        : intl.formatMessage(globalMessages.failed)}\n                    </Badge>\n                  ) : (\n                    <StatusBadge\n                      status={\n                        requestData.media[\n                          requestData.is4k ? 'status4k' : 'status'\n                        ]\n                      }\n                      downloadItem={\n                        requestData.media[\n                          requestData.is4k\n                            ? 'downloadStatus4k'\n                            : 'downloadStatus'\n                        ]\n                      }\n                      title={intl.formatMessage(messages.unknowntitle)}\n                      inProgress={\n                        (\n                          requestData.media[\n                            requestData.is4k\n                              ? 'downloadStatus4k'\n                              : 'downloadStatus'\n                          ] ?? []\n                        ).length > 0\n                      }\n                      is4k={requestData.is4k}\n                      mediaType={requestData.type}\n                      plexUrl={requestData.is4k ? plexUrl4k : plexUrl}\n                      serviceUrl={\n                        requestData.is4k\n                          ? requestData.media.serviceUrl4k\n                          : requestData.media.serviceUrl\n                      }\n                    />\n                  )}\n                </div>\n              </>\n            )}\n            <div className=\"flex flex-1 items-end space-x-2\">\n              {hasPermission(Permission.MANAGE_REQUESTS) &&\n                requestData?.media.id && (\n                  <>\n                    <Button\n                      buttonType=\"danger\"\n                      buttonSize=\"sm\"\n                      className=\"mt-4 hidden sm:block\"\n                      onClick={() => deleteRequest()}\n                    >\n                      <TrashIcon />\n                      <span>{intl.formatMessage(globalMessages.delete)}</span>\n                    </Button>\n                    <Tooltip\n                      content={intl.formatMessage(messages.deleterequest)}\n                    >\n                      <Button\n                        buttonType=\"danger\"\n                        buttonSize=\"sm\"\n                        className=\"mt-4 sm:hidden\"\n                        onClick={() => deleteRequest()}\n                      >\n                        <TrashIcon />\n                      </Button>\n                    </Tooltip>\n                  </>\n                )}\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n};\n\ninterface RequestCardProps {\n  request: NonFunctionProperties<MediaRequest>;\n  onTitleData?: (requestId: number, title: MovieDetails | TvDetails) => void;\n}\n\nconst RequestCard = ({ request, onTitleData }: RequestCardProps) => {\n  const { ref, inView } = useInView({\n    triggerOnce: true,\n  });\n  const intl = useIntl();\n  const { user, hasPermission } = useUser();\n  const { addToast } = useToasts();\n  const [isRetrying, setRetrying] = useState(false);\n  const [showEditModal, setShowEditModal] = useState(false);\n  const url =\n    request.type === 'movie'\n      ? `/api/v1/movie/${request.media.tmdbId}`\n      : `/api/v1/tv/${request.media.tmdbId}`;\n\n  const { data: title, error } = useSWR<MovieDetails | TvDetails>(\n    inView ? `${url}` : null\n  );\n  const {\n    data: requestData,\n    error: requestError,\n    mutate: revalidate,\n  } = useSWR<NonFunctionProperties<MediaRequest>>(\n    `/api/v1/request/${request.id}`,\n    {\n      fallbackData: request,\n      refreshInterval: refreshIntervalHelper(\n        {\n          downloadStatus: request.media.downloadStatus,\n          downloadStatus4k: request.media.downloadStatus4k,\n        },\n        15000\n      ),\n    }\n  );\n\n  const { mediaUrl: plexUrl, mediaUrl4k: plexUrl4k } = useDeepLinks({\n    mediaUrl: requestData?.media?.mediaUrl,\n    mediaUrl4k: requestData?.media?.mediaUrl4k,\n    iOSPlexUrl: requestData?.media?.iOSPlexUrl,\n    iOSPlexUrl4k: requestData?.media?.iOSPlexUrl4k,\n  });\n\n  const modifyRequest = async (type: 'approve' | 'decline') => {\n    const response = await axios.post(`/api/v1/request/${request.id}/${type}`);\n\n    if (response) {\n      revalidate();\n      mutate('/api/v1/request/count');\n    }\n  };\n\n  const deleteRequest = async () => {\n    await axios.delete(`/api/v1/request/${request.id}`);\n    mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');\n    mutate('/api/v1/request/count');\n  };\n\n  const retryRequest = async () => {\n    setRetrying(true);\n\n    try {\n      const response = await axios.post(`/api/v1/request/${request.id}/retry`);\n\n      if (response) {\n        revalidate();\n      }\n    } catch {\n      addToast(intl.formatMessage(messages.failedretry), {\n        autoDismiss: true,\n        appearance: 'error',\n      });\n    } finally {\n      setRetrying(false);\n    }\n  };\n\n  useEffect(() => {\n    if (title && onTitleData) {\n      onTitleData(request.id, title);\n    }\n  }, [title, onTitleData, request]);\n\n  if (!title && !error) {\n    return (\n      <div ref={ref}>\n        <RequestCardPlaceholder />\n      </div>\n    );\n  }\n\n  if (!requestData && !requestError) {\n    return <RequestCardError />;\n  }\n\n  if (!title || !requestData) {\n    return <RequestCardError requestData={requestData} />;\n  }\n\n  return (\n    <>\n      <RequestModal\n        show={showEditModal}\n        tmdbId={request.media.tmdbId}\n        type={request.type}\n        is4k={request.is4k}\n        editRequest={request}\n        onCancel={() => setShowEditModal(false)}\n        onComplete={() => {\n          revalidate();\n          setShowEditModal(false);\n        }}\n      />\n      <div\n        className=\"relative flex w-72 overflow-hidden rounded-xl bg-gray-800 bg-cover bg-center p-4 text-gray-400 shadow ring-1 ring-gray-700 sm:w-96\"\n        data-testid=\"request-card\"\n      >\n        {title.backdropPath && (\n          <div className=\"absolute inset-0 z-0\">\n            <CachedImage\n              type=\"tmdb\"\n              alt=\"\"\n              src={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${title.backdropPath}`}\n              style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n              fill\n            />\n            <div\n              className=\"absolute inset-0\"\n              style={{\n                backgroundImage:\n                  'linear-gradient(135deg, rgba(17, 24, 39, 0.47) 0%, rgba(17, 24, 39, 1) 75%)',\n              }}\n            />\n          </div>\n        )}\n        <div\n          className=\"relative z-10 flex min-w-0 flex-1 flex-col pr-4\"\n          data-testid=\"request-card-title\"\n        >\n          <div className=\"hidden text-xs font-medium text-white sm:flex\">\n            {(isMovie(title) ? title.releaseDate : title.firstAirDate)?.slice(\n              0,\n              4\n            )}\n          </div>\n          <Link\n            href={\n              request.type === 'movie'\n                ? `/movie/${requestData.media.tmdbId}`\n                : `/tv/${requestData.media.tmdbId}`\n            }\n            className=\"overflow-hidden overflow-ellipsis whitespace-nowrap text-base font-bold text-white hover:underline sm:text-lg\"\n          >\n            {isMovie(title) ? title.title : title.name}\n          </Link>\n          {hasPermission(\n            [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n            { type: 'or' }\n          ) && (\n            <div className=\"card-field\">\n              <Link\n                href={`/users/${requestData.requestedBy.id}`}\n                className=\"group flex items-center\"\n              >\n                <span className=\"avatar-sm\">\n                  <CachedImage\n                    type=\"avatar\"\n                    src={requestData.requestedBy.avatar}\n                    alt=\"\"\n                    className=\"avatar-sm object-cover\"\n                    width={20}\n                    height={20}\n                  />\n                </span>\n                <span className=\"truncate font-semibold group-hover:text-white group-hover:underline\">\n                  {requestData.requestedBy.displayName}\n                </span>\n              </Link>\n            </div>\n          )}\n          {!isMovie(title) && request.seasons.length > 0 && (\n            <div className=\"my-0.5 hidden items-center text-sm sm:my-1 sm:flex\">\n              <span className=\"mr-2 font-bold\">\n                {intl.formatMessage(messages.seasons, {\n                  seasonCount: request.seasons.length,\n                })}\n              </span>\n              <div className=\"hide-scrollbar overflow-x-scroll\">\n                {request.seasons.map((season) => (\n                  <span key={`season-${season.id}`} className=\"mr-2\">\n                    <Badge>\n                      {season.seasonNumber === 0\n                        ? intl.formatMessage(globalMessages.specials)\n                        : season.seasonNumber}\n                    </Badge>\n                  </span>\n                ))}\n              </div>\n            </div>\n          )}\n          <div className=\"mt-2 flex items-center text-sm sm:mt-1\">\n            <span className=\"mr-2 hidden font-bold sm:block\">\n              {intl.formatMessage(globalMessages.status)}\n            </span>\n            {requestData.status === MediaRequestStatus.DECLINED ? (\n              <Badge badgeType=\"danger\">\n                {intl.formatMessage(globalMessages.declined)}\n              </Badge>\n            ) : requestData.status === MediaRequestStatus.FAILED ? (\n              <Badge\n                badgeType=\"danger\"\n                href={`/${requestData.type}/${requestData.media.tmdbId}?manage=1`}\n              >\n                {intl.formatMessage(globalMessages.failed)}\n              </Badge>\n            ) : requestData.status === MediaRequestStatus.PENDING &&\n              requestData.media[requestData.is4k ? 'status4k' : 'status'] ===\n                MediaStatus.DELETED ? (\n              <Badge\n                badgeType=\"warning\"\n                href={`/${requestData.type}/${requestData.media.tmdbId}?manage=1`}\n              >\n                {intl.formatMessage(globalMessages.pending)}\n              </Badge>\n            ) : (\n              <StatusBadge\n                status={\n                  requestData.media[requestData.is4k ? 'status4k' : 'status']\n                }\n                downloadItem={\n                  requestData.media[\n                    requestData.is4k ? 'downloadStatus4k' : 'downloadStatus'\n                  ]\n                }\n                title={isMovie(title) ? title.title : title.name}\n                inProgress={\n                  (\n                    requestData.media[\n                      requestData.is4k ? 'downloadStatus4k' : 'downloadStatus'\n                    ] ?? []\n                  ).length > 0\n                }\n                is4k={requestData.is4k}\n                tmdbId={requestData.media.tmdbId}\n                mediaType={requestData.type}\n                plexUrl={requestData.is4k ? plexUrl4k : plexUrl}\n                serviceUrl={\n                  requestData.is4k\n                    ? requestData.media.serviceUrl4k\n                    : requestData.media.serviceUrl\n                }\n              />\n            )}\n          </div>\n          <div className=\"flex flex-1 items-end space-x-2\">\n            {requestData.status === MediaRequestStatus.FAILED &&\n              hasPermission(Permission.MANAGE_REQUESTS) && (\n                <Button\n                  buttonType=\"primary\"\n                  buttonSize=\"sm\"\n                  disabled={isRetrying}\n                  onClick={() => retryRequest()}\n                >\n                  <ArrowPathIcon\n                    className={isRetrying ? 'animate-spin' : ''}\n                    style={{ marginRight: '0', animationDirection: 'reverse' }}\n                  />\n                  <span className=\"ml-1.5 hidden sm:block\">\n                    {intl.formatMessage(globalMessages.retry)}\n                  </span>\n                </Button>\n              )}\n            {requestData.status === MediaRequestStatus.PENDING &&\n              hasPermission(Permission.MANAGE_REQUESTS) && (\n                <>\n                  <div>\n                    <Button\n                      buttonType=\"success\"\n                      buttonSize=\"sm\"\n                      className=\"hidden sm:block\"\n                      onClick={() => modifyRequest('approve')}\n                    >\n                      <CheckIcon />\n                      <span>{intl.formatMessage(globalMessages.approve)}</span>\n                    </Button>\n                    <Tooltip\n                      content={intl.formatMessage(messages.approverequest)}\n                    >\n                      <Button\n                        buttonType=\"success\"\n                        buttonSize=\"sm\"\n                        className=\"sm:hidden\"\n                        onClick={() => modifyRequest('approve')}\n                      >\n                        <CheckIcon />\n                      </Button>\n                    </Tooltip>\n                  </div>\n                  <div>\n                    <Button\n                      buttonType=\"danger\"\n                      buttonSize=\"sm\"\n                      className=\"hidden sm:block\"\n                      onClick={() => modifyRequest('decline')}\n                    >\n                      <XMarkIcon />\n                      <span>{intl.formatMessage(globalMessages.decline)}</span>\n                    </Button>\n                    <Tooltip\n                      content={intl.formatMessage(messages.declinerequest)}\n                    >\n                      <Button\n                        buttonType=\"danger\"\n                        buttonSize=\"sm\"\n                        className=\"sm:hidden\"\n                        onClick={() => modifyRequest('decline')}\n                      >\n                        <XMarkIcon />\n                      </Button>\n                    </Tooltip>\n                  </div>\n                </>\n              )}\n            {requestData.status === MediaRequestStatus.PENDING &&\n              !hasPermission(Permission.MANAGE_REQUESTS) &&\n              requestData.requestedBy.id === user?.id &&\n              (requestData.type === 'tv' ||\n                hasPermission(Permission.REQUEST_ADVANCED)) && (\n                <div>\n                  {!hasPermission(Permission.MANAGE_REQUESTS) && (\n                    <Button\n                      buttonType=\"primary\"\n                      buttonSize=\"sm\"\n                      className=\"hidden sm:block\"\n                      onClick={() => setShowEditModal(true)}\n                    >\n                      <PencilIcon />\n                      <span>{intl.formatMessage(globalMessages.edit)}</span>\n                    </Button>\n                  )}\n                  <Tooltip content={intl.formatMessage(messages.editrequest)}>\n                    <Button\n                      buttonType=\"primary\"\n                      buttonSize=\"sm\"\n                      className=\"sm:hidden\"\n                      onClick={() => setShowEditModal(true)}\n                    >\n                      <PencilIcon />\n                    </Button>\n                  </Tooltip>\n                </div>\n              )}\n            {requestData.status === MediaRequestStatus.PENDING &&\n              !hasPermission(Permission.MANAGE_REQUESTS) &&\n              requestData.requestedBy.id === user?.id && (\n                <div>\n                  <Button\n                    buttonType=\"danger\"\n                    buttonSize=\"sm\"\n                    className=\"hidden sm:block\"\n                    onClick={() => deleteRequest()}\n                  >\n                    <XMarkIcon />\n                    <span>{intl.formatMessage(globalMessages.cancel)}</span>\n                  </Button>\n                  <Tooltip content={intl.formatMessage(messages.cancelrequest)}>\n                    <Button\n                      buttonType=\"danger\"\n                      buttonSize=\"sm\"\n                      className=\"sm:hidden\"\n                      onClick={() => deleteRequest()}\n                    >\n                      <XMarkIcon />\n                    </Button>\n                  </Tooltip>\n                </div>\n              )}\n          </div>\n        </div>\n        <Link\n          href={\n            request.type === 'movie'\n              ? `/movie/${requestData.media.tmdbId}`\n              : `/tv/${requestData.media.tmdbId}`\n          }\n          className=\"w-20 flex-shrink-0 scale-100 transform-gpu cursor-pointer overflow-hidden rounded-md shadow-sm transition duration-300 hover:scale-105 hover:shadow-md sm:w-28\"\n        >\n          <CachedImage\n            type=\"tmdb\"\n            src={\n              title.posterPath\n                ? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`\n                : '/images/seerr_poster_not_found.png'\n            }\n            alt=\"\"\n            sizes=\"100vw\"\n            style={{ width: '100%', height: 'auto' }}\n            width={600}\n            height={900}\n          />\n        </Link>\n      </div>\n    </>\n  );\n};\n\nexport default withProperties(RequestCard, {\n  Placeholder: RequestCardPlaceholder,\n});\n"
  },
  {
    "path": "src/components/RequestList/RequestItem/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport ConfirmButton from '@app/components/Common/ConfirmButton';\nimport RequestModal from '@app/components/RequestModal';\nimport StatusBadge from '@app/components/StatusBadge';\nimport useDeepLinks from '@app/hooks/useDeepLinks';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { refreshIntervalHelper } from '@app/utils/refreshIntervalHelper';\nimport {\n  ArrowPathIcon,\n  CheckIcon,\n  PencilIcon,\n  TrashIcon,\n  XMarkIcon,\n} from '@heroicons/react/24/solid';\nimport { MediaRequestStatus, MediaStatus } from '@server/constants/media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport type { NonFunctionProperties } from '@server/interfaces/api/common';\nimport type { RequestResultsResponse } from '@server/interfaces/api/requestInterfaces';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport axios from 'axios';\nimport Link from 'next/link';\nimport { useState } from 'react';\nimport { useInView } from 'react-intersection-observer';\nimport { FormattedRelativeTime, useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\n\nconst messages = defineMessages('components.RequestList.RequestItem', {\n  seasons: '{seasonCount, plural, one {Season} other {Seasons}}',\n  failedretry: 'Something went wrong while retrying the request.',\n  requested: 'Requested',\n  requesteddate: 'Requested',\n  modified: 'Modified',\n  modifieduserdate: '{date} by {user}',\n  mediaerror: '{mediaType} Not Found',\n  editrequest: 'Edit Request',\n  deleterequest: 'Delete Request',\n  cancelRequest: 'Cancel Request',\n  tmdbid: 'TMDB ID',\n  tvdbid: 'TheTVDB ID',\n  unknowntitle: 'Unknown Title',\n  removearr: 'Remove from {arr}',\n  profileName: 'Profile',\n});\n\nconst isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {\n  return (movie as MovieDetails).title !== undefined;\n};\n\ninterface RequestItemErrorProps {\n  requestData?: NonFunctionProperties<MediaRequest>;\n  revalidateList: () => void;\n}\n\nconst RequestItemError = ({\n  requestData,\n  revalidateList,\n}: RequestItemErrorProps) => {\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n\n  const deleteRequest = async () => {\n    await axios.delete(`/api/v1/media/${requestData?.media.id}`);\n    revalidateList();\n    mutate('/api/v1/request/count');\n  };\n\n  const { mediaUrl: plexUrl, mediaUrl4k: plexUrl4k } = useDeepLinks({\n    mediaUrl: requestData?.media?.mediaUrl,\n    mediaUrl4k: requestData?.media?.mediaUrl4k,\n    iOSPlexUrl: requestData?.media?.iOSPlexUrl,\n    iOSPlexUrl4k: requestData?.media?.iOSPlexUrl4k,\n  });\n\n  return (\n    <div className=\"flex h-64 w-full flex-col justify-center rounded-xl bg-gray-800 py-4 text-gray-400 shadow-md ring-1 ring-red-500 xl:h-28 xl:flex-row\">\n      <div className=\"flex w-full flex-col justify-between overflow-hidden sm:flex-row\">\n        <div className=\"flex w-full flex-col justify-center overflow-hidden pl-4 pr-4 sm:pr-0 xl:w-7/12 2xl:w-2/3\">\n          <div className=\"flex text-lg font-bold text-white xl:text-xl\">\n            {intl.formatMessage(messages.mediaerror, {\n              mediaType: intl.formatMessage(\n                requestData?.type\n                  ? requestData?.type === 'movie'\n                    ? globalMessages.movie\n                    : globalMessages.tvshow\n                  : globalMessages.request\n              ),\n            })}\n          </div>\n          {requestData && hasPermission(Permission.MANAGE_REQUESTS) && (\n            <>\n              <div className=\"card-field\">\n                <span className=\"card-field-name\">\n                  {intl.formatMessage(messages.tmdbid)}\n                </span>\n                <span className=\"flex truncate text-sm text-gray-300\">\n                  {requestData.media.tmdbId}\n                </span>\n              </div>\n              {requestData.media.tvdbId && (\n                <div className=\"card-field\">\n                  <span className=\"card-field-name\">\n                    {intl.formatMessage(messages.tvdbid)}\n                  </span>\n                  <span className=\"flex truncate text-sm text-gray-300\">\n                    {requestData?.media.tvdbId}\n                  </span>\n                </div>\n              )}\n            </>\n          )}\n        </div>\n        <div className=\"ml-4 mt-4 flex w-full flex-col justify-center overflow-hidden pr-4 text-sm sm:ml-2 sm:mt-0 xl:flex-1 xl:pr-0\">\n          {requestData && (\n            <>\n              <div className=\"card-field\">\n                <span className=\"card-field-name\">\n                  {intl.formatMessage(globalMessages.status)}\n                </span>\n                {requestData.status === MediaRequestStatus.DECLINED ||\n                requestData.status === MediaRequestStatus.FAILED ? (\n                  <Badge badgeType=\"danger\">\n                    {requestData.status === MediaRequestStatus.DECLINED\n                      ? intl.formatMessage(globalMessages.declined)\n                      : intl.formatMessage(globalMessages.failed)}\n                  </Badge>\n                ) : (\n                  <StatusBadge\n                    status={\n                      requestData.media[\n                        requestData.is4k ? 'status4k' : 'status'\n                      ]\n                    }\n                    downloadItem={\n                      requestData.media[\n                        requestData.is4k ? 'downloadStatus4k' : 'downloadStatus'\n                      ]\n                    }\n                    title={intl.formatMessage(messages.unknowntitle)}\n                    inProgress={\n                      (\n                        requestData.media[\n                          requestData.is4k\n                            ? 'downloadStatus4k'\n                            : 'downloadStatus'\n                        ] ?? []\n                      ).length > 0\n                    }\n                    is4k={requestData.is4k}\n                    mediaType={requestData.type}\n                    plexUrl={requestData.is4k ? plexUrl4k : plexUrl}\n                    serviceUrl={\n                      requestData.is4k\n                        ? requestData.media.serviceUrl4k\n                        : requestData.media.serviceUrl\n                    }\n                  />\n                )}\n              </div>\n              <div className=\"card-field\">\n                {hasPermission(\n                  [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n                  { type: 'or' }\n                ) ? (\n                  <>\n                    <span className=\"card-field-name\">\n                      {intl.formatMessage(messages.requested)}\n                    </span>\n                    <span className=\"flex truncate text-sm text-gray-300\">\n                      {intl.formatMessage(messages.modifieduserdate, {\n                        date: (\n                          <FormattedRelativeTime\n                            value={Math.floor(\n                              (new Date(requestData.createdAt).getTime() -\n                                Date.now()) /\n                                1000\n                            )}\n                            updateIntervalInSeconds={1}\n                            numeric=\"auto\"\n                          />\n                        ),\n                        user: (\n                          <Link\n                            href={`/users/${requestData.requestedBy.id}`}\n                            className=\"group flex items-center truncate\"\n                          >\n                            <span className=\"avatar-sm ml-1.5\">\n                              <CachedImage\n                                type=\"avatar\"\n                                src={requestData.requestedBy.avatar}\n                                alt=\"\"\n                                className=\"avatar-sm object-cover\"\n                                width={20}\n                                height={20}\n                              />\n                            </span>\n                            <span className=\"truncate text-sm group-hover:underline\">\n                              {requestData.requestedBy.displayName}\n                            </span>\n                          </Link>\n                        ),\n                      })}\n                    </span>\n                  </>\n                ) : (\n                  <>\n                    <span className=\"card-field-name\">\n                      {intl.formatMessage(messages.requesteddate)}\n                    </span>\n                    <span className=\"flex truncate text-sm text-gray-300\">\n                      <FormattedRelativeTime\n                        value={Math.floor(\n                          (new Date(requestData.createdAt).getTime() -\n                            Date.now()) /\n                            1000\n                        )}\n                        updateIntervalInSeconds={1}\n                        numeric=\"auto\"\n                      />\n                    </span>\n                  </>\n                )}\n              </div>\n              {requestData.modifiedBy && (\n                <div className=\"card-field\">\n                  <span className=\"card-field-name\">\n                    {intl.formatMessage(messages.modified)}\n                  </span>\n                  <span className=\"flex truncate text-sm text-gray-300\">\n                    {intl.formatMessage(messages.modifieduserdate, {\n                      date: (\n                        <FormattedRelativeTime\n                          value={Math.floor(\n                            (new Date(requestData.updatedAt).getTime() -\n                              Date.now()) /\n                              1000\n                          )}\n                          updateIntervalInSeconds={1}\n                          numeric=\"auto\"\n                        />\n                      ),\n                      user: (\n                        <Link\n                          href={`/users/${requestData.modifiedBy.id}`}\n                          className=\"group flex items-center truncate\"\n                        >\n                          <span className=\"avatar-sm ml-1.5\">\n                            <CachedImage\n                              type=\"avatar\"\n                              src={requestData.modifiedBy.avatar}\n                              alt=\"\"\n                              className=\"avatar-sm object-cover\"\n                              width={20}\n                              height={20}\n                            />\n                          </span>\n                          <span className=\"truncate text-sm group-hover:underline\">\n                            {requestData.modifiedBy.displayName}\n                          </span>\n                        </Link>\n                      ),\n                    })}\n                  </span>\n                </div>\n              )}\n            </>\n          )}\n        </div>\n      </div>\n      <div className=\"z-10 mt-4 flex w-full flex-col justify-center pl-4 pr-4 xl:mt-0 xl:w-96 xl:items-end xl:pl-0\">\n        {hasPermission(Permission.MANAGE_REQUESTS) && requestData?.media.id && (\n          <Button\n            className=\"w-full\"\n            buttonType=\"danger\"\n            onClick={() => deleteRequest()}\n          >\n            <TrashIcon />\n            <span>{intl.formatMessage(messages.deleterequest)}</span>\n          </Button>\n        )}\n      </div>\n    </div>\n  );\n};\n\ninterface RequestItemProps {\n  request: RequestResultsResponse['results'][number];\n  revalidateList: () => void;\n}\n\nconst RequestItem = ({ request, revalidateList }: RequestItemProps) => {\n  const { ref, inView } = useInView({\n    triggerOnce: true,\n  });\n  const { addToast } = useToasts();\n  const intl = useIntl();\n  const { user, hasPermission } = useUser();\n  const [showEditModal, setShowEditModal] = useState(false);\n  const url =\n    request.type === 'movie'\n      ? `/api/v1/movie/${request.media.tmdbId}`\n      : `/api/v1/tv/${request.media.tmdbId}`;\n  const { data: title, error } = useSWR<MovieDetails | TvDetails>(\n    inView ? url : null\n  );\n  const { data: requestData, mutate: revalidate } = useSWR<\n    NonFunctionProperties<MediaRequest>\n  >(`/api/v1/request/${request.id}`, {\n    fallbackData: request,\n    refreshInterval: refreshIntervalHelper(\n      {\n        downloadStatus: request.media.downloadStatus,\n        downloadStatus4k: request.media.downloadStatus4k,\n      },\n      15000\n    ),\n  });\n\n  const [isRetrying, setRetrying] = useState(false);\n\n  const modifyRequest = async (type: 'approve' | 'decline') => {\n    const response = await axios.post(`/api/v1/request/${request.id}/${type}`);\n\n    if (response) {\n      revalidate();\n      mutate('/api/v1/request/count');\n    }\n  };\n\n  const deleteRequest = async () => {\n    await axios.delete(`/api/v1/request/${request.id}`);\n\n    revalidateList();\n    mutate('/api/v1/request/count');\n  };\n\n  const deleteMediaFile = async () => {\n    if (request.media) {\n      await axios.delete(\n        `/api/v1/media/${request.media.id}/file?is4k=${request.is4k}`\n      );\n      await axios.delete(`/api/v1/media/${request.media.id}`);\n      revalidateList();\n    }\n  };\n\n  const retryRequest = async () => {\n    setRetrying(true);\n\n    try {\n      const result = await axios.post(`/api/v1/request/${request.id}/retry`);\n      revalidate(result.data);\n    } catch {\n      addToast(intl.formatMessage(messages.failedretry), {\n        autoDismiss: true,\n        appearance: 'error',\n      });\n    } finally {\n      setRetrying(false);\n    }\n  };\n\n  const { mediaUrl: plexUrl, mediaUrl4k: plexUrl4k } = useDeepLinks({\n    mediaUrl: requestData?.media?.mediaUrl,\n    mediaUrl4k: requestData?.media?.mediaUrl4k,\n    iOSPlexUrl: requestData?.media?.iOSPlexUrl,\n    iOSPlexUrl4k: requestData?.media?.iOSPlexUrl4k,\n  });\n\n  if (!title && !error) {\n    return (\n      <div\n        className=\"h-64 w-full animate-pulse rounded-xl bg-gray-800 xl:h-28\"\n        ref={ref}\n      />\n    );\n  }\n\n  if (!title || !requestData) {\n    return (\n      <RequestItemError\n        requestData={requestData}\n        revalidateList={revalidateList}\n      />\n    );\n  }\n\n  return (\n    <>\n      <RequestModal\n        show={showEditModal}\n        tmdbId={request.media.tmdbId}\n        type={request.type}\n        is4k={request.is4k}\n        editRequest={request}\n        onCancel={() => setShowEditModal(false)}\n        onComplete={() => {\n          revalidateList();\n          setShowEditModal(false);\n        }}\n      />\n      <div className=\"relative flex w-full flex-col justify-between overflow-hidden rounded-xl bg-gray-800 py-2 text-gray-400 shadow-md ring-1 ring-gray-700 xl:h-28 xl:flex-row\">\n        {title.backdropPath && (\n          <div className=\"absolute inset-0 z-0 w-full bg-cover bg-center xl:w-2/3\">\n            <CachedImage\n              type=\"tmdb\"\n              src={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${title.backdropPath}`}\n              alt=\"\"\n              style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n              fill\n            />\n            <div\n              className=\"absolute inset-0\"\n              style={{\n                backgroundImage:\n                  'linear-gradient(90deg, rgba(31, 41, 55, 0.47) 0%, rgba(31, 41, 55, 1) 100%)',\n              }}\n            />\n          </div>\n        )}\n        <div className=\"relative flex w-full flex-col justify-between overflow-hidden sm:flex-row\">\n          <div className=\"relative z-10 flex w-full items-center overflow-hidden pl-4 pr-4 sm:pr-0 xl:w-7/12 2xl:w-2/3\">\n            <Link\n              href={\n                requestData.type === 'movie'\n                  ? `/movie/${requestData.media.tmdbId}`\n                  : `/tv/${requestData.media.tmdbId}`\n              }\n              className=\"relative h-auto w-12 flex-shrink-0 scale-100 transform-gpu overflow-hidden rounded-md transition duration-300 hover:scale-105\"\n            >\n              <CachedImage\n                type=\"tmdb\"\n                src={\n                  title.posterPath\n                    ? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${title.posterPath}`\n                    : '/images/seerr_poster_not_found.png'\n                }\n                alt=\"\"\n                sizes=\"100vw\"\n                style={{ width: '100%', height: 'auto', objectFit: 'cover' }}\n                width={600}\n                height={900}\n              />\n            </Link>\n            <div className=\"flex flex-col justify-center overflow-hidden pl-2 xl:pl-4\">\n              <div className=\"pt-0.5 text-xs font-medium text-white sm:pt-1\">\n                {(isMovie(title)\n                  ? title.releaseDate\n                  : title.firstAirDate\n                )?.slice(0, 4)}\n              </div>\n              <Link\n                href={\n                  requestData.type === 'movie'\n                    ? `/movie/${requestData.media.tmdbId}`\n                    : `/tv/${requestData.media.tmdbId}`\n                }\n                className=\"mr-2 min-w-0 truncate text-lg font-bold text-white hover:underline xl:text-xl\"\n              >\n                {isMovie(title) ? title.title : title.name}\n              </Link>\n              {!isMovie(title) && request.seasons.length > 0 && (\n                <div className=\"card-field\">\n                  <span className=\"card-field-name\">\n                    {intl.formatMessage(messages.seasons, {\n                      seasonCount: request.seasons.length,\n                    })}\n                  </span>\n                  <div className=\"hide-scrollbar flex flex-nowrap overflow-x-scroll\">\n                    {request.seasons.map((season) => (\n                      <span key={`season-${season.id}`} className=\"mr-2\">\n                        <Badge>\n                          {season.seasonNumber === 0\n                            ? intl.formatMessage(globalMessages.specials)\n                            : season.seasonNumber}\n                        </Badge>\n                      </span>\n                    ))}\n                  </div>\n                </div>\n              )}\n            </div>\n          </div>\n          <div className=\"z-10 ml-4 mt-4 flex w-full flex-col justify-center gap-1 overflow-hidden pr-4 text-sm sm:ml-2 sm:mt-0 xl:flex-1 xl:pr-0\">\n            <div className=\"card-field\">\n              <span className=\"card-field-name\">\n                {intl.formatMessage(globalMessages.status)}\n              </span>\n              {requestData.status === MediaRequestStatus.DECLINED ? (\n                <Badge badgeType=\"danger\">\n                  {intl.formatMessage(globalMessages.declined)}\n                </Badge>\n              ) : requestData.status === MediaRequestStatus.FAILED ? (\n                <Badge\n                  badgeType=\"danger\"\n                  href={`/${requestData.type}/${requestData.media.tmdbId}?manage=1`}\n                >\n                  {intl.formatMessage(globalMessages.failed)}\n                </Badge>\n              ) : requestData.status === MediaRequestStatus.PENDING &&\n                requestData.media[requestData.is4k ? 'status4k' : 'status'] ===\n                  MediaStatus.DELETED ? (\n                <Badge\n                  badgeType=\"warning\"\n                  href={`/${requestData.type}/${requestData.media.tmdbId}?manage=1`}\n                >\n                  {intl.formatMessage(globalMessages.pending)}\n                </Badge>\n              ) : (\n                <StatusBadge\n                  status={\n                    requestData.media[requestData.is4k ? 'status4k' : 'status']\n                  }\n                  downloadItem={\n                    requestData.media[\n                      requestData.is4k ? 'downloadStatus4k' : 'downloadStatus'\n                    ]\n                  }\n                  title={isMovie(title) ? title.title : title.name}\n                  inProgress={\n                    (\n                      requestData.media[\n                        requestData.is4k ? 'downloadStatus4k' : 'downloadStatus'\n                      ] ?? []\n                    ).length > 0\n                  }\n                  is4k={requestData.is4k}\n                  tmdbId={requestData.media.tmdbId}\n                  mediaType={requestData.type}\n                  plexUrl={requestData.is4k ? plexUrl4k : plexUrl}\n                  serviceUrl={\n                    requestData.is4k\n                      ? requestData.media.serviceUrl4k\n                      : requestData.media.serviceUrl\n                  }\n                />\n              )}\n            </div>\n            <div className=\"card-field\">\n              {hasPermission(\n                [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n                { type: 'or' }\n              ) ? (\n                <>\n                  <span className=\"card-field-name\">\n                    {intl.formatMessage(messages.requested)}\n                  </span>\n                  <span className=\"flex truncate text-sm text-gray-300\">\n                    {intl.formatMessage(messages.modifieduserdate, {\n                      date: (\n                        <FormattedRelativeTime\n                          value={Math.floor(\n                            (new Date(requestData.createdAt).getTime() -\n                              Date.now()) /\n                              1000\n                          )}\n                          updateIntervalInSeconds={1}\n                          numeric=\"auto\"\n                        />\n                      ),\n                      user: (\n                        <Link\n                          href={`/users/${requestData.requestedBy.id}`}\n                          className=\"group flex items-center truncate\"\n                        >\n                          <span className=\"avatar-sm ml-1.5\">\n                            <CachedImage\n                              type=\"avatar\"\n                              src={requestData.requestedBy.avatar}\n                              alt=\"\"\n                              className=\"avatar-sm object-cover\"\n                              width={20}\n                              height={20}\n                            />\n                          </span>\n                          <span className=\"truncate text-sm font-semibold group-hover:text-white group-hover:underline\">\n                            {requestData.requestedBy.displayName}\n                          </span>\n                        </Link>\n                      ),\n                    })}\n                  </span>\n                </>\n              ) : (\n                <>\n                  <span className=\"card-field-name\">\n                    {intl.formatMessage(messages.requesteddate)}\n                  </span>\n                  <span className=\"flex truncate text-sm text-gray-300\">\n                    <FormattedRelativeTime\n                      value={Math.floor(\n                        (new Date(requestData.createdAt).getTime() -\n                          Date.now()) /\n                          1000\n                      )}\n                      updateIntervalInSeconds={1}\n                      numeric=\"auto\"\n                    />\n                  </span>\n                </>\n              )}\n            </div>\n            {requestData.modifiedBy && (\n              <div className=\"card-field\">\n                <span className=\"card-field-name\">\n                  {intl.formatMessage(messages.modified)}\n                </span>\n                <span className=\"flex truncate text-sm text-gray-300\">\n                  {intl.formatMessage(messages.modifieduserdate, {\n                    date: (\n                      <FormattedRelativeTime\n                        value={Math.floor(\n                          (new Date(requestData.updatedAt).getTime() -\n                            Date.now()) /\n                            1000\n                        )}\n                        updateIntervalInSeconds={1}\n                        numeric=\"auto\"\n                      />\n                    ),\n                    user: (\n                      <Link\n                        href={`/users/${requestData.modifiedBy.id}`}\n                        className=\"group flex items-center truncate\"\n                      >\n                        <span className=\"avatar-sm ml-1.5\">\n                          <CachedImage\n                            type=\"avatar\"\n                            src={requestData.modifiedBy.avatar}\n                            alt=\"\"\n                            className=\"avatar-sm object-cover\"\n                            width={20}\n                            height={20}\n                          />\n                        </span>\n                        <span className=\"truncate text-sm font-semibold group-hover:text-white group-hover:underline\">\n                          {requestData.modifiedBy.displayName}\n                        </span>\n                      </Link>\n                    ),\n                  })}\n                </span>\n              </div>\n            )}\n            {request.profileName && (\n              <div className=\"card-field\">\n                <span className=\"card-field-name\">\n                  {intl.formatMessage(messages.profileName)}\n                </span>\n                <span className=\"flex truncate text-sm text-gray-300\">\n                  {request.profileName}\n                </span>\n              </div>\n            )}\n          </div>\n        </div>\n        <div className=\"z-10 mt-4 flex w-full flex-col justify-center space-y-2 pl-4 pr-4 xl:mt-0 xl:w-96 xl:items-end xl:pl-0\">\n          {requestData.status === MediaRequestStatus.FAILED &&\n            hasPermission(Permission.MANAGE_REQUESTS) && (\n              <Button\n                className=\"w-full\"\n                buttonType=\"primary\"\n                disabled={isRetrying}\n                onClick={() => retryRequest()}\n              >\n                <ArrowPathIcon\n                  className={isRetrying ? 'animate-spin' : ''}\n                  style={{ animationDirection: 'reverse' }}\n                />\n                <span>\n                  {intl.formatMessage(\n                    isRetrying ? globalMessages.retrying : globalMessages.retry\n                  )}\n                </span>\n              </Button>\n            )}\n          {requestData.status !== MediaRequestStatus.PENDING &&\n            hasPermission(Permission.MANAGE_REQUESTS) && (\n              <>\n                <ConfirmButton\n                  onClick={() => deleteRequest()}\n                  confirmText={intl.formatMessage(globalMessages.areyousure)}\n                  className=\"w-full\"\n                >\n                  <TrashIcon />\n                  <span>{intl.formatMessage(messages.deleterequest)}</span>\n                </ConfirmButton>\n                {request.canRemove && (\n                  <ConfirmButton\n                    onClick={() => deleteMediaFile()}\n                    confirmText={intl.formatMessage(globalMessages.areyousure)}\n                    className=\"w-full\"\n                  >\n                    <TrashIcon />\n                    <span>\n                      {intl.formatMessage(messages.removearr, {\n                        arr: request.type === 'movie' ? 'Radarr' : 'Sonarr',\n                      })}\n                    </span>\n                  </ConfirmButton>\n                )}\n              </>\n            )}\n          {requestData.status === MediaRequestStatus.PENDING &&\n            hasPermission(Permission.MANAGE_REQUESTS) && (\n              <div className=\"flex w-full flex-row space-x-2\">\n                <span className=\"w-full\">\n                  <Button\n                    className=\"w-full\"\n                    buttonType=\"success\"\n                    onClick={() => modifyRequest('approve')}\n                  >\n                    <CheckIcon />\n                    <span>{intl.formatMessage(globalMessages.approve)}</span>\n                  </Button>\n                </span>\n                <span className=\"w-full\">\n                  <Button\n                    className=\"w-full\"\n                    buttonType=\"danger\"\n                    onClick={() => modifyRequest('decline')}\n                  >\n                    <XMarkIcon />\n                    <span>{intl.formatMessage(globalMessages.decline)}</span>\n                  </Button>\n                </span>\n              </div>\n            )}\n          {requestData.status === MediaRequestStatus.PENDING &&\n            (hasPermission(Permission.MANAGE_REQUESTS) ||\n              (requestData.requestedBy.id === user?.id &&\n                (requestData.type === 'tv' ||\n                  hasPermission(Permission.REQUEST_ADVANCED)))) && (\n              <span className=\"w-full\">\n                <Button\n                  className=\"w-full\"\n                  buttonType=\"primary\"\n                  onClick={() => setShowEditModal(true)}\n                >\n                  <PencilIcon />\n                  <span>{intl.formatMessage(messages.editrequest)}</span>\n                </Button>\n              </span>\n            )}\n          {requestData.status === MediaRequestStatus.PENDING &&\n            !hasPermission(Permission.MANAGE_REQUESTS) &&\n            requestData.requestedBy.id === user?.id && (\n              <ConfirmButton\n                onClick={() => deleteRequest()}\n                confirmText={intl.formatMessage(globalMessages.areyousure)}\n                className=\"w-full\"\n              >\n                <XMarkIcon />\n                <span>{intl.formatMessage(messages.cancelRequest)}</span>\n              </ConfirmButton>\n            )}\n        </div>\n      </div>\n    </>\n  );\n};\n\nexport default RequestItem;\n"
  },
  {
    "path": "src/components/RequestList/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport RequestItem from '@app/components/RequestList/RequestItem';\nimport { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ExclamationTriangleIcon } from '@heroicons/react/24/outline';\nimport {\n  ArrowDownIcon,\n  ArrowUpIcon,\n  Bars3BottomLeftIcon,\n  ChevronLeftIcon,\n  ChevronRightIcon,\n  CircleStackIcon,\n  FunnelIcon,\n} from '@heroicons/react/24/solid';\nimport type { RequestResultsResponse } from '@server/interfaces/api/requestInterfaces';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.RequestList', {\n  requests: 'Requests',\n  showallrequests: 'Show All Requests',\n  sortAdded: 'Most Recent',\n  sortModified: 'Last Modified',\n  sortDirection: 'Toggle Sort Direction',\n  unableToConnect:\n    'Unable to connect to {services}. Some information may be unavailable.',\n});\n\nenum Filter {\n  ALL = 'all',\n  PENDING = 'pending',\n  APPROVED = 'approved',\n  PROCESSING = 'processing',\n  AVAILABLE = 'available',\n  UNAVAILABLE = 'unavailable',\n  FAILED = 'failed',\n  DELETED = 'deleted',\n  COMPLETED = 'completed',\n}\n\ntype Sort = 'added' | 'modified';\n\ntype SortDirection = 'asc' | 'desc';\n\ntype MediaType = 'all' | 'movie' | 'tv';\n\nconst RequestList = () => {\n  const router = useRouter();\n  const intl = useIntl();\n  const { user } = useUser({\n    id: Number(router.query.userId),\n  });\n  const { user: currentUser, hasPermission } = useUser();\n  const [currentFilter, setCurrentFilter] = useState<Filter>(Filter.PENDING);\n  const [currentSort, setCurrentSort] = useState<Sort>('added');\n  const [currentMediaType, setCurrentMediaType] = useState<string>('all');\n  const [currentSortDirection, setCurrentSortDirection] =\n    useState<SortDirection>('desc');\n  const [currentPageSize, setCurrentPageSize] = useState<number>(10);\n\n  const page = router.query.page ? Number(router.query.page) : 1;\n  const pageIndex = page - 1;\n  const updateQueryParams = useUpdateQueryParams({ page: page.toString() });\n\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<RequestResultsResponse>(\n    `/api/v1/request?take=${currentPageSize}&skip=${\n      pageIndex * currentPageSize\n    }&filter=${currentFilter}&mediaType=${currentMediaType}&sort=${currentSort}&sortDirection=${currentSortDirection}${\n      router.pathname.startsWith('/profile')\n        ? `&requestedBy=${currentUser?.id}`\n        : router.query.userId\n          ? `&requestedBy=${router.query.userId}`\n          : ''\n    }`\n  );\n\n  // Restore last set filter values on component mount\n  useEffect(() => {\n    const filterString = window.localStorage.getItem('rl-filter-settings');\n\n    if (filterString) {\n      const filterSettings = JSON.parse(filterString);\n\n      setCurrentFilter(filterSettings.currentFilter);\n      setCurrentSort(filterSettings.currentSort);\n      setCurrentPageSize(filterSettings.currentPageSize);\n      if (['asc', 'desc'].includes(filterSettings.currentSortDirection)) {\n        setCurrentSortDirection(filterSettings.currentSortDirection);\n      }\n    }\n\n    // If filter value is provided in query, use that instead\n    if (Object.values(Filter).includes(router.query.filter as Filter)) {\n      setCurrentFilter(router.query.filter as Filter);\n    }\n  }, [router.query.filter]);\n\n  // Set filter values to local storage any time they are changed\n  useEffect(() => {\n    window.localStorage.setItem(\n      'rl-filter-settings',\n      JSON.stringify({\n        currentFilter,\n        currentMediaType,\n        currentSort,\n        currentSortDirection,\n        currentPageSize,\n      })\n    );\n  }, [\n    currentFilter,\n    currentMediaType,\n    currentSort,\n    currentSortDirection,\n    currentPageSize,\n  ]);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <LoadingSpinner />;\n  }\n\n  const hasNextPage = data.pageInfo.pages > pageIndex + 1;\n  const hasPrevPage = pageIndex > 0;\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.requests),\n          router.query.userId ? user?.displayName : '',\n        ]}\n      />\n      <div className=\"mb-4 flex flex-col justify-between lg:flex-row lg:items-end\">\n        <Header\n          subtext={\n            router.pathname.startsWith('/profile') ? (\n              <Link href={`/profile`} className=\"hover:underline\">\n                {currentUser?.displayName}\n              </Link>\n            ) : router.query.userId ? (\n              <Link href={`/users/${user?.id}`} className=\"hover:underline\">\n                {user?.displayName}\n              </Link>\n            ) : (\n              ''\n            )\n          }\n        >\n          {intl.formatMessage(messages.requests)}\n        </Header>\n        <div className=\"mt-2 flex flex-grow flex-col sm:flex-row lg:flex-grow-0\">\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n              <CircleStackIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"mediaType\"\n              name=\"mediaType\"\n              onChange={(e) => {\n                setCurrentMediaType(e.target.value as MediaType);\n                router.push({\n                  pathname: router.pathname,\n                  query: router.query.userId\n                    ? { userId: router.query.userId }\n                    : {},\n                });\n              }}\n              value={currentMediaType}\n              className=\"rounded-r-only\"\n            >\n              <option value=\"all\">\n                {intl.formatMessage(globalMessages.all)}\n              </option>\n              <option value=\"movie\">\n                {intl.formatMessage(globalMessages.movies)}\n              </option>\n              <option value=\"tv\">\n                {intl.formatMessage(globalMessages.tvshows)}\n              </option>\n            </select>\n          </div>\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n              <FunnelIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"filter\"\n              name=\"filter\"\n              onChange={(e) => {\n                setCurrentFilter(e.target.value as Filter);\n                router.push({\n                  pathname: router.pathname,\n                  query: router.query.userId\n                    ? { userId: router.query.userId }\n                    : {},\n                });\n              }}\n              value={currentFilter}\n              className=\"rounded-r-only\"\n            >\n              <option value=\"all\">\n                {intl.formatMessage(globalMessages.all)}\n              </option>\n              <option value=\"pending\">\n                {intl.formatMessage(globalMessages.pending)}\n              </option>\n              <option value=\"approved\">\n                {intl.formatMessage(globalMessages.approved)}\n              </option>\n              <option value=\"completed\">\n                {intl.formatMessage(globalMessages.completed)}\n              </option>\n              <option value=\"processing\">\n                {intl.formatMessage(globalMessages.processing)}\n              </option>\n              <option value=\"failed\">\n                {intl.formatMessage(globalMessages.failed)}\n              </option>\n              <option value=\"available\">\n                {intl.formatMessage(globalMessages.available)}\n              </option>\n              <option value=\"unavailable\">\n                {intl.formatMessage(globalMessages.unavailable)}\n              </option>\n              <option value=\"deleted\">\n                {intl.formatMessage(globalMessages.deleted)}\n              </option>\n            </select>\n          </div>\n          <div className=\"mb-2 flex flex-grow sm:mb-0 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-gray-100 sm:text-sm\">\n              <Bars3BottomLeftIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"sort\"\n              name=\"sort\"\n              onChange={(e) => {\n                setCurrentSort(e.target.value as Sort);\n                router.push({\n                  pathname: router.pathname,\n                  query: router.query.userId\n                    ? { userId: router.query.userId }\n                    : {},\n                });\n              }}\n              value={currentSort}\n              className=\"rounded-none border-r-0\"\n            >\n              <option value=\"added\">\n                {intl.formatMessage(messages.sortAdded)}\n              </option>\n              <option value=\"modified\">\n                {intl.formatMessage(messages.sortModified)}\n              </option>\n            </select>\n            <Tooltip content={intl.formatMessage(messages.sortDirection)}>\n              <Button\n                buttonType=\"default\"\n                className=\"z-40 mr-2 rounded-l-none border !border-gray-500 !bg-gray-800 !px-3 !text-gray-500 hover:!bg-gray-400 hover:!text-white\"\n                buttonSize=\"md\"\n                onClick={() =>\n                  setCurrentSortDirection(\n                    currentSortDirection === 'asc' ? 'desc' : 'asc'\n                  )\n                }\n              >\n                {currentSortDirection === 'asc' ? (\n                  <ArrowUpIcon className=\"h-6 w-6\" />\n                ) : (\n                  <ArrowDownIcon className=\"h-6 w-6\" />\n                )}\n              </Button>\n            </Tooltip>\n          </div>\n        </div>\n      </div>\n\n      {data.serviceErrors &&\n        (data.serviceErrors.radarr.length > 0 ||\n          data.serviceErrors.sonarr.length > 0) &&\n        (hasPermission(Permission.MANAGE_REQUESTS) ||\n          hasPermission(Permission.REQUEST_ADVANCED)) && (\n          <div className=\"service-error-banner\">\n            <ExclamationTriangleIcon className=\"h-5 w-5 flex-shrink-0\" />\n            <span>\n              {intl.formatMessage(messages.unableToConnect, {\n                services: [\n                  ...data.serviceErrors.radarr.map((s) => s.name),\n                  ...data.serviceErrors.sonarr.map((s) => s.name),\n                ].join(', '),\n              })}\n            </span>\n          </div>\n        )}\n\n      {data.results.map((request) => {\n        return (\n          <div className=\"py-2\" key={`request-list-${request.id}`}>\n            <RequestItem\n              request={request}\n              revalidateList={() => revalidate()}\n            />\n          </div>\n        );\n      })}\n\n      {data.results.length === 0 && (\n        <div className=\"flex w-full flex-col items-center justify-center py-24 text-white\">\n          <span className=\"text-2xl text-gray-400\">\n            {intl.formatMessage(globalMessages.noresults)}\n          </span>\n          {(currentFilter !== Filter.ALL ||\n            currentMediaType !== Filter.ALL) && (\n            <div className=\"mt-4\">\n              <Button\n                buttonType=\"primary\"\n                onClick={() => {\n                  setCurrentFilter(Filter.ALL);\n                  setCurrentMediaType(Filter.ALL);\n                }}\n              >\n                {intl.formatMessage(messages.showallrequests)}\n              </Button>\n            </div>\n          )}\n        </div>\n      )}\n      <div className=\"actions\">\n        <nav\n          className=\"mb-3 flex flex-col items-center space-y-3 sm:flex-row sm:space-y-0\"\n          aria-label=\"Pagination\"\n        >\n          <div className=\"hidden lg:flex lg:flex-1\">\n            <p className=\"text-sm\">\n              {data.results.length > 0 &&\n                intl.formatMessage(globalMessages.showingresults, {\n                  from: pageIndex * currentPageSize + 1,\n                  to:\n                    data.results.length < currentPageSize\n                      ? pageIndex * currentPageSize + data.results.length\n                      : (pageIndex + 1) * currentPageSize,\n                  total: data.pageInfo.results,\n                  strong: (msg: React.ReactNode) => (\n                    <span className=\"font-medium\">{msg}</span>\n                  ),\n                })}\n            </p>\n          </div>\n          <div className=\"flex justify-center sm:flex-1 sm:justify-start lg:justify-center\">\n            <span className=\"-mt-3 items-center truncate text-sm sm:mt-0\">\n              {intl.formatMessage(globalMessages.resultsperpage, {\n                pageSize: (\n                  <select\n                    id=\"pageSize\"\n                    name=\"pageSize\"\n                    onChange={(e) => {\n                      setCurrentPageSize(Number(e.target.value));\n                      router\n                        .push({\n                          pathname: router.pathname,\n                          query: router.query.userId\n                            ? { userId: router.query.userId }\n                            : {},\n                        })\n                        .then(() => window.scrollTo(0, 0));\n                    }}\n                    value={currentPageSize}\n                    className=\"short inline\"\n                  >\n                    <option value=\"5\">5</option>\n                    <option value=\"10\">10</option>\n                    <option value=\"25\">25</option>\n                    <option value=\"50\">50</option>\n                    <option value=\"100\">100</option>\n                  </select>\n                ),\n              })}\n            </span>\n          </div>\n          <div className=\"flex flex-auto justify-center space-x-2 sm:flex-1 sm:justify-end\">\n            <Button\n              disabled={!hasPrevPage}\n              onClick={() => updateQueryParams('page', (page - 1).toString())}\n            >\n              <ChevronLeftIcon />\n              <span>{intl.formatMessage(globalMessages.previous)}</span>\n            </Button>\n            <Button\n              disabled={!hasNextPage}\n              onClick={() => updateQueryParams('page', (page + 1).toString())}\n            >\n              <span>{intl.formatMessage(globalMessages.next)}</span>\n              <ChevronRightIcon />\n            </Button>\n          </div>\n        </nav>\n      </div>\n    </>\n  );\n};\n\nexport default RequestList;\n"
  },
  {
    "path": "src/components/RequestModal/AdvancedRequester/index.tsx",
    "content": "/* eslint-disable react-hooks/exhaustive-deps */\nimport CachedImage from '@app/components/Common/CachedImage';\nimport { SmallLoadingSpinner } from '@app/components/Common/LoadingSpinner';\nimport type { User } from '@app/hooks/useUser';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { formatBytes } from '@app/utils/numberHelpers';\nimport { Listbox, Transition } from '@headlessui/react';\nimport { CheckIcon, ChevronDownIcon } from '@heroicons/react/24/solid';\nimport type {\n  ServiceCommonServer,\n  ServiceCommonServerWithDetails,\n} from '@server/interfaces/api/serviceInterfaces';\nimport type { UserResultsResponse } from '@server/interfaces/api/userInterfaces';\nimport { hasPermission } from '@server/lib/permissions';\nimport { isEqual } from 'lodash';\nimport { useEffect, useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport Select from 'react-select';\nimport useSWR from 'swr';\n\ntype OptionType = {\n  value: number;\n  label: string;\n};\n\nconst messages = defineMessages('components.RequestModal.AdvancedRequester', {\n  advancedoptions: 'Advanced',\n  destinationserver: 'Destination Server',\n  qualityprofile: 'Quality Profile',\n  rootfolder: 'Root Folder',\n  animenote: '* This series is an anime.',\n  default: '{name} (Default)',\n  folder: '{path} ({space})',\n  requestas: 'Request As',\n  languageprofile: 'Language Profile',\n  tags: 'Tags',\n  selecttags: 'Select tags',\n  notagoptions: 'No tags.',\n});\n\nexport type RequestOverrides = {\n  server?: number;\n  profile?: number;\n  folder?: string;\n  tags?: number[];\n  language?: number;\n  user?: User;\n};\n\ninterface AdvancedRequesterProps {\n  type: 'movie' | 'tv';\n  is4k: boolean;\n  isAnime?: boolean;\n  defaultOverrides?: RequestOverrides;\n  requestUser?: User;\n  onChange: (overrides: RequestOverrides) => void;\n}\n\nconst AdvancedRequester = ({\n  type,\n  is4k = false,\n  isAnime = false,\n  defaultOverrides,\n  requestUser,\n  onChange,\n}: AdvancedRequesterProps) => {\n  const intl = useIntl();\n  const { user: currentUser, hasPermission: currentHasPermission } = useUser();\n  const { data, error } = useSWR<ServiceCommonServer[]>(\n    `/api/v1/service/${type === 'movie' ? 'radarr' : 'sonarr'}`,\n    {\n      refreshInterval: 0,\n      refreshWhenHidden: false,\n      revalidateOnFocus: false,\n      revalidateOnMount: true,\n    }\n  );\n  const [selectedServer, setSelectedServer] = useState<number | null>(\n    defaultOverrides?.server !== undefined && defaultOverrides?.server >= 0\n      ? defaultOverrides?.server\n      : null\n  );\n  const [selectedProfile, setSelectedProfile] = useState<number>(\n    defaultOverrides?.profile ?? -1\n  );\n  const [selectedFolder, setSelectedFolder] = useState<string>(\n    defaultOverrides?.folder ?? ''\n  );\n\n  const [selectedLanguage, setSelectedLanguage] = useState<number>(\n    defaultOverrides?.language ?? -1\n  );\n\n  const [selectedTags, setSelectedTags] = useState<number[]>(\n    defaultOverrides?.tags ?? []\n  );\n\n  const { data: serverData, isValidating } =\n    useSWR<ServiceCommonServerWithDetails>(\n      selectedServer !== null\n        ? `/api/v1/service/${\n            type === 'movie' ? 'radarr' : 'sonarr'\n          }/${selectedServer}`\n        : null,\n      {\n        refreshInterval: 0,\n        refreshWhenHidden: false,\n        revalidateOnFocus: false,\n      }\n    );\n\n  const [selectedUser, setSelectedUser] = useState<User | null>(\n    requestUser ?? null\n  );\n\n  const { data: userData } = useSWR<UserResultsResponse>(\n    currentHasPermission([Permission.MANAGE_REQUESTS, Permission.MANAGE_USERS])\n      ? '/api/v1/user?take=1000&sort=displayname'\n      : null\n  );\n  const filteredUserData = useMemo(\n    () =>\n      userData?.results.filter((user) =>\n        hasPermission(\n          is4k\n            ? [\n                Permission.REQUEST_4K,\n                type === 'movie'\n                  ? Permission.REQUEST_4K_MOVIE\n                  : Permission.REQUEST_4K_TV,\n              ]\n            : [\n                Permission.REQUEST,\n                type === 'movie'\n                  ? Permission.REQUEST_MOVIE\n                  : Permission.REQUEST_TV,\n              ],\n          user.permissions,\n          { type: 'or' }\n        )\n      ),\n    [userData?.results]\n  );\n\n  useEffect(() => {\n    if (filteredUserData && !requestUser) {\n      setSelectedUser(\n        filteredUserData.find((u) => u.id === currentUser?.id) ?? null\n      );\n    }\n  }, [filteredUserData]);\n\n  useEffect(() => {\n    let defaultServer = data?.find(\n      (server) => server.isDefault && is4k === server.is4k\n    );\n\n    if (!defaultServer && (data ?? []).length > 0) {\n      defaultServer = data?.[0];\n    }\n\n    if (\n      defaultServer &&\n      defaultServer.id !== selectedServer &&\n      (!defaultOverrides || defaultOverrides.server === null)\n    ) {\n      setSelectedServer(defaultServer.id);\n    }\n  }, [data]);\n\n  useEffect(() => {\n    if (serverData) {\n      const defaultProfile = serverData.profiles.find(\n        (profile) =>\n          profile.id ===\n          (isAnime && serverData.server.activeAnimeProfileId\n            ? serverData.server.activeAnimeProfileId\n            : serverData.server.activeProfileId)\n      );\n      const defaultFolder = serverData.rootFolders.find(\n        (folder) =>\n          folder.path ===\n          (isAnime && serverData.server.activeAnimeDirectory\n            ? serverData.server.activeAnimeDirectory\n            : serverData.server.activeDirectory)\n      );\n      const defaultLanguage = serverData.languageProfiles?.find(\n        (language) =>\n          language.id ===\n          (isAnime && serverData.server.activeAnimeLanguageProfileId\n            ? serverData.server.activeAnimeLanguageProfileId\n            : serverData.server.activeLanguageProfileId)\n      );\n      const defaultTags = isAnime\n        ? serverData.server.activeAnimeTags\n        : serverData.server.activeTags;\n\n      const applyOverrides =\n        defaultOverrides &&\n        ((defaultOverrides.server === null && serverData.server.isDefault) ||\n          defaultOverrides.server === serverData.server.id);\n\n      if (\n        defaultProfile &&\n        defaultProfile.id !== selectedProfile &&\n        (!applyOverrides || defaultOverrides.profile === null)\n      ) {\n        setSelectedProfile(defaultProfile.id);\n      }\n\n      if (\n        defaultFolder &&\n        defaultFolder.path !== selectedFolder &&\n        (!applyOverrides || !defaultOverrides.folder)\n      ) {\n        setSelectedFolder(defaultFolder.path ?? '');\n      }\n\n      if (\n        defaultLanguage &&\n        defaultLanguage.id !== selectedLanguage &&\n        (!applyOverrides || defaultOverrides.language === null)\n      ) {\n        setSelectedLanguage(defaultLanguage.id);\n      }\n\n      if (\n        defaultTags &&\n        !isEqual(defaultTags, selectedTags) &&\n        (!applyOverrides || defaultOverrides.tags === null)\n      ) {\n        setSelectedTags(defaultTags);\n      }\n    }\n  }, [serverData]);\n\n  useEffect(() => {\n    if (defaultOverrides && defaultOverrides.server != null) {\n      setSelectedServer(defaultOverrides.server);\n    }\n\n    if (defaultOverrides && defaultOverrides.profile != null) {\n      setSelectedProfile(defaultOverrides.profile);\n    }\n\n    if (defaultOverrides && defaultOverrides.folder) {\n      setSelectedFolder(defaultOverrides.folder);\n    }\n\n    if (defaultOverrides && defaultOverrides.language != null) {\n      setSelectedLanguage(defaultOverrides.language);\n    }\n\n    if (defaultOverrides && defaultOverrides.tags != null) {\n      setSelectedTags(defaultOverrides.tags);\n    }\n  }, [\n    defaultOverrides?.server,\n    defaultOverrides?.folder,\n    defaultOverrides?.profile,\n    defaultOverrides?.language,\n    defaultOverrides?.tags,\n  ]);\n\n  useEffect(() => {\n    if (selectedServer !== null || selectedUser) {\n      onChange({\n        folder: selectedFolder !== '' ? selectedFolder : undefined,\n        profile: selectedProfile !== -1 ? selectedProfile : undefined,\n        server: selectedServer ?? undefined,\n        user: selectedUser ?? undefined,\n        language: selectedLanguage !== -1 ? selectedLanguage : undefined,\n        tags: selectedTags,\n      });\n    }\n  }, [\n    selectedFolder,\n    selectedServer,\n    selectedProfile,\n    selectedUser,\n    selectedLanguage,\n    selectedTags,\n  ]);\n\n  if (!data && !error) {\n    return (\n      <div className=\"mb-2 w-full\">\n        <SmallLoadingSpinner />\n      </div>\n    );\n  }\n\n  if (\n    (!data ||\n      selectedServer === null ||\n      (data.filter((server) => server.is4k === is4k).length < 2 &&\n        (!serverData ||\n          (serverData.profiles.length < 2 &&\n            serverData.rootFolders.length < 2 &&\n            (serverData.languageProfiles ?? []).length < 2 &&\n            !serverData.tags?.length)))) &&\n    (!selectedUser || (filteredUserData ?? []).length < 2)\n  ) {\n    return null;\n  }\n\n  return (\n    <>\n      <div className=\"mb-2 mt-4 flex items-center text-lg font-semibold\">\n        {intl.formatMessage(messages.advancedoptions)}\n      </div>\n      <div className=\"rounded-md\">\n        {!!data && selectedServer !== null && (\n          <div className=\"flex flex-col md:flex-row\">\n            {data.filter((server) => server.is4k === is4k).length > 1 && (\n              <div className=\"mb-3 w-full flex-shrink-0 flex-grow last:pr-0 md:w-1/4 md:pr-4\">\n                <label htmlFor=\"server\">\n                  {intl.formatMessage(messages.destinationserver)}\n                </label>\n                <select\n                  id=\"server\"\n                  name=\"server\"\n                  value={selectedServer}\n                  onChange={(e) => setSelectedServer(Number(e.target.value))}\n                  onBlur={(e) => setSelectedServer(Number(e.target.value))}\n                  className=\"border-gray-700 bg-gray-800\"\n                >\n                  {data\n                    .filter((server) => server.is4k === is4k)\n                    .map((server) => (\n                      <option\n                        key={`server-list-${server.id}`}\n                        value={server.id}\n                      >\n                        {server.isDefault\n                          ? intl.formatMessage(messages.default, {\n                              name: server.name,\n                            })\n                          : server.name}\n                      </option>\n                    ))}\n                </select>\n              </div>\n            )}\n            {(isValidating ||\n              !serverData ||\n              serverData.profiles.length > 1) && (\n              <div className=\"mb-3 w-full flex-shrink-0 flex-grow last:pr-0 md:w-1/4 md:pr-4\">\n                <label htmlFor=\"profile\">\n                  {intl.formatMessage(messages.qualityprofile)}\n                </label>\n                <select\n                  id=\"profile\"\n                  name=\"profile\"\n                  value={selectedProfile}\n                  onChange={(e) => setSelectedProfile(Number(e.target.value))}\n                  onBlur={(e) => setSelectedProfile(Number(e.target.value))}\n                  className=\"border-gray-700 bg-gray-800\"\n                  disabled={isValidating || !serverData}\n                >\n                  {(isValidating || !serverData) && (\n                    <option value=\"\">\n                      {intl.formatMessage(globalMessages.loading)}\n                    </option>\n                  )}\n                  {!isValidating &&\n                    serverData &&\n                    serverData.profiles\n                      .toSorted((a, b) =>\n                        a.name.localeCompare(b.name, intl.locale, {\n                          numeric: true,\n                          sensitivity: 'base',\n                        })\n                      )\n                      .map((profile) => (\n                        <option\n                          key={`profile-list${profile.id}`}\n                          value={profile.id}\n                        >\n                          {isAnime &&\n                          serverData.server.activeAnimeProfileId === profile.id\n                            ? intl.formatMessage(messages.default, {\n                                name: profile.name,\n                              })\n                            : !isAnime &&\n                                serverData.server.activeProfileId === profile.id\n                              ? intl.formatMessage(messages.default, {\n                                  name: profile.name,\n                                })\n                              : profile.name}\n                        </option>\n                      ))}\n                </select>\n              </div>\n            )}\n            {(isValidating ||\n              !serverData ||\n              serverData.rootFolders.length > 1) && (\n              <div className=\"mb-3 w-full flex-shrink-0 flex-grow last:pr-0 md:w-1/4 md:pr-4\">\n                <label htmlFor=\"folder\">\n                  {intl.formatMessage(messages.rootfolder)}\n                </label>\n                <select\n                  id=\"folder\"\n                  name=\"folder\"\n                  value={selectedFolder}\n                  onChange={(e) => setSelectedFolder(e.target.value)}\n                  onBlur={(e) => setSelectedFolder(e.target.value)}\n                  className=\"border-gray-700 bg-gray-800\"\n                  disabled={isValidating || !serverData}\n                >\n                  {(isValidating || !serverData) && (\n                    <option value=\"\">\n                      {intl.formatMessage(globalMessages.loading)}\n                    </option>\n                  )}\n                  {!isValidating &&\n                    serverData &&\n                    serverData.rootFolders.map((folder) => (\n                      <option\n                        key={`folder-list${folder.id}`}\n                        value={folder.path}\n                      >\n                        {isAnime &&\n                        serverData.server.activeAnimeDirectory === folder.path\n                          ? intl.formatMessage(messages.default, {\n                              name: intl.formatMessage(messages.folder, {\n                                path: folder.path,\n                                space: formatBytes(folder.freeSpace ?? 0),\n                              }),\n                            })\n                          : !isAnime &&\n                              serverData.server.activeDirectory === folder.path\n                            ? intl.formatMessage(messages.default, {\n                                name: intl.formatMessage(messages.folder, {\n                                  path: folder.path,\n                                  space: formatBytes(folder.freeSpace ?? 0),\n                                }),\n                              })\n                            : intl.formatMessage(messages.folder, {\n                                path: folder.path,\n                                space: formatBytes(folder.freeSpace ?? 0),\n                              })}\n                      </option>\n                    ))}\n                </select>\n              </div>\n            )}\n            {type === 'tv' &&\n              (isValidating ||\n                !serverData ||\n                (serverData.languageProfiles ?? []).length > 1) && (\n                <div className=\"mb-3 w-full flex-shrink-0 flex-grow last:pr-0 md:w-1/4 md:pr-4\">\n                  <label htmlFor=\"language\">\n                    {intl.formatMessage(messages.languageprofile)}\n                  </label>\n                  <select\n                    id=\"language\"\n                    name=\"language\"\n                    value={selectedLanguage}\n                    onChange={(e) =>\n                      setSelectedLanguage(parseInt(e.target.value))\n                    }\n                    onBlur={(e) =>\n                      setSelectedLanguage(parseInt(e.target.value))\n                    }\n                    className=\"border-gray-700 bg-gray-800\"\n                    disabled={isValidating || !serverData}\n                  >\n                    {(isValidating || !serverData) && (\n                      <option value=\"\">\n                        {intl.formatMessage(globalMessages.loading)}\n                      </option>\n                    )}\n                    {!isValidating &&\n                      serverData &&\n                      serverData.languageProfiles?.map((language) => (\n                        <option\n                          key={`folder-list${language.id}`}\n                          value={language.id}\n                        >\n                          {isAnime &&\n                          serverData.server.activeAnimeLanguageProfileId ===\n                            language.id\n                            ? intl.formatMessage(messages.default, {\n                                name: language.name,\n                              })\n                            : !isAnime &&\n                                serverData.server.activeLanguageProfileId ===\n                                  language.id\n                              ? intl.formatMessage(messages.default, {\n                                  name: language.name,\n                                })\n                              : language.name}\n                        </option>\n                      ))}\n                  </select>\n                </div>\n              )}\n          </div>\n        )}\n        {selectedServer !== null &&\n          (isValidating || !serverData || !!serverData?.tags?.length) && (\n            <div className=\"mb-2\">\n              <label htmlFor=\"tags\">{intl.formatMessage(messages.tags)}</label>\n              <Select<OptionType, true>\n                name=\"tags\"\n                options={(serverData?.tags ?? []).map((tag) => ({\n                  label: tag.label,\n                  value: tag.id,\n                }))}\n                isMulti\n                isDisabled={isValidating || !serverData}\n                placeholder={\n                  isValidating || !serverData\n                    ? intl.formatMessage(globalMessages.loading)\n                    : intl.formatMessage(messages.selecttags)\n                }\n                className=\"react-select-container react-select-container-dark\"\n                classNamePrefix=\"react-select\"\n                value={\n                  selectedTags\n                    .map((tagId) => {\n                      const foundTag = serverData?.tags.find(\n                        (tag) => tag.id === tagId\n                      );\n\n                      if (!foundTag) {\n                        return undefined;\n                      }\n\n                      return {\n                        value: foundTag.id,\n                        label: foundTag.label,\n                      };\n                    })\n                    .filter((option) => option !== undefined) as OptionType[]\n                }\n                onChange={(value) => {\n                  setSelectedTags(value.map((option) => option.value));\n                }}\n                noOptionsMessage={() =>\n                  intl.formatMessage(messages.notagoptions)\n                }\n              />\n            </div>\n          )}\n        {currentHasPermission([\n          Permission.MANAGE_REQUESTS,\n          Permission.MANAGE_USERS,\n        ]) &&\n          selectedUser &&\n          (filteredUserData ?? []).length > 1 && (\n            <Listbox\n              as=\"div\"\n              value={selectedUser}\n              onChange={(value) => setSelectedUser(value)}\n              className=\"space-y-1\"\n            >\n              {({ open }) => (\n                <>\n                  <Listbox.Label>\n                    {intl.formatMessage(messages.requestas)}\n                  </Listbox.Label>\n                  <div className=\"relative\">\n                    <span className=\"inline-block w-full rounded-md shadow-sm\">\n                      <Listbox.Button className=\"focus:shadow-outline-blue relative w-full cursor-default rounded-md border border-gray-700 bg-gray-800 py-2 pl-3 pr-10 text-left text-white transition duration-150 ease-in-out focus:border-blue-300 focus:outline-none sm:text-sm sm:leading-5\">\n                        <span className=\"flex items-center\">\n                          <CachedImage\n                            type=\"avatar\"\n                            src={selectedUser.avatar}\n                            alt=\"\"\n                            className=\"h-6 w-6 flex-shrink-0 rounded-full object-cover\"\n                            width={24}\n                            height={24}\n                          />\n                          <span className=\"ml-3 block\">\n                            {selectedUser.displayName}\n                          </span>\n                          {selectedUser.displayName.toLowerCase() !==\n                            selectedUser.email && (\n                            <span className=\"ml-1 truncate text-gray-400\">\n                              ({selectedUser.email})\n                            </span>\n                          )}\n                        </span>\n                        <span className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-500\">\n                          <ChevronDownIcon className=\"h-5 w-5\" />\n                        </span>\n                      </Listbox.Button>\n                    </span>\n\n                    <Transition\n                      show={open}\n                      enter=\"transition-opacity ease-in duration-300\"\n                      enterFrom=\"opacity-0\"\n                      enterTo=\"opacity-100\"\n                      leave=\"transition-opacity ease-in duration-100\"\n                      leaveFrom=\"opacity-100\"\n                      leaveTo=\"opacity-0\"\n                      className=\"mt-1 w-full rounded-md border border-gray-700 bg-gray-800 shadow-lg\"\n                    >\n                      <Listbox.Options\n                        static\n                        className=\"shadow-xs max-h-60 overflow-auto rounded-md py-1 text-base leading-6 focus:outline-none sm:text-sm sm:leading-5\"\n                      >\n                        {filteredUserData?.map((user) => (\n                          <Listbox.Option key={user.id} value={user}>\n                            {({ selected, active }) => (\n                              <div\n                                className={`${\n                                  active\n                                    ? 'bg-indigo-600 text-white'\n                                    : 'text-gray-300'\n                                } relative cursor-default select-none py-2 pl-8 pr-4`}\n                              >\n                                <span\n                                  className={`${\n                                    selected ? 'font-semibold' : 'font-normal'\n                                  } flex items-center`}\n                                >\n                                  <CachedImage\n                                    type=\"avatar\"\n                                    src={user.avatar}\n                                    alt=\"\"\n                                    className=\"h-6 w-6 flex-shrink-0 rounded-full object-cover\"\n                                    width={24}\n                                    height={24}\n                                  />\n                                  <span className=\"ml-3 block flex-shrink-0\">\n                                    {user.displayName}\n                                  </span>\n                                  {user.displayName.toLowerCase() !==\n                                    user.email && (\n                                    <span className=\"ml-1 truncate text-gray-400\">\n                                      ({user.email})\n                                    </span>\n                                  )}\n                                </span>\n                                {selected && (\n                                  <span\n                                    className={`${\n                                      active ? 'text-white' : 'text-indigo-600'\n                                    } absolute inset-y-0 left-0 flex items-center pl-1.5`}\n                                  >\n                                    <CheckIcon className=\"h-5 w-5\" />\n                                  </span>\n                                )}\n                              </div>\n                            )}\n                          </Listbox.Option>\n                        ))}\n                      </Listbox.Options>\n                    </Transition>\n                  </div>\n                </>\n              )}\n            </Listbox>\n          )}\n        {isAnime && (\n          <div className=\"mt-4 italic\">\n            {intl.formatMessage(messages.animenote)}\n          </div>\n        )}\n      </div>\n    </>\n  );\n};\n\nexport default AdvancedRequester;\n"
  },
  {
    "path": "src/components/RequestModal/CollectionRequestModal.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Badge from '@app/components/Common/Badge';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport Modal from '@app/components/Common/Modal';\nimport type { RequestOverrides } from '@app/components/RequestModal/AdvancedRequester';\nimport AdvancedRequester from '@app/components/RequestModal/AdvancedRequester';\nimport QuotaDisplay from '@app/components/RequestModal/QuotaDisplay';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { MediaRequestStatus, MediaStatus } from '@server/constants/media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport type { QuotaResponse } from '@server/interfaces/api/userInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport type { Collection } from '@server/models/Collection';\nimport axios from 'axios';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\n\nconst messages = defineMessages('components.RequestModal', {\n  requestadmin: 'This request will be approved automatically.',\n  requestSuccess: '<strong>{title}</strong> requested successfully!',\n  requestcollectiontitle: 'Request Collection',\n  requestcollection4ktitle: 'Request Collection in 4K',\n  requesterror: 'Something went wrong while submitting the request.',\n  selectmovies: 'Select Movie(s)',\n  requestmovies: 'Request {count} {count, plural, one {Movie} other {Movies}}',\n  requestmovies4k:\n    'Request {count} {count, plural, one {Movie} other {Movies}} in 4K',\n});\n\ninterface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> {\n  tmdbId: number;\n  is4k?: boolean;\n  onCancel?: () => void;\n  onComplete?: (newStatus: MediaStatus) => void;\n  onUpdating?: (isUpdating: boolean) => void;\n}\n\nconst CollectionRequestModal = ({\n  onCancel,\n  onComplete,\n  tmdbId,\n  onUpdating,\n  is4k = false,\n}: RequestModalProps) => {\n  const [isUpdating, setIsUpdating] = useState(false);\n  const [requestOverrides, setRequestOverrides] =\n    useState<RequestOverrides | null>(null);\n  const [selectedParts, setSelectedParts] = useState<number[]>([]);\n  const { addToast } = useToasts();\n  const { data, error } = useSWR<Collection>(`/api/v1/collection/${tmdbId}`, {\n    revalidateOnMount: true,\n  });\n  const intl = useIntl();\n  const { user, hasPermission } = useUser();\n  const { data: quota } = useSWR<QuotaResponse>(\n    user &&\n      (!requestOverrides?.user?.id || hasPermission(Permission.MANAGE_USERS))\n      ? `/api/v1/user/${requestOverrides?.user?.id ?? user.id}/quota`\n      : null\n  );\n\n  const currentlyRemaining =\n    (quota?.movie.remaining ?? 0) - selectedParts.length;\n\n  const getAllParts = (): number[] => {\n    return (data?.parts ?? [])\n      .filter((part) => part.mediaInfo?.status !== MediaStatus.BLOCKLISTED)\n      .map((part) => part.id);\n  };\n\n  const getAllRequestedParts = (): number[] => {\n    const requestedParts = (data?.parts ?? []).reduce(\n      (requestedParts, part) => {\n        return [\n          ...requestedParts,\n          ...(part.mediaInfo?.requests ?? [])\n            .filter(\n              (request) =>\n                request.is4k === is4k &&\n                request.status !== MediaRequestStatus.DECLINED &&\n                request.status !== MediaRequestStatus.COMPLETED\n            )\n            .map((part) => part.id),\n        ];\n      },\n      [] as number[]\n    );\n\n    const availableParts = (data?.parts ?? [])\n      .filter(\n        (part) =>\n          part.mediaInfo &&\n          (part.mediaInfo[is4k ? 'status4k' : 'status'] ===\n            MediaStatus.AVAILABLE ||\n            part.mediaInfo[is4k ? 'status4k' : 'status'] ===\n              MediaStatus.PROCESSING) &&\n          !requestedParts.includes(part.id)\n      )\n      .map((part) => part.id);\n\n    return [...requestedParts, ...availableParts];\n  };\n\n  const isSelectedPart = (tmdbId: number): boolean =>\n    selectedParts.includes(tmdbId);\n\n  const togglePart = (tmdbId: number): void => {\n    // If this part already has a pending request, don't allow it to be toggled\n    if (getAllRequestedParts().includes(tmdbId)) {\n      return;\n    }\n\n    // If there are no more remaining requests available, block toggle\n    if (\n      quota?.movie.limit &&\n      currentlyRemaining <= 0 &&\n      !isSelectedPart(tmdbId)\n    ) {\n      return;\n    }\n\n    if (selectedParts.includes(tmdbId)) {\n      setSelectedParts((parts) => parts.filter((partId) => partId !== tmdbId));\n    } else {\n      setSelectedParts((parts) => [...parts, tmdbId]);\n    }\n  };\n\n  const unrequestedParts = getAllParts().filter(\n    (tmdbId) => !getAllRequestedParts().includes(tmdbId)\n  );\n\n  const toggleAllParts = (): void => {\n    // If the user has a quota and not enough requests for all parts, block toggleAllParts\n    if (\n      quota?.movie.limit &&\n      (quota?.movie.remaining ?? 0) < unrequestedParts.length\n    ) {\n      return;\n    }\n\n    if (\n      data &&\n      selectedParts.length >= 0 &&\n      selectedParts.length < unrequestedParts.length\n    ) {\n      setSelectedParts(unrequestedParts);\n    } else {\n      setSelectedParts([]);\n    }\n  };\n\n  const isAllParts = (): boolean => {\n    if (!data) {\n      return false;\n    }\n\n    return (\n      selectedParts.length ===\n      getAllParts().filter((part) => !getAllRequestedParts().includes(part))\n        .length\n    );\n  };\n\n  const getPartRequest = (tmdbId: number): MediaRequest | undefined => {\n    const part = (data?.parts ?? []).find((part) => part.id === tmdbId);\n\n    return (part?.mediaInfo?.requests ?? []).find(\n      (request) =>\n        request.is4k === is4k &&\n        request.status !== MediaRequestStatus.DECLINED &&\n        request.status !== MediaRequestStatus.COMPLETED\n    );\n  };\n\n  useEffect(() => {\n    if (onUpdating) {\n      onUpdating(isUpdating);\n    }\n  }, [isUpdating, onUpdating]);\n\n  const sendRequest = useCallback(async () => {\n    setIsUpdating(true);\n\n    try {\n      let overrideParams = {};\n      if (requestOverrides) {\n        overrideParams = {\n          serverId: requestOverrides.server,\n          profileId: requestOverrides.profile,\n          rootFolder: requestOverrides.folder,\n          userId: requestOverrides.user?.id,\n          tags: requestOverrides.tags,\n        };\n      }\n\n      await Promise.all(\n        (\n          data?.parts.filter((part) => selectedParts.includes(part.id)) ?? []\n        ).map(async (part) => {\n          await axios.post<MediaRequest>('/api/v1/request', {\n            mediaId: part.id,\n            mediaType: 'movie',\n            is4k,\n            ...overrideParams,\n          });\n        })\n      );\n\n      if (onComplete) {\n        onComplete(\n          selectedParts.length === (data?.parts ?? []).length\n            ? MediaStatus.UNKNOWN\n            : MediaStatus.PARTIALLY_AVAILABLE\n        );\n        mutate('/api/v1/request/count');\n      }\n\n      addToast(\n        <span>\n          {intl.formatMessage(messages.requestSuccess, {\n            title: data?.name,\n            strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n          })}\n        </span>,\n        { appearance: 'success', autoDismiss: true }\n      );\n    } catch {\n      addToast(intl.formatMessage(messages.requesterror), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      setIsUpdating(false);\n    }\n  }, [\n    requestOverrides,\n    data?.parts,\n    data?.name,\n    onComplete,\n    addToast,\n    intl,\n    selectedParts,\n    is4k,\n  ]);\n\n  const hasAutoApprove = hasPermission(\n    [\n      Permission.MANAGE_REQUESTS,\n      is4k ? Permission.AUTO_APPROVE_4K : Permission.AUTO_APPROVE,\n      is4k ? Permission.AUTO_APPROVE_4K_MOVIE : Permission.AUTO_APPROVE_MOVIE,\n    ],\n    { type: 'or' }\n  );\n\n  const blocklistVisibility = hasPermission(\n    [Permission.MANAGE_BLOCKLIST, Permission.VIEW_BLOCKLIST],\n    { type: 'or' }\n  );\n\n  return (\n    <Modal\n      loading={(!data && !error) || !quota}\n      backgroundClickable\n      onCancel={onCancel}\n      onOk={sendRequest}\n      title={intl.formatMessage(\n        is4k\n          ? messages.requestcollection4ktitle\n          : messages.requestcollectiontitle\n      )}\n      subTitle={data?.name}\n      okText={\n        isUpdating\n          ? intl.formatMessage(globalMessages.requesting)\n          : selectedParts.length === 0\n            ? intl.formatMessage(messages.selectmovies)\n            : intl.formatMessage(\n                is4k ? messages.requestmovies4k : messages.requestmovies,\n                {\n                  count: selectedParts.length,\n                }\n              )\n      }\n      okDisabled={selectedParts.length === 0}\n      okButtonType={'primary'}\n      backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}\n    >\n      {hasAutoApprove && !quota?.movie.restricted && (\n        <div className=\"mt-6\">\n          <Alert\n            title={intl.formatMessage(messages.requestadmin)}\n            type=\"info\"\n          />\n        </div>\n      )}\n      {(quota?.movie.limit ?? 0) > 0 && (\n        <QuotaDisplay\n          mediaType=\"movie\"\n          quota={quota?.movie}\n          remaining={currentlyRemaining}\n          userOverride={\n            requestOverrides?.user && requestOverrides.user.id !== user?.id\n              ? requestOverrides?.user?.id\n              : undefined\n          }\n        />\n      )}\n      <div className=\"flex flex-col\">\n        <div className=\"-mx-4 sm:mx-0\">\n          <div className=\"inline-block min-w-full py-2 align-middle\">\n            <div className=\"overflow-hidden border border-gray-700 backdrop-blur sm:rounded-lg\">\n              <table className=\"min-w-full\">\n                <thead>\n                  <tr>\n                    <th className=\"w-16 bg-gray-700/80 px-4 py-3\">\n                      <span\n                        role=\"checkbox\"\n                        tabIndex={0}\n                        aria-checked={isAllParts()}\n                        onClick={() => toggleAllParts()}\n                        onKeyDown={(e) => {\n                          if (e.key === 'Enter' || e.key === 'Space') {\n                            toggleAllParts();\n                          }\n                        }}\n                        className={`relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center pt-2 focus:outline-none ${\n                          quota?.movie.limit &&\n                          (quota.movie.remaining ?? 0) < unrequestedParts.length\n                            ? 'opacity-50'\n                            : ''\n                        }`}\n                      >\n                        <span\n                          aria-hidden=\"true\"\n                          className={`${\n                            isAllParts() ? 'bg-indigo-500' : 'bg-gray-800'\n                          } absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}\n                        />\n                        <span\n                          aria-hidden=\"true\"\n                          className={`${\n                            isAllParts() ? 'translate-x-5' : 'translate-x-0'\n                          } absolute left-0 inline-block h-5 w-5 rounded-full border border-gray-200 bg-white shadow transition-transform duration-200 ease-in-out group-focus:border-blue-300 group-focus:ring`}\n                        />\n                      </span>\n                    </th>\n                    <th className=\"bg-gray-700/80 px-1 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6\">\n                      {intl.formatMessage(globalMessages.movie)}\n                    </th>\n                    <th className=\"bg-gray-700/80 px-2 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6\">\n                      {intl.formatMessage(globalMessages.status)}\n                    </th>\n                  </tr>\n                </thead>\n                <tbody className=\"divide-y divide-gray-700\">\n                  {data?.parts\n                    .filter((part) => {\n                      if (!blocklistVisibility)\n                        return (\n                          part.mediaInfo?.status !== MediaStatus.BLOCKLISTED\n                        );\n                      return part;\n                    })\n                    .map((part) => {\n                      const partRequest = getPartRequest(part.id);\n                      const partMedia =\n                        part.mediaInfo &&\n                        part.mediaInfo[is4k ? 'status4k' : 'status'] !==\n                          MediaStatus.UNKNOWN &&\n                        part.mediaInfo[is4k ? 'status4k' : 'status'] !==\n                          MediaStatus.DELETED\n                          ? part.mediaInfo\n                          : undefined;\n\n                      return (\n                        <tr key={`part-${part.id}`}>\n                          <td\n                            className={`whitespace-nowrap px-4 py-4 text-sm font-medium leading-5 text-gray-100 ${\n                              partMedia?.status === MediaStatus.BLOCKLISTED &&\n                              'pointer-events-none opacity-50'\n                            }`}\n                          >\n                            <span\n                              role=\"checkbox\"\n                              tabIndex={0}\n                              aria-checked={\n                                (!!partMedia &&\n                                  partMedia.status !==\n                                    MediaStatus.BLOCKLISTED) ||\n                                isSelectedPart(part.id)\n                              }\n                              onClick={() => togglePart(part.id)}\n                              onKeyDown={(e) => {\n                                if (e.key === 'Enter' || e.key === 'Space') {\n                                  togglePart(part.id);\n                                }\n                              }}\n                              className={`relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center pt-2 focus:outline-none ${\n                                (!!partMedia &&\n                                  partMedia.status !==\n                                    MediaStatus.BLOCKLISTED) ||\n                                partRequest ||\n                                (quota?.movie.limit &&\n                                  currentlyRemaining <= 0 &&\n                                  !isSelectedPart(part.id))\n                                  ? 'opacity-50'\n                                  : ''\n                              }`}\n                            >\n                              <span\n                                aria-hidden=\"true\"\n                                className={`${\n                                  (!!partMedia &&\n                                    partMedia.status !==\n                                      MediaStatus.BLOCKLISTED) ||\n                                  partRequest ||\n                                  isSelectedPart(part.id)\n                                    ? 'bg-indigo-500'\n                                    : 'bg-gray-700'\n                                } absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}\n                              />\n                              <span\n                                aria-hidden=\"true\"\n                                className={`${\n                                  (!!partMedia &&\n                                    partMedia.status !==\n                                      MediaStatus.BLOCKLISTED) ||\n                                  partRequest ||\n                                  isSelectedPart(part.id)\n                                    ? 'translate-x-5'\n                                    : 'translate-x-0'\n                                } absolute left-0 inline-block h-5 w-5 rounded-full border border-gray-200 bg-white shadow transition-transform duration-200 ease-in-out group-focus:border-blue-300 group-focus:ring`}\n                              />\n                            </span>\n                          </td>\n                          <td\n                            className={`flex items-center px-1 py-4 text-sm font-medium leading-5 text-gray-100 md:px-6 ${\n                              partMedia?.status === MediaStatus.BLOCKLISTED &&\n                              'pointer-events-none opacity-50'\n                            }`}\n                          >\n                            <div className=\"relative h-auto w-10 flex-shrink-0 overflow-hidden rounded-md\">\n                              <CachedImage\n                                type=\"tmdb\"\n                                src={\n                                  part.posterPath\n                                    ? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${part.posterPath}`\n                                    : '/images/seerr_poster_not_found.png'\n                                }\n                                alt=\"\"\n                                sizes=\"100vw\"\n                                style={{\n                                  width: '100%',\n                                  height: 'auto',\n                                  objectFit: 'cover',\n                                }}\n                                width={600}\n                                height={900}\n                              />\n                            </div>\n                            <div className=\"flex flex-col justify-center pl-2\">\n                              <div className=\"text-xs font-medium\">\n                                {part.releaseDate?.slice(0, 4)}\n                              </div>\n                              <div className=\"text-base font-bold\">\n                                {part.title}\n                              </div>\n                            </div>\n                          </td>\n                          <td className=\"whitespace-nowrap py-4 pr-2 text-sm leading-5 text-gray-200 md:px-6\">\n                            {!partMedia && !partRequest && (\n                              <Badge>\n                                {intl.formatMessage(\n                                  globalMessages.notrequested\n                                )}\n                              </Badge>\n                            )}\n                            {!partMedia &&\n                              partRequest?.status ===\n                                MediaRequestStatus.PENDING && (\n                                <Badge badgeType=\"warning\">\n                                  {intl.formatMessage(globalMessages.pending)}\n                                </Badge>\n                              )}\n                            {((!partMedia &&\n                              partRequest?.status ===\n                                MediaRequestStatus.APPROVED) ||\n                              partMedia?.[is4k ? 'status4k' : 'status'] ===\n                                MediaStatus.PROCESSING) && (\n                              <Badge badgeType=\"primary\">\n                                {intl.formatMessage(globalMessages.requested)}\n                              </Badge>\n                            )}\n                            {partMedia?.[is4k ? 'status4k' : 'status'] ===\n                              MediaStatus.AVAILABLE && (\n                              <Badge badgeType=\"success\">\n                                {intl.formatMessage(globalMessages.available)}\n                              </Badge>\n                            )}\n                            {partMedia?.status === MediaStatus.BLOCKLISTED && (\n                              <Badge badgeType=\"danger\">\n                                {intl.formatMessage(globalMessages.blocklisted)}\n                              </Badge>\n                            )}\n                          </td>\n                        </tr>\n                      );\n                    })}\n                </tbody>\n              </table>\n            </div>\n          </div>\n        </div>\n      </div>\n      {(hasPermission(Permission.REQUEST_ADVANCED) ||\n        hasPermission(Permission.MANAGE_REQUESTS)) && (\n        <AdvancedRequester\n          type=\"movie\"\n          is4k={is4k}\n          onChange={(overrides) => {\n            setRequestOverrides(overrides);\n          }}\n        />\n      )}\n    </Modal>\n  );\n};\n\nexport default CollectionRequestModal;\n"
  },
  {
    "path": "src/components/RequestModal/MovieRequestModal.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Modal from '@app/components/Common/Modal';\nimport type { RequestOverrides } from '@app/components/RequestModal/AdvancedRequester';\nimport AdvancedRequester from '@app/components/RequestModal/AdvancedRequester';\nimport QuotaDisplay from '@app/components/RequestModal/QuotaDisplay';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { MediaStatus } from '@server/constants/media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport type { NonFunctionProperties } from '@server/interfaces/api/common';\nimport type { QuotaResponse } from '@server/interfaces/api/userInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport type { MovieDetails } from '@server/models/Movie';\nimport axios from 'axios';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\n\nconst messages = defineMessages('components.RequestModal', {\n  requestadmin: 'This request will be approved automatically.',\n  requestSuccess: '<strong>{title}</strong> requested successfully!',\n  requestCancel: 'Request for <strong>{title}</strong> canceled.',\n  requestmovietitle: 'Request Movie',\n  requestmovie4ktitle: 'Request Movie in 4K',\n  edit: 'Edit Request',\n  approve: 'Approve Request',\n  cancel: 'Cancel Request',\n  pendingrequest: 'Pending Movie Request',\n  pending4krequest: 'Pending 4K Movie Request',\n  requestfrom: \"{username}'s request is pending approval.\",\n  errorediting: 'Something went wrong while editing the request.',\n  requestedited: 'Request for <strong>{title}</strong> edited successfully!',\n  requestApproved: 'Request for <strong>{title}</strong> approved!',\n  requesterror: 'Something went wrong while submitting the request.',\n  pendingapproval: 'Your request is pending approval.',\n});\n\ninterface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> {\n  tmdbId: number;\n  is4k?: boolean;\n  editRequest?: NonFunctionProperties<MediaRequest>;\n  onCancel?: () => void;\n  onComplete?: (newStatus: MediaStatus) => void;\n  onUpdating?: (isUpdating: boolean) => void;\n}\n\nconst MovieRequestModal = ({\n  onCancel,\n  onComplete,\n  tmdbId,\n  onUpdating,\n  editRequest,\n  is4k = false,\n}: RequestModalProps) => {\n  const [isUpdating, setIsUpdating] = useState(false);\n  const [requestOverrides, setRequestOverrides] =\n    useState<RequestOverrides | null>(null);\n  const { addToast } = useToasts();\n  const { data, error } = useSWR<MovieDetails>(`/api/v1/movie/${tmdbId}`, {\n    revalidateOnMount: true,\n  });\n  const intl = useIntl();\n  const { user, hasPermission } = useUser();\n  const { data: quota } = useSWR<QuotaResponse>(\n    user &&\n      (!requestOverrides?.user?.id || hasPermission(Permission.MANAGE_USERS))\n      ? `/api/v1/user/${requestOverrides?.user?.id ?? user.id}/quota`\n      : null\n  );\n\n  useEffect(() => {\n    if (onUpdating) {\n      onUpdating(isUpdating);\n    }\n  }, [isUpdating, onUpdating]);\n\n  const sendRequest = useCallback(async () => {\n    setIsUpdating(true);\n\n    try {\n      let overrideParams = {};\n      if (requestOverrides) {\n        overrideParams = {\n          serverId: requestOverrides.server,\n          profileId: requestOverrides.profile,\n          rootFolder: requestOverrides.folder,\n          userId: requestOverrides.user?.id,\n          tags: requestOverrides.tags,\n        };\n      }\n      const response = await axios.post<MediaRequest>('/api/v1/request', {\n        mediaId: data?.id,\n        mediaType: 'movie',\n        is4k,\n        ...overrideParams,\n      });\n      mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');\n      mutate('/api/v1/request/count');\n\n      if (response.data) {\n        if (onComplete) {\n          onComplete(\n            hasPermission(\n              is4k ? Permission.AUTO_APPROVE_4K : Permission.AUTO_APPROVE\n            ) ||\n              hasPermission(\n                is4k\n                  ? Permission.AUTO_APPROVE_4K_MOVIE\n                  : Permission.AUTO_APPROVE_MOVIE\n              )\n              ? MediaStatus.PROCESSING\n              : MediaStatus.PENDING\n          );\n        }\n        addToast(\n          <span>\n            {intl.formatMessage(messages.requestSuccess, {\n              title: data?.title,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'success', autoDismiss: true }\n        );\n      }\n    } catch {\n      addToast(intl.formatMessage(messages.requesterror), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      setIsUpdating(false);\n    }\n  }, [\n    requestOverrides,\n    data?.id,\n    data?.title,\n    is4k,\n    onComplete,\n    addToast,\n    intl,\n    hasPermission,\n  ]);\n\n  const cancelRequest = async () => {\n    setIsUpdating(true);\n\n    try {\n      const response = await axios.delete<MediaRequest>(\n        `/api/v1/request/${editRequest?.id}`\n      );\n      mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');\n      mutate('/api/v1/request/count');\n\n      if (response.status === 204) {\n        if (onComplete) {\n          onComplete(MediaStatus.UNKNOWN);\n        }\n        addToast(\n          <span>\n            {intl.formatMessage(messages.requestCancel, {\n              title: data?.title,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'success', autoDismiss: true }\n        );\n      }\n    } catch {\n      setIsUpdating(false);\n    }\n  };\n\n  const updateRequest = async (alsoApproveRequest = false) => {\n    setIsUpdating(true);\n\n    try {\n      await axios.put(`/api/v1/request/${editRequest?.id}`, {\n        mediaType: 'movie',\n        serverId: requestOverrides?.server,\n        profileId: requestOverrides?.profile,\n        rootFolder: requestOverrides?.folder,\n        userId: requestOverrides?.user?.id,\n        tags: requestOverrides?.tags,\n      });\n\n      if (alsoApproveRequest) {\n        await axios.post(`/api/v1/request/${editRequest?.id}/approve`);\n      }\n      mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');\n      mutate('/api/v1/request/count');\n\n      addToast(\n        <span>\n          {intl.formatMessage(\n            alsoApproveRequest\n              ? messages.requestApproved\n              : messages.requestedited,\n            {\n              title: data?.title,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            }\n          )}\n        </span>,\n        {\n          appearance: 'success',\n          autoDismiss: true,\n        }\n      );\n\n      if (onComplete) {\n        onComplete(MediaStatus.PENDING);\n      }\n    } catch {\n      addToast(<span>{intl.formatMessage(messages.errorediting)}</span>, {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      setIsUpdating(false);\n    }\n  };\n\n  if (editRequest) {\n    const isOwner = editRequest.requestedBy.id === user?.id;\n\n    return (\n      <Modal\n        loading={!data && !error}\n        backgroundClickable\n        onCancel={onCancel}\n        title={intl.formatMessage(\n          is4k ? messages.pending4krequest : messages.pendingrequest\n        )}\n        subTitle={data?.title}\n        onOk={() =>\n          hasPermission(Permission.MANAGE_REQUESTS)\n            ? updateRequest(true)\n            : hasPermission(Permission.REQUEST_ADVANCED)\n              ? updateRequest()\n              : cancelRequest()\n        }\n        okDisabled={isUpdating}\n        okText={\n          hasPermission(Permission.MANAGE_REQUESTS)\n            ? intl.formatMessage(messages.approve)\n            : hasPermission(Permission.REQUEST_ADVANCED)\n              ? intl.formatMessage(messages.edit)\n              : intl.formatMessage(messages.cancel)\n        }\n        okButtonType={\n          hasPermission(Permission.MANAGE_REQUESTS)\n            ? 'success'\n            : hasPermission(Permission.REQUEST_ADVANCED)\n              ? 'primary'\n              : 'danger'\n        }\n        onSecondary={\n          isOwner &&\n          hasPermission(\n            [Permission.REQUEST_ADVANCED, Permission.MANAGE_REQUESTS],\n            { type: 'or' }\n          )\n            ? () => cancelRequest()\n            : undefined\n        }\n        secondaryDisabled={isUpdating}\n        secondaryText={\n          isOwner &&\n          hasPermission(\n            [Permission.REQUEST_ADVANCED, Permission.MANAGE_REQUESTS],\n            { type: 'or' }\n          )\n            ? intl.formatMessage(messages.cancel)\n            : undefined\n        }\n        secondaryButtonType=\"danger\"\n        cancelText={intl.formatMessage(globalMessages.close)}\n        backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}\n      >\n        {isOwner\n          ? intl.formatMessage(messages.pendingapproval)\n          : intl.formatMessage(messages.requestfrom, {\n              username: editRequest.requestedBy.displayName,\n            })}\n        {(hasPermission(Permission.REQUEST_ADVANCED) ||\n          hasPermission(Permission.MANAGE_REQUESTS)) && (\n          <AdvancedRequester\n            type=\"movie\"\n            is4k={is4k}\n            requestUser={editRequest.requestedBy}\n            defaultOverrides={{\n              folder: editRequest.rootFolder,\n              profile: editRequest.profileId,\n              server: editRequest.serverId,\n              tags: editRequest.tags,\n            }}\n            onChange={(overrides) => {\n              setRequestOverrides(overrides);\n            }}\n          />\n        )}\n      </Modal>\n    );\n  }\n\n  const hasAutoApprove = hasPermission(\n    [\n      Permission.MANAGE_REQUESTS,\n      is4k ? Permission.AUTO_APPROVE_4K : Permission.AUTO_APPROVE,\n      is4k ? Permission.AUTO_APPROVE_4K_MOVIE : Permission.AUTO_APPROVE_MOVIE,\n    ],\n    { type: 'or' }\n  );\n\n  return (\n    <Modal\n      loading={(!data && !error) || !quota}\n      backgroundClickable\n      onCancel={onCancel}\n      onOk={sendRequest}\n      okDisabled={isUpdating || quota?.movie.restricted}\n      title={intl.formatMessage(\n        is4k ? messages.requestmovie4ktitle : messages.requestmovietitle\n      )}\n      subTitle={data?.title}\n      okText={\n        isUpdating\n          ? intl.formatMessage(globalMessages.requesting)\n          : intl.formatMessage(\n              is4k ? globalMessages.request4k : globalMessages.request\n            )\n      }\n      okButtonType={'primary'}\n      backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}\n    >\n      {hasAutoApprove && !quota?.movie.restricted && (\n        <div className=\"mt-6\">\n          <Alert\n            title={intl.formatMessage(messages.requestadmin)}\n            type=\"info\"\n          />\n        </div>\n      )}\n      {(quota?.movie.limit ?? 0) > 0 && (\n        <QuotaDisplay\n          mediaType=\"movie\"\n          quota={quota?.movie}\n          userOverride={\n            requestOverrides?.user && requestOverrides.user.id !== user?.id\n              ? requestOverrides?.user?.id\n              : undefined\n          }\n        />\n      )}\n      {(hasPermission(Permission.REQUEST_ADVANCED) ||\n        hasPermission(Permission.MANAGE_REQUESTS)) && (\n        <AdvancedRequester\n          type=\"movie\"\n          is4k={is4k}\n          onChange={(overrides) => {\n            setRequestOverrides(overrides);\n          }}\n        />\n      )}\n    </Modal>\n  );\n};\n\nexport default MovieRequestModal;\n"
  },
  {
    "path": "src/components/RequestModal/QuotaDisplay/index.tsx",
    "content": "import ProgressCircle from '@app/components/Common/ProgressCircle';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/solid';\nimport type { QuotaStatus } from '@server/interfaces/api/userInterfaces';\nimport Link from 'next/link';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.RequestModal.QuotaDisplay', {\n  requestsremaining:\n    '{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {request} other {requests}} remaining',\n  movielimit: '{limit, plural, one {movie} other {movies}}',\n  seasonlimit: '{limit, plural, one {season} other {seasons}}',\n  allowedRequests:\n    'You are allowed to request <strong>{limit}</strong> {type} every <strong>{days}</strong> days.',\n  allowedRequestsUser:\n    'This user is allowed to request <strong>{limit}</strong> {type} every <strong>{days}</strong> days.',\n  quotaLink:\n    'You can view a summary of your request limits on your <ProfileLink>profile page</ProfileLink>.',\n  quotaLinkUser:\n    \"You can view a summary of this user's request limits on their <ProfileLink>profile page</ProfileLink>.\",\n  movie: 'movie',\n  season: 'season',\n  notenoughseasonrequests: 'Not enough season requests remaining',\n  requiredquota:\n    'You need to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.',\n  requiredquotaUser:\n    'This user needs to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.',\n});\n\ninterface QuotaDisplayProps {\n  quota?: QuotaStatus;\n  mediaType: 'movie' | 'tv';\n  userOverride?: number | null;\n  remaining?: number;\n  overLimit?: number;\n}\n\nconst QuotaDisplay = ({\n  quota,\n  mediaType,\n  userOverride,\n  remaining,\n  overLimit,\n}: QuotaDisplayProps) => {\n  const intl = useIntl();\n  const [showDetails, setShowDetails] = useState(false);\n  return (\n    <div\n      className=\"my-4 flex flex-col rounded-md border border-gray-700 p-4 backdrop-blur\"\n      onClick={() => setShowDetails((s) => !s)}\n      onKeyDown={(e) => {\n        if (e.key === 'Enter') {\n          setShowDetails((s) => !s);\n        }\n      }}\n      role=\"button\"\n      tabIndex={0}\n    >\n      <div className=\"flex items-center\">\n        <ProgressCircle\n          className=\"h-8 w-8\"\n          progress={Math.round(\n            ((remaining ?? quota?.remaining ?? 0) / (quota?.limit ?? 1)) * 100\n          )}\n          useHeatLevel\n        />\n        <div\n          className={`flex items-end ${\n            (remaining ?? quota?.remaining ?? 0) <= 0 || quota?.restricted\n              ? 'text-red-500'\n              : ''\n          }`}\n        >\n          <div className=\"ml-2 text-lg\">\n            {overLimit !== undefined\n              ? intl.formatMessage(messages.notenoughseasonrequests)\n              : intl.formatMessage(messages.requestsremaining, {\n                  remaining: remaining ?? quota?.remaining ?? 0,\n                  type: intl.formatMessage(\n                    mediaType === 'movie' ? messages.movie : messages.season\n                  ),\n                  strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n                })}\n          </div>\n        </div>\n        <div className=\"flex flex-1 justify-end\">\n          {showDetails ? (\n            <ChevronUpIcon className=\"h-6 w-6\" />\n          ) : (\n            <ChevronDownIcon className=\"h-6 w-6\" />\n          )}\n        </div>\n      </div>\n      {showDetails && (\n        <div className=\"mt-4\">\n          {overLimit !== undefined && (\n            <div className=\"mb-2\">\n              {intl.formatMessage(\n                userOverride\n                  ? messages.requiredquotaUser\n                  : messages.requiredquota,\n                {\n                  seasons: overLimit,\n                  strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n                }\n              )}\n            </div>\n          )}\n          <div>\n            {intl.formatMessage(\n              userOverride\n                ? messages.allowedRequestsUser\n                : messages.allowedRequests,\n              {\n                limit: quota?.limit,\n                days: quota?.days,\n                type: intl.formatMessage(\n                  mediaType === 'movie'\n                    ? messages.movielimit\n                    : messages.seasonlimit,\n                  { limit: quota?.limit }\n                ),\n                strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n              }\n            )}\n          </div>\n          <div className=\"mt-2\">\n            {intl.formatMessage(\n              userOverride ? messages.quotaLinkUser : messages.quotaLink,\n              {\n                ProfileLink: (msg: React.ReactNode) => (\n                  <Link\n                    href={userOverride ? `/users/${userOverride}` : '/profile'}\n                    className=\"text-white transition duration-300 hover:underline\"\n                  >\n                    {msg}\n                  </Link>\n                ),\n              }\n            )}\n          </div>\n        </div>\n      )}\n    </div>\n  );\n};\n\nexport default QuotaDisplay;\n"
  },
  {
    "path": "src/components/RequestModal/SearchByNameModal/index.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport Modal from '@app/components/Common/Modal';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { SonarrSeries } from '@server/api/servarr/sonarr';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.RequestModal.SearchByNameModal', {\n  notvdbiddescription:\n    'We were unable to automatically match this series. Please select the correct match below.',\n  nomatches: 'We were unable to find a match for this series.',\n});\n\ninterface SearchByNameModalProps {\n  setTvdbId: (id: number) => void;\n  tvdbId: number | undefined;\n  onCancel?: () => void;\n  closeModal: () => void;\n  modalTitle: string;\n  modalSubTitle: string;\n  tmdbId: number;\n  backdrop?: string;\n}\n\nconst SearchByNameModal = ({\n  setTvdbId,\n  tvdbId,\n  onCancel,\n  closeModal,\n  modalTitle,\n  modalSubTitle,\n  tmdbId,\n  backdrop,\n}: SearchByNameModalProps) => {\n  const intl = useIntl();\n  const { data, error } = useSWR<SonarrSeries[]>(\n    `/api/v1/service/sonarr/lookup/${tmdbId}`\n  );\n\n  const handleClick = (tvdbId: number) => {\n    setTvdbId(tvdbId);\n  };\n\n  if ((data ?? []).length === 0 || error) {\n    return (\n      <Modal\n        loading={!data && !error}\n        backgroundClickable\n        onOk={onCancel}\n        title={modalTitle}\n        subTitle={modalSubTitle}\n        okText={intl.formatMessage(globalMessages.close)}\n        okButtonType=\"primary\"\n        backdrop={backdrop}\n      >\n        <Alert title={intl.formatMessage(messages.nomatches)} type=\"info\" />\n      </Modal>\n    );\n  }\n\n  return (\n    <Modal\n      backgroundClickable\n      onCancel={onCancel}\n      onOk={closeModal}\n      title={modalTitle}\n      subTitle={modalSubTitle}\n      okText={intl.formatMessage(globalMessages.next)}\n      okDisabled={!tvdbId}\n      okButtonType=\"primary\"\n      backdrop={backdrop}\n    >\n      <Alert\n        title={intl.formatMessage(messages.notvdbiddescription)}\n        type=\"info\"\n      />\n      <div className=\"grid grid-cols-1 gap-4 pb-2 md:grid-cols-2\">\n        {data?.slice(0, 6).map((item) => (\n          <button\n            key={item.tvdbId}\n            className=\"container mx-auto flex h-40 scale-100 transform-gpu cursor-pointer flex-col items-center justify-center space-y-4 rounded-xl outline-none transition hover:scale-105 focus:outline-none focus:ring focus:ring-indigo-500 focus:ring-opacity-70\"\n            onClick={() => handleClick(item.tvdbId)}\n          >\n            <div\n              className={`flex h-40 w-full items-center overflow-hidden rounded-xl border border-gray-700 bg-gray-700/20 p-2 shadow backdrop-blur transition ${\n                tvdbId === item.tvdbId ? 'ring ring-indigo-500' : ''\n              } `}\n            >\n              <div className=\"relative flex w-24 flex-none items-center space-x-4 self-stretch\">\n                <CachedImage\n                  type=\"tvdb\"\n                  src={\n                    item.remotePoster ?? '/images/seerr_poster_not_found.png'\n                  }\n                  alt={item.title}\n                  className=\"w-100 h-auto rounded-md\"\n                  fill\n                />\n              </div>\n              <div className=\"flex-grow self-start p-3 text-left\">\n                <div className=\"text-sm font-medium leading-tight\">\n                  {item.year}\n                </div>\n                <div\n                  className=\"text-grey-200 text-xl font-bold leading-tight\"\n                  style={{\n                    WebkitLineClamp: 1,\n                    display: '-webkit-box',\n                    overflow: 'hidden',\n                    WebkitBoxOrient: 'vertical',\n                    wordBreak: 'break-word',\n                  }}\n                >\n                  {item.title}\n                </div>\n                {item.overview && (\n                  <div\n                    className=\"whitespace-normal text-xs text-gray-400\"\n                    style={{\n                      WebkitLineClamp: 5,\n                      display: '-webkit-box',\n                      overflow: 'hidden',\n                      WebkitBoxOrient: 'vertical',\n                      wordBreak: 'break-word',\n                    }}\n                  >\n                    {item.overview}\n                  </div>\n                )}\n              </div>\n            </div>\n          </button>\n        ))}\n      </div>\n    </Modal>\n  );\n};\n\nexport default SearchByNameModal;\n"
  },
  {
    "path": "src/components/RequestModal/TvRequestModal.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Badge from '@app/components/Common/Badge';\nimport Modal from '@app/components/Common/Modal';\nimport type { RequestOverrides } from '@app/components/RequestModal/AdvancedRequester';\nimport AdvancedRequester from '@app/components/RequestModal/AdvancedRequester';\nimport QuotaDisplay from '@app/components/RequestModal/QuotaDisplay';\nimport SearchByNameModal from '@app/components/RequestModal/SearchByNameModal';\nimport useSettings from '@app/hooks/useSettings';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants';\nimport { MediaRequestStatus, MediaStatus } from '@server/constants/media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport type SeasonRequest from '@server/entity/SeasonRequest';\nimport type { NonFunctionProperties } from '@server/interfaces/api/common';\nimport type { QuotaResponse } from '@server/interfaces/api/userInterfaces';\nimport { Permission } from '@server/lib/permissions';\nimport type { TvDetails } from '@server/models/Tv';\nimport axios from 'axios';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\n\nconst messages = defineMessages('components.RequestModal', {\n  requestadmin: 'This request will be approved automatically.',\n  requestSuccess: '<strong>{title}</strong> requested successfully!',\n  requestseriestitle: 'Request Series',\n  requestseries4ktitle: 'Request Series in 4K',\n  edit: 'Edit Request',\n  approve: 'Approve Request',\n  cancel: 'Cancel Request',\n  pendingrequest: 'Pending Request',\n  pending4krequest: 'Pending 4K Request',\n  requestfrom: \"{username}'s request is pending approval.\",\n  requestseasons:\n    'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}',\n  requestseasons4k:\n    'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}} in 4K',\n  alreadyrequested: 'Already Requested',\n  selectseason: 'Select Season(s)',\n  season: 'Season',\n  numberofepisodes: '# of Episodes',\n  seasonnumber: 'Season {number}',\n  errorediting: 'Something went wrong while editing the request.',\n  requestedited: 'Request for <strong>{title}</strong> edited successfully!',\n  requestApproved: 'Request for <strong>{title}</strong> approved!',\n  requestcancelled: 'Request for <strong>{title}</strong> canceled.',\n  autoapproval: 'Automatic Approval',\n  requesterror: 'Something went wrong while submitting the request.',\n  pendingapproval: 'Your request is pending approval.',\n});\n\ninterface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> {\n  tmdbId: number;\n  onCancel?: () => void;\n  onComplete?: (newStatus: MediaStatus) => void;\n  onUpdating?: (isUpdating: boolean) => void;\n  is4k?: boolean;\n  editRequest?: NonFunctionProperties<MediaRequest>;\n}\n\nconst TvRequestModal = ({\n  onCancel,\n  onComplete,\n  tmdbId,\n  onUpdating,\n  editRequest,\n  is4k = false,\n}: RequestModalProps) => {\n  const settings = useSettings();\n  const { addToast } = useToasts();\n  const editingSeasons: number[] = (editRequest?.seasons ?? []).map(\n    (season) => season.seasonNumber\n  );\n  const { data, error } = useSWR<TvDetails>(`/api/v1/tv/${tmdbId}`);\n  const [requestOverrides, setRequestOverrides] =\n    useState<RequestOverrides | null>(null);\n  const [selectedSeasons, setSelectedSeasons] = useState<number[]>(\n    editRequest ? editingSeasons : []\n  );\n  const intl = useIntl();\n  const { user, hasPermission } = useUser();\n  const [searchModal, setSearchModal] = useState<{\n    show: boolean;\n  }>({\n    show: true,\n  });\n  const [tvdbId, setTvdbId] = useState<number | undefined>(undefined);\n  const { data: quota } = useSWR<QuotaResponse>(\n    user &&\n      (!requestOverrides?.user?.id || hasPermission(Permission.MANAGE_USERS))\n      ? `/api/v1/user/${requestOverrides?.user?.id ?? user.id}/quota`\n      : null\n  );\n\n  const currentlyRemaining =\n    (quota?.tv.remaining ?? 0) -\n    selectedSeasons.length +\n    (editRequest?.seasons ?? []).length;\n\n  const updateRequest = async (alsoApproveRequest = false) => {\n    if (!editRequest) {\n      return;\n    }\n\n    if (onUpdating) {\n      onUpdating(true);\n      mutate('/api/v1/request/count');\n    }\n\n    try {\n      if (selectedSeasons.length > 0) {\n        await axios.put(`/api/v1/request/${editRequest.id}`, {\n          mediaType: 'tv',\n          serverId: requestOverrides?.server,\n          profileId: requestOverrides?.profile,\n          rootFolder: requestOverrides?.folder,\n          languageProfileId: requestOverrides?.language,\n          userId: requestOverrides?.user?.id,\n          tags: requestOverrides?.tags,\n          seasons: selectedSeasons.sort((a, b) => a - b),\n        });\n\n        if (alsoApproveRequest) {\n          await axios.post(`/api/v1/request/${editRequest.id}/approve`);\n        }\n      } else {\n        await axios.delete(`/api/v1/request/${editRequest.id}`);\n      }\n      mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');\n      mutate('/api/v1/request/count');\n\n      addToast(\n        <span>\n          {selectedSeasons.length > 0\n            ? intl.formatMessage(\n                alsoApproveRequest\n                  ? messages.requestApproved\n                  : messages.requestedited,\n                {\n                  title: data?.name,\n                  strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n                }\n              )\n            : intl.formatMessage(messages.requestcancelled, {\n                title: data?.name,\n                strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n              })}\n        </span>,\n        {\n          appearance: 'success',\n          autoDismiss: true,\n        }\n      );\n      if (onComplete) {\n        onComplete(MediaStatus.PENDING);\n      }\n    } catch {\n      addToast(<span>{intl.formatMessage(messages.errorediting)}</span>, {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      if (onUpdating) {\n        onUpdating(false);\n      }\n    }\n  };\n\n  const sendRequest = async () => {\n    if (\n      settings.currentSettings.partialRequestsEnabled &&\n      selectedSeasons.length === 0\n    ) {\n      return;\n    }\n\n    if (onUpdating) {\n      onUpdating(true);\n      mutate('/api/v1/request/count');\n    }\n\n    try {\n      let overrideParams = {};\n      if (requestOverrides) {\n        overrideParams = {\n          serverId: requestOverrides.server,\n          profileId: requestOverrides.profile,\n          rootFolder: requestOverrides.folder,\n          languageProfileId: requestOverrides.language,\n          userId: requestOverrides?.user?.id,\n          tags: requestOverrides.tags,\n        };\n      }\n      const response = await axios.post<MediaRequest>('/api/v1/request', {\n        mediaId: data?.id,\n        tvdbId: tvdbId ?? data?.externalIds.tvdbId,\n        mediaType: 'tv',\n        is4k,\n        seasons: settings.currentSettings.partialRequestsEnabled\n          ? selectedSeasons.sort((a, b) => a - b)\n          : getAllSeasons().filter(\n              (season) =>\n                !getAllRequestedSeasons().includes(season) && season !== 0\n            ),\n        ...overrideParams,\n      });\n      mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');\n\n      if (response.data) {\n        if (onComplete) {\n          onComplete(response.data.media.status);\n        }\n        addToast(\n          <span>\n            {intl.formatMessage(messages.requestSuccess, {\n              title: data?.name,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'success', autoDismiss: true }\n        );\n      }\n    } catch {\n      addToast(intl.formatMessage(messages.requesterror), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      if (onUpdating) {\n        onUpdating(false);\n      }\n    }\n  };\n\n  const getAllSeasons = (): number[] => {\n    let allSeasons = (data?.seasons ?? []).filter(\n      (season) => season.episodeCount !== 0\n    );\n    if (!settings.currentSettings.enableSpecialEpisodes) {\n      allSeasons = allSeasons.filter((season) => season.seasonNumber > 0);\n    }\n    return allSeasons.map((season) => season.seasonNumber);\n  };\n\n  const getAllRequestedSeasons = (): number[] => {\n    const requestedSeasons = (data?.mediaInfo?.requests ?? [])\n      .filter(\n        (request) =>\n          request.is4k === is4k &&\n          request.status !== MediaRequestStatus.DECLINED &&\n          request.status !== MediaRequestStatus.COMPLETED\n      )\n      .reduce((requestedSeasons, request) => {\n        return [\n          ...requestedSeasons,\n          ...request.seasons\n            .filter((season) => !editingSeasons.includes(season.seasonNumber))\n            .map((sr) => sr.seasonNumber),\n        ];\n      }, [] as number[]);\n\n    const availableSeasons = (data?.mediaInfo?.seasons ?? [])\n      .filter(\n        (season) =>\n          (season[is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE ||\n            season[is4k ? 'status4k' : 'status'] ===\n              MediaStatus.PARTIALLY_AVAILABLE ||\n            season[is4k ? 'status4k' : 'status'] === MediaStatus.PROCESSING) &&\n          !requestedSeasons.includes(season.seasonNumber)\n      )\n      .map((season) => season.seasonNumber);\n\n    return [...requestedSeasons, ...availableSeasons];\n  };\n\n  const isSelectedSeason = (seasonNumber: number): boolean =>\n    selectedSeasons.includes(seasonNumber);\n\n  const toggleSeason = (seasonNumber: number): void => {\n    // If this season already has a pending request, don't allow it to be toggled\n    if (getAllRequestedSeasons().includes(seasonNumber)) {\n      return;\n    }\n\n    // If there are no more remaining requests available, block toggle\n    if (\n      quota?.tv.limit &&\n      currentlyRemaining <= 0 &&\n      !isSelectedSeason(seasonNumber)\n    ) {\n      return;\n    }\n\n    if (selectedSeasons.includes(seasonNumber)) {\n      setSelectedSeasons((seasons) =>\n        seasons.filter((sn) => sn !== seasonNumber)\n      );\n    } else {\n      setSelectedSeasons((seasons) => [...seasons, seasonNumber]);\n    }\n  };\n\n  const unrequestedSeasons = getAllSeasons().filter((season) =>\n    !settings.currentSettings.partialRequestsEnabled\n      ? !getAllRequestedSeasons().includes(season) && season !== 0\n      : !getAllRequestedSeasons().includes(season)\n  );\n\n  const toggleAllSeasons = (): void => {\n    // If the user has a quota and not enough requests for all seasons, block toggleAllSeasons\n    if (\n      quota?.tv.limit &&\n      (quota?.tv.remaining ?? 0) < unrequestedSeasons.length\n    ) {\n      return;\n    }\n\n    const standardUnrequestedSeasons = unrequestedSeasons.filter(\n      (seasonNumber) => seasonNumber !== 0\n    );\n\n    if (\n      data &&\n      selectedSeasons.length >= 0 &&\n      selectedSeasons.length < standardUnrequestedSeasons.length\n    ) {\n      setSelectedSeasons(standardUnrequestedSeasons);\n    } else {\n      setSelectedSeasons([]);\n    }\n  };\n\n  const isAllSeasons = (): boolean => {\n    if (!data) {\n      return false;\n    }\n    return (\n      selectedSeasons.filter((season) => season !== 0).length ===\n      getAllSeasons().filter(\n        (season) => !getAllRequestedSeasons().includes(season) && season !== 0\n      ).length\n    );\n  };\n\n  const getSeasonRequest = (\n    seasonNumber: number\n  ): SeasonRequest | undefined => {\n    let seasonRequest: SeasonRequest | undefined;\n\n    if (\n      data?.mediaInfo &&\n      (data.mediaInfo.requests || []).filter(\n        (request) =>\n          request.is4k === is4k &&\n          request.status !== MediaRequestStatus.DECLINED &&\n          request.status !== MediaRequestStatus.COMPLETED\n      ).length > 0\n    ) {\n      data.mediaInfo.requests\n        .filter(\n          (request) =>\n            request.is4k === is4k &&\n            request.status !== MediaRequestStatus.DECLINED &&\n            request.status !== MediaRequestStatus.COMPLETED\n        )\n        .forEach((request) => {\n          if (!seasonRequest) {\n            seasonRequest = request.seasons.find(\n              (season) =>\n                season.seasonNumber === seasonNumber &&\n                season.status !== MediaRequestStatus.COMPLETED\n            );\n          }\n        });\n    }\n\n    return seasonRequest;\n  };\n\n  const isOwner = editRequest && editRequest.requestedBy.id === user?.id;\n\n  return data && !error && !data.externalIds.tvdbId && searchModal.show ? (\n    <SearchByNameModal\n      tvdbId={tvdbId}\n      setTvdbId={setTvdbId}\n      closeModal={() => setSearchModal({ show: false })}\n      onCancel={onCancel}\n      modalTitle={intl.formatMessage(\n        is4k ? messages.requestseries4ktitle : messages.requestseriestitle\n      )}\n      modalSubTitle={data.name}\n      tmdbId={tmdbId}\n      backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}\n    />\n  ) : (\n    <Modal\n      loading={!data && !error}\n      backgroundClickable\n      onCancel={tvdbId ? () => setSearchModal({ show: true }) : onCancel}\n      onOk={() =>\n        editRequest\n          ? hasPermission(Permission.MANAGE_REQUESTS)\n            ? updateRequest(true)\n            : updateRequest()\n          : sendRequest()\n      }\n      title={intl.formatMessage(\n        editRequest\n          ? is4k\n            ? messages.pending4krequest\n            : messages.pendingrequest\n          : is4k\n            ? messages.requestseries4ktitle\n            : messages.requestseriestitle\n      )}\n      subTitle={data?.name}\n      okText={\n        editRequest\n          ? selectedSeasons.length === 0\n            ? intl.formatMessage(messages.cancel)\n            : hasPermission(Permission.MANAGE_REQUESTS)\n              ? intl.formatMessage(messages.approve)\n              : intl.formatMessage(messages.edit)\n          : getAllRequestedSeasons().length >= getAllSeasons().length\n            ? intl.formatMessage(messages.alreadyrequested)\n            : !settings.currentSettings.partialRequestsEnabled\n              ? intl.formatMessage(\n                  is4k ? globalMessages.request4k : globalMessages.request\n                )\n              : selectedSeasons.length === 0\n                ? intl.formatMessage(messages.selectseason)\n                : intl.formatMessage(\n                    is4k ? messages.requestseasons4k : messages.requestseasons,\n                    {\n                      seasonCount: selectedSeasons.length,\n                    }\n                  )\n      }\n      okDisabled={\n        editRequest\n          ? false\n          : !settings.currentSettings.partialRequestsEnabled &&\n              quota?.tv.limit &&\n              unrequestedSeasons.length > quota.tv.limit\n            ? true\n            : getAllRequestedSeasons().length >= getAllSeasons().length ||\n              (settings.currentSettings.partialRequestsEnabled &&\n                selectedSeasons.length === 0)\n      }\n      okButtonType={\n        editRequest\n          ? settings.currentSettings.partialRequestsEnabled &&\n            selectedSeasons.length === 0\n            ? 'danger'\n            : hasPermission(Permission.MANAGE_REQUESTS)\n              ? 'success'\n              : 'primary'\n          : 'primary'\n      }\n      cancelText={\n        editRequest\n          ? intl.formatMessage(globalMessages.close)\n          : tvdbId\n            ? intl.formatMessage(globalMessages.back)\n            : intl.formatMessage(globalMessages.cancel)\n      }\n      backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}\n    >\n      {editRequest\n        ? isOwner\n          ? intl.formatMessage(messages.pendingapproval)\n          : intl.formatMessage(messages.requestfrom, {\n              username: editRequest?.requestedBy.displayName,\n            })\n        : null}\n      {hasPermission(\n        [\n          Permission.MANAGE_REQUESTS,\n          is4k ? Permission.AUTO_APPROVE_4K : Permission.AUTO_APPROVE,\n          is4k ? Permission.AUTO_APPROVE_4K_TV : Permission.AUTO_APPROVE_TV,\n        ],\n        { type: 'or' }\n      ) &&\n        !(\n          quota?.tv.limit &&\n          !settings.currentSettings.partialRequestsEnabled &&\n          unrequestedSeasons.length > (quota?.tv.remaining ?? 0)\n        ) &&\n        getAllRequestedSeasons().length < getAllSeasons().length &&\n        !editRequest && (\n          <p className=\"mt-6\">\n            <Alert\n              title={intl.formatMessage(messages.requestadmin)}\n              type=\"info\"\n            />\n          </p>\n        )}\n      {(quota?.tv.limit ?? 0) > 0 && (\n        <QuotaDisplay\n          mediaType=\"tv\"\n          quota={quota?.tv}\n          remaining={\n            !settings.currentSettings.partialRequestsEnabled &&\n            unrequestedSeasons.length > (quota?.tv.remaining ?? 0)\n              ? 0\n              : currentlyRemaining\n          }\n          userOverride={\n            requestOverrides?.user && requestOverrides.user.id !== user?.id\n              ? requestOverrides?.user?.id\n              : undefined\n          }\n          overLimit={\n            !settings.currentSettings.partialRequestsEnabled &&\n            unrequestedSeasons.length > (quota?.tv.remaining ?? 0)\n              ? unrequestedSeasons.length\n              : undefined\n          }\n        />\n      )}\n      <div className=\"flex flex-col\">\n        <div className=\"-mx-4 sm:mx-0\">\n          <div className=\"inline-block min-w-full py-2 align-middle\">\n            <div className=\"overflow-hidden border border-gray-700 shadow backdrop-blur sm:rounded-lg\">\n              <table className=\"min-w-full\">\n                <thead>\n                  <tr>\n                    <th\n                      className={`w-16 bg-gray-700/80 px-4 py-3 ${\n                        !settings.currentSettings.partialRequestsEnabled &&\n                        'hidden'\n                      }`}\n                    >\n                      <span\n                        role=\"checkbox\"\n                        tabIndex={0}\n                        aria-checked={isAllSeasons()}\n                        onClick={() => toggleAllSeasons()}\n                        onKeyDown={(e) => {\n                          if (e.key === 'Enter' || e.key === 'Space') {\n                            toggleAllSeasons();\n                          }\n                        }}\n                        className={`relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center pt-2 focus:outline-none ${\n                          quota?.tv.remaining &&\n                          quota.tv.limit &&\n                          quota.tv.remaining < unrequestedSeasons.length\n                            ? 'opacity-50'\n                            : ''\n                        }`}\n                      >\n                        <span\n                          aria-hidden=\"true\"\n                          className={`${\n                            isAllSeasons() ? 'bg-indigo-500' : 'bg-gray-800'\n                          } absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}\n                        />\n                        <span\n                          aria-hidden=\"true\"\n                          className={`${\n                            isAllSeasons() ? 'translate-x-5' : 'translate-x-0'\n                          } absolute left-0 inline-block h-5 w-5 rounded-full border border-gray-200 bg-white shadow transition-transform duration-200 ease-in-out group-focus:border-blue-300 group-focus:ring`}\n                        />\n                      </span>\n                    </th>\n                    <th className=\"bg-gray-700/80 px-1 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6\">\n                      {intl.formatMessage(messages.season)}\n                    </th>\n                    <th className=\"bg-gray-700/80 px-5 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6\">\n                      {intl.formatMessage(messages.numberofepisodes)}\n                    </th>\n                    <th className=\"bg-gray-700/80 px-2 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6\">\n                      {intl.formatMessage(globalMessages.status)}\n                    </th>\n                  </tr>\n                </thead>\n                <tbody className=\"divide-y divide-gray-700\">\n                  {data?.seasons\n                    .filter(\n                      (season) =>\n                        (!settings.currentSettings.enableSpecialEpisodes\n                          ? season.seasonNumber !== 0\n                          : true) &&\n                        (!settings.currentSettings.partialRequestsEnabled\n                          ? season.episodeCount !== 0 &&\n                            season.seasonNumber !== 0\n                          : season.episodeCount !== 0)\n                    )\n                    .map((season) => {\n                      const seasonRequest = getSeasonRequest(\n                        season.seasonNumber\n                      );\n                      const mediaSeason = data?.mediaInfo?.seasons.find(\n                        (sn) =>\n                          sn.seasonNumber === season.seasonNumber &&\n                          sn[is4k ? 'status4k' : 'status'] !==\n                            MediaStatus.UNKNOWN &&\n                          sn[is4k ? 'status4k' : 'status'] !==\n                            MediaStatus.DELETED\n                      );\n                      return (\n                        <tr key={`season-${season.id}`}>\n                          <td\n                            className={`whitespace-nowrap px-4 py-4 text-sm font-medium leading-5 text-gray-100 ${\n                              !settings.currentSettings\n                                .partialRequestsEnabled && 'hidden'\n                            }`}\n                          >\n                            <span\n                              role=\"checkbox\"\n                              tabIndex={0}\n                              aria-checked={\n                                !!mediaSeason ||\n                                (!!seasonRequest &&\n                                  !editingSeasons.includes(\n                                    season.seasonNumber\n                                  )) ||\n                                isSelectedSeason(season.seasonNumber)\n                              }\n                              onClick={() => toggleSeason(season.seasonNumber)}\n                              onKeyDown={(e) => {\n                                if (e.key === 'Enter' || e.key === 'Space') {\n                                  toggleSeason(season.seasonNumber);\n                                }\n                              }}\n                              className={`relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center pt-2 focus:outline-none ${\n                                mediaSeason ||\n                                (quota?.tv.limit &&\n                                  currentlyRemaining <= 0 &&\n                                  !isSelectedSeason(season.seasonNumber)) ||\n                                (!!seasonRequest &&\n                                  !editingSeasons.includes(season.seasonNumber))\n                                  ? 'opacity-50'\n                                  : ''\n                              }`}\n                            >\n                              <span\n                                aria-hidden=\"true\"\n                                className={`${\n                                  !!mediaSeason ||\n                                  (!!seasonRequest &&\n                                    !editingSeasons.includes(\n                                      season.seasonNumber\n                                    )) ||\n                                  isSelectedSeason(season.seasonNumber)\n                                    ? 'bg-indigo-500'\n                                    : 'bg-gray-700'\n                                } absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}\n                              />\n                              <span\n                                aria-hidden=\"true\"\n                                className={`${\n                                  !!mediaSeason ||\n                                  (!!seasonRequest &&\n                                    !editingSeasons.includes(\n                                      season.seasonNumber\n                                    )) ||\n                                  isSelectedSeason(season.seasonNumber)\n                                    ? 'translate-x-5'\n                                    : 'translate-x-0'\n                                } absolute left-0 inline-block h-5 w-5 rounded-full border border-gray-200 bg-white shadow transition-transform duration-200 ease-in-out group-focus:border-blue-300 group-focus:ring`}\n                              />\n                            </span>\n                          </td>\n                          <td className=\"whitespace-nowrap px-1 py-4 text-sm font-medium leading-5 text-gray-100 md:px-6\">\n                            {season.seasonNumber === 0\n                              ? intl.formatMessage(globalMessages.specials)\n                              : intl.formatMessage(messages.seasonnumber, {\n                                  number: season.seasonNumber,\n                                })}\n                          </td>\n                          <td className=\"whitespace-nowrap px-5 py-4 text-sm leading-5 text-gray-200 md:px-6\">\n                            {season.episodeCount}\n                          </td>\n                          <td className=\"whitespace-nowrap py-4 pr-2 text-sm leading-5 text-gray-200 md:px-6\">\n                            {!seasonRequest && !mediaSeason && (\n                              <Badge>\n                                {intl.formatMessage(\n                                  globalMessages.notrequested\n                                )}\n                              </Badge>\n                            )}\n                            {!mediaSeason &&\n                              seasonRequest?.status ===\n                                MediaRequestStatus.PENDING && (\n                                <Badge badgeType=\"warning\">\n                                  {intl.formatMessage(globalMessages.pending)}\n                                </Badge>\n                              )}\n                            {((!mediaSeason &&\n                              seasonRequest?.status ===\n                                MediaRequestStatus.APPROVED) ||\n                              mediaSeason?.[is4k ? 'status4k' : 'status'] ===\n                                MediaStatus.PROCESSING) && (\n                              <Badge badgeType=\"primary\">\n                                {intl.formatMessage(globalMessages.requested)}\n                              </Badge>\n                            )}\n                            {mediaSeason?.[is4k ? 'status4k' : 'status'] ===\n                              MediaStatus.PARTIALLY_AVAILABLE && (\n                              <Badge badgeType=\"success\">\n                                {intl.formatMessage(\n                                  globalMessages.partiallyavailable\n                                )}\n                              </Badge>\n                            )}\n                            {mediaSeason?.[is4k ? 'status4k' : 'status'] ===\n                              MediaStatus.AVAILABLE && (\n                              <Badge badgeType=\"success\">\n                                {intl.formatMessage(globalMessages.available)}\n                              </Badge>\n                            )}\n                          </td>\n                        </tr>\n                      );\n                    })}\n                </tbody>\n              </table>\n            </div>\n          </div>\n        </div>\n      </div>\n      {(hasPermission(Permission.REQUEST_ADVANCED) ||\n        hasPermission(Permission.MANAGE_REQUESTS)) && (\n        <AdvancedRequester\n          type=\"tv\"\n          is4k={is4k}\n          isAnime={data?.keywords.some(\n            (keyword) => keyword.id === ANIME_KEYWORD_ID\n          )}\n          onChange={(overrides) => setRequestOverrides(overrides)}\n          requestUser={editRequest?.requestedBy}\n          defaultOverrides={\n            editRequest\n              ? {\n                  folder: editRequest.rootFolder,\n                  profile: editRequest.profileId,\n                  server: editRequest.serverId,\n                  language: editRequest.languageProfileId,\n                  tags: editRequest.tags,\n                }\n              : undefined\n          }\n        />\n      )}\n    </Modal>\n  );\n};\n\nexport default TvRequestModal;\n"
  },
  {
    "path": "src/components/RequestModal/index.tsx",
    "content": "import CollectionRequestModal from '@app/components/RequestModal/CollectionRequestModal';\nimport MovieRequestModal from '@app/components/RequestModal/MovieRequestModal';\nimport TvRequestModal from '@app/components/RequestModal/TvRequestModal';\nimport { Transition } from '@headlessui/react';\nimport type { MediaStatus } from '@server/constants/media';\nimport type { MediaRequest } from '@server/entity/MediaRequest';\nimport type { NonFunctionProperties } from '@server/interfaces/api/common';\n\ninterface RequestModalProps {\n  show: boolean;\n  type: 'movie' | 'tv' | 'collection';\n  tmdbId: number;\n  is4k?: boolean;\n  editRequest?: NonFunctionProperties<MediaRequest>;\n  onComplete?: (newStatus: MediaStatus) => void;\n  onCancel?: () => void;\n  onUpdating?: (isUpdating: boolean) => void;\n}\n\nconst RequestModal = ({\n  type,\n  show,\n  tmdbId,\n  is4k,\n  editRequest,\n  onComplete,\n  onUpdating,\n  onCancel,\n}: RequestModalProps) => {\n  return (\n    <Transition\n      as=\"div\"\n      enter=\"transition-opacity duration-300\"\n      enterFrom=\"opacity-0\"\n      enterTo=\"opacity-100\"\n      leave=\"transition-opacity duration-300\"\n      leaveFrom=\"opacity-100\"\n      leaveTo=\"opacity-0\"\n      show={show}\n    >\n      {type === 'movie' ? (\n        <MovieRequestModal\n          onComplete={onComplete}\n          onCancel={onCancel}\n          tmdbId={tmdbId}\n          onUpdating={onUpdating}\n          is4k={is4k}\n          editRequest={editRequest}\n        />\n      ) : type === 'tv' ? (\n        <TvRequestModal\n          onComplete={onComplete}\n          onCancel={onCancel}\n          tmdbId={tmdbId}\n          onUpdating={onUpdating}\n          is4k={is4k}\n          editRequest={editRequest}\n        />\n      ) : (\n        <CollectionRequestModal\n          onComplete={onComplete}\n          onCancel={onCancel}\n          tmdbId={tmdbId}\n          onUpdating={onUpdating}\n          is4k={is4k}\n        />\n      )}\n    </Transition>\n  );\n};\n\nexport default RequestModal;\n"
  },
  {
    "path": "src/components/ResetPassword/RequestResetLink.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport ImageFader from '@app/components/Common/ImageFader';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport LanguagePicker from '@app/components/Layout/LanguagePicker';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowLeftIcon, EnvelopeIcon } from '@heroicons/react/24/solid';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport Image from 'next/image';\nimport Link from 'next/link';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport validator from 'validator';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.ResetPassword', {\n  passwordreset: 'Password Reset',\n  resetpassword: 'Reset your password',\n  emailresetlink: 'Email Recovery Link',\n  email: 'Email Address',\n  validationemailrequired: 'You must provide a valid email address',\n  gobacklogin: 'Return to Sign-In Page',\n  requestresetlinksuccessmessage:\n    'A password reset link will be sent to the provided email address if it is associated with a valid user.',\n});\n\nconst ResetPassword = () => {\n  const intl = useIntl();\n  const [hasSubmitted, setSubmitted] = useState(false);\n\n  const ResetSchema = Yup.object().shape({\n    email: Yup.string()\n      .test(\n        'email',\n        intl.formatMessage(messages.validationemailrequired),\n        (value) => !value || validator.isEmail(value, { require_tld: false })\n      )\n      .required(intl.formatMessage(messages.validationemailrequired)),\n  });\n\n  return (\n    <div className=\"relative flex min-h-screen flex-col bg-gray-900 py-14\">\n      <PageTitle title={intl.formatMessage(messages.passwordreset)} />\n      <ImageFader\n        forceOptimize\n        backgroundImages={[\n          '/images/rotate1.jpg',\n          '/images/rotate2.jpg',\n          '/images/rotate3.jpg',\n          '/images/rotate4.jpg',\n          '/images/rotate5.jpg',\n          '/images/rotate6.jpg',\n        ]}\n      />\n      <div className=\"absolute right-4 top-4 z-50\">\n        <LanguagePicker />\n      </div>\n      <div className=\"relative z-40 mt-10 flex flex-col items-center px-4 sm:mx-auto sm:w-full sm:max-w-md\">\n        <div className=\"relative h-48 w-full max-w-full\">\n          <Image src=\"/logo_stacked.svg\" alt=\"Logo\" fill />\n        </div>\n        <h2 className=\"mt-12 text-center text-3xl font-extrabold leading-9 text-gray-100\">\n          {intl.formatMessage(messages.resetpassword)}\n        </h2>\n      </div>\n      <div className=\"relative z-50 mt-8 sm:mx-auto sm:w-full sm:max-w-md\">\n        <div\n          className=\"bg-gray-800/50 shadow sm:rounded-lg\"\n          style={{ backdropFilter: 'blur(5px)' }}\n        >\n          <div className=\"px-10 py-8\">\n            {hasSubmitted ? (\n              <>\n                <p className=\"text-md text-gray-300\">\n                  {intl.formatMessage(messages.requestresetlinksuccessmessage)}\n                </p>\n                <span className=\"mt-4 flex justify-center rounded-md shadow-sm\">\n                  <Link href=\"/login\" passHref legacyBehavior>\n                    <Button as=\"a\" buttonType=\"ghost\">\n                      <ArrowLeftIcon />\n                      <span>{intl.formatMessage(messages.gobacklogin)}</span>\n                    </Button>\n                  </Link>\n                </span>\n              </>\n            ) : (\n              <Formik\n                initialValues={{\n                  email: '',\n                }}\n                validationSchema={ResetSchema}\n                onSubmit={async (values) => {\n                  const response = await axios.post(\n                    `/api/v1/auth/reset-password`,\n                    {\n                      email: values.email,\n                    }\n                  );\n\n                  if (response.status === 200) {\n                    setSubmitted(true);\n                  }\n                }}\n              >\n                {({ errors, touched, isSubmitting, isValid }) => {\n                  return (\n                    <Form>\n                      <div>\n                        <label\n                          htmlFor=\"email\"\n                          className=\"my-1 block text-sm font-medium leading-5 text-gray-400 sm:mt-px\"\n                        >\n                          {intl.formatMessage(messages.email)}\n                        </label>\n                        <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n                          <div className=\"form-input-field\">\n                            <Field\n                              id=\"email\"\n                              name=\"email\"\n                              type=\"text\"\n                              inputMode=\"email\"\n                              className=\"form-input-area block w-full min-w-0 flex-1 rounded-md border border-gray-500 bg-gray-700 text-white transition duration-150 ease-in-out sm:text-sm sm:leading-5\"\n                            />\n                          </div>\n                          {errors.email &&\n                            touched.email &&\n                            typeof errors.email === 'string' && (\n                              <div className=\"error\">{errors.email}</div>\n                            )}\n                        </div>\n                      </div>\n                      <div className=\"mt-4 border-t border-gray-700 pt-5\">\n                        <div className=\"flex justify-end\">\n                          <span className=\"inline-flex rounded-md shadow-sm\">\n                            <Button\n                              buttonType=\"primary\"\n                              type=\"submit\"\n                              disabled={isSubmitting || !isValid}\n                            >\n                              <EnvelopeIcon />\n                              <span>\n                                {intl.formatMessage(messages.emailresetlink)}\n                              </span>\n                            </Button>\n                          </span>\n                        </div>\n                      </div>\n                    </Form>\n                  );\n                }}\n              </Formik>\n            )}\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default ResetPassword;\n"
  },
  {
    "path": "src/components/ResetPassword/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport ImageFader from '@app/components/Common/ImageFader';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport LanguagePicker from '@app/components/Layout/LanguagePicker';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { LifebuoyIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Form, Formik } from 'formik';\nimport Image from 'next/image';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.ResetPassword', {\n  passwordreset: 'Password Reset',\n  resetpassword: 'Reset your password',\n  password: 'Password',\n  confirmpassword: 'Confirm Password',\n  validationpasswordrequired: 'You must provide a password',\n  validationpasswordmatch: 'Passwords must match',\n  validationpasswordminchars:\n    'Password is too short; should be a minimum of 8 characters',\n  gobacklogin: 'Return to Sign-In Page',\n  resetpasswordsuccessmessage: 'Password reset successfully!',\n});\n\nconst ResetPassword = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const [hasSubmitted, setSubmitted] = useState(false);\n\n  const guid = router.query.guid;\n\n  const ResetSchema = Yup.object().shape({\n    password: Yup.string()\n      .required(intl.formatMessage(messages.validationpasswordrequired))\n      .min(8, intl.formatMessage(messages.validationpasswordminchars)),\n    confirmPassword: Yup.string()\n      .required(intl.formatMessage(messages.validationpasswordmatch))\n      .test(\n        'passwords-match',\n        intl.formatMessage(messages.validationpasswordmatch),\n        function (value) {\n          return this.parent.password === value;\n        }\n      ),\n  });\n\n  return (\n    <div className=\"relative flex min-h-screen flex-col bg-gray-900 py-14\">\n      <ImageFader\n        forceOptimize\n        backgroundImages={[\n          '/images/rotate1.jpg',\n          '/images/rotate2.jpg',\n          '/images/rotate3.jpg',\n          '/images/rotate4.jpg',\n          '/images/rotate5.jpg',\n          '/images/rotate6.jpg',\n        ]}\n      />\n      <div className=\"absolute right-4 top-4 z-50\">\n        <LanguagePicker />\n      </div>\n      <div className=\"relative z-40 mt-10 flex flex-col items-center px-4 sm:mx-auto sm:w-full sm:max-w-md\">\n        <div className=\"relative h-48 w-full max-w-full\">\n          <Image src=\"/logo_stacked.svg\" alt=\"Logo\" fill />\n        </div>\n        <h2 className=\"mt-12 text-center text-3xl font-extrabold leading-9 text-gray-100\">\n          {intl.formatMessage(messages.resetpassword)}\n        </h2>\n      </div>\n      <div className=\"relative z-50 mt-8 sm:mx-auto sm:w-full sm:max-w-md\">\n        <div\n          className=\"bg-gray-800/50 shadow sm:rounded-lg\"\n          style={{ backdropFilter: 'blur(5px)' }}\n        >\n          <div className=\"px-10 py-8\">\n            {hasSubmitted ? (\n              <>\n                <p className=\"text-md text-gray-300\">\n                  {intl.formatMessage(messages.resetpasswordsuccessmessage)}\n                </p>\n                <span className=\"mt-4 flex justify-center rounded-md shadow-sm\">\n                  <Link href=\"/login\" passHref legacyBehavior>\n                    <Button as=\"a\" buttonType=\"ghost\">\n                      {intl.formatMessage(messages.gobacklogin)}\n                    </Button>\n                  </Link>\n                </span>\n              </>\n            ) : (\n              <Formik\n                initialValues={{\n                  confirmPassword: '',\n                  password: '',\n                }}\n                validationSchema={ResetSchema}\n                onSubmit={async (values) => {\n                  const response = await axios.post(\n                    `/api/v1/auth/reset-password/${guid}`,\n                    {\n                      password: values.password,\n                    }\n                  );\n\n                  if (response.status === 200) {\n                    setSubmitted(true);\n                  }\n                }}\n              >\n                {({ errors, touched, isSubmitting, isValid }) => {\n                  return (\n                    <Form>\n                      <div>\n                        <label\n                          htmlFor=\"password\"\n                          className=\"my-1 block text-sm font-medium leading-5 text-gray-400 sm:mt-px\"\n                        >\n                          {intl.formatMessage(messages.password)}\n                        </label>\n                        <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n                          <div className=\"form-input-field\">\n                            <SensitiveInput\n                              as=\"field\"\n                              id=\"password\"\n                              name=\"password\"\n                              type=\"password\"\n                              autoComplete=\"new-password\"\n                              className=\"form-input-area block w-full min-w-0 flex-1 rounded-md border border-gray-500 bg-gray-700 text-white transition duration-150 ease-in-out sm:text-sm sm:leading-5\"\n                            />\n                          </div>\n                          {errors.password &&\n                            touched.password &&\n                            typeof errors.password === 'string' && (\n                              <div className=\"error\">{errors.password}</div>\n                            )}\n                        </div>\n                        <label\n                          htmlFor=\"confirmPassword\"\n                          className=\"my-1 block text-sm font-medium leading-5 text-gray-400 sm:mt-px\"\n                        >\n                          {intl.formatMessage(messages.confirmpassword)}\n                        </label>\n                        <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n                          <div className=\"form-input-field\">\n                            <SensitiveInput\n                              as=\"field\"\n                              id=\"confirmPassword\"\n                              name=\"confirmPassword\"\n                              type=\"password\"\n                              autoComplete=\"new-password\"\n                              className=\"form-input-area block w-full min-w-0 flex-1 rounded-md border border-gray-500 bg-gray-700 text-white transition duration-150 ease-in-out sm:text-sm sm:leading-5\"\n                            />\n                          </div>\n                          {errors.confirmPassword &&\n                            touched.confirmPassword && (\n                              <div className=\"error\">\n                                {errors.confirmPassword}\n                              </div>\n                            )}\n                        </div>\n                      </div>\n                      <div className=\"mt-4 border-t border-gray-700 pt-5\">\n                        <div className=\"flex justify-end\">\n                          <span className=\"inline-flex rounded-md shadow-sm\">\n                            <Button\n                              buttonType=\"primary\"\n                              type=\"submit\"\n                              disabled={isSubmitting || !isValid}\n                            >\n                              <LifebuoyIcon />\n                              <span>\n                                {isSubmitting\n                                  ? intl.formatMessage(globalMessages.saving)\n                                  : intl.formatMessage(globalMessages.save)}\n                              </span>\n                            </Button>\n                          </span>\n                        </div>\n                      </div>\n                    </Form>\n                  );\n                }}\n              </Formik>\n            )}\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default ResetPassword;\n"
  },
  {
    "path": "src/components/Search/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type {\n  MovieResult,\n  PersonResult,\n  TvResult,\n} from '@server/models/Search';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Search', {\n  search: 'Search',\n  searchresults: 'Search Results',\n});\n\nconst Search = () => {\n  const intl = useIntl();\n  const router = useRouter();\n\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<MovieResult | TvResult | PersonResult>(\n    `/api/v1/search`,\n    {\n      query: router.query.query,\n    },\n    { hideAvailable: false, hideBlocklisted: false }\n  );\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(messages.search)} />\n      <div className=\"mb-5 mt-1\">\n        <Header>{intl.formatMessage(messages.searchresults)}</Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        isReachingEnd={isReachingEnd}\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default Search;\n"
  },
  {
    "path": "src/components/Selector/CertificationSelector.tsx",
    "content": "import { SmallLoadingSpinner } from '@app/components/Common/LoadingSpinner';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { Region } from '@server/lib/settings';\nimport React, { useCallback, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport AsyncSelect from 'react-select/async';\nimport useSWR from 'swr';\n\ninterface Certification {\n  certification: string;\n  meaning?: string;\n  order?: number;\n}\n\ninterface CertificationResponse {\n  certifications: {\n    [country: string]: Certification[];\n  };\n}\n\ninterface CertificationOption {\n  value: string;\n  label: string;\n  certification?: string;\n}\n\ninterface CertificationSelectorProps {\n  type: string;\n  certificationCountry?: string;\n  certification?: string;\n  certificationGte?: string;\n  certificationLte?: string;\n  onChange: (params: {\n    certificationCountry?: string;\n    certification?: string;\n    certificationGte?: string;\n    certificationLte?: string;\n  }) => void;\n  showRange?: boolean;\n}\n\nconst messages = defineMessages('components.Selector.CertificationSelector', {\n  selectCountry: 'Select a country',\n  selectCertification: 'Select a certification',\n  minRating: 'Minimum rating',\n  maxRating: 'Maximum rating',\n  noOptions: 'No options available',\n  starttyping: 'Starting typing to search.',\n  errorLoading: 'Failed to load certifications',\n});\n\nconst CertificationSelector: React.FC<CertificationSelectorProps> = ({\n  type,\n  certificationCountry,\n  certification,\n  certificationGte,\n  certificationLte,\n  showRange = false,\n  onChange,\n}) => {\n  const intl = useIntl();\n  const [selectedCountry, setSelectedCountry] =\n    useState<CertificationOption | null>(\n      certificationCountry\n        ? { value: certificationCountry, label: certificationCountry }\n        : null\n    );\n  const [selectedCertification, setSelectedCertification] =\n    useState<CertificationOption | null>(null);\n  const [selectedCertificationGte, setSelectedCertificationGte] =\n    useState<CertificationOption | null>(null);\n  const [selectedCertificationLte, setSelectedCertificationLte] =\n    useState<CertificationOption | null>(null);\n\n  const {\n    data: certificationData,\n    error: certificationError,\n    isLoading: certificationLoading,\n  } = useSWR<CertificationResponse>(`/api/v1/certifications/${type}`);\n\n  const { data: regionsData } = useSWR<Region[]>('/api/v1/regions');\n\n  // Get the country name from its code\n  const getCountryName = useCallback(\n    (countryCode: string): string => {\n      const region = regionsData?.find(\n        (region) => region.iso_3166_1 === countryCode\n      );\n      return region?.name || countryCode;\n    },\n    [regionsData]\n  );\n\n  useEffect(() => {\n    if (certificationCountry && regionsData) {\n      setSelectedCountry({\n        value: certificationCountry,\n        label: getCountryName(certificationCountry),\n      });\n    }\n  }, [certificationCountry, regionsData, getCountryName]);\n\n  useEffect(() => {\n    if (!certificationData || !certificationCountry) return;\n\n    const certifications = (\n      certificationData.certifications[certificationCountry] || []\n    )\n      .sort((a, b) => {\n        if (a.order !== undefined && b.order !== undefined) {\n          return a.order - b.order;\n        }\n        return a.certification.localeCompare(b.certification);\n      })\n      .map((cert) => ({\n        value: cert.certification,\n        label: `${cert.certification}${\n          cert.meaning ? ` - ${cert.meaning}` : ''\n        }`,\n        certification: cert.certification,\n      }));\n\n    if (certification) {\n      setSelectedCertification(\n        certifications.find((c) => c.value === certification) || null\n      );\n    }\n\n    if (certificationGte) {\n      setSelectedCertificationGte(\n        certifications.find((c) => c.value === certificationGte) || null\n      );\n    }\n\n    if (certificationLte) {\n      setSelectedCertificationLte(\n        certifications.find((c) => c.value === certificationLte) || null\n      );\n    }\n  }, [\n    certificationData,\n    certificationCountry,\n    certification,\n    certificationGte,\n    certificationLte,\n  ]);\n\n  if (certificationError) {\n    return (\n      <div className=\"text-red-500\">\n        {intl.formatMessage(messages.errorLoading)}\n      </div>\n    );\n  }\n\n  if (certificationLoading || !certificationData) {\n    return <SmallLoadingSpinner />;\n  }\n\n  const loadCountryOptions = async (inputValue: string) => {\n    if (!certificationData || !regionsData) return [];\n\n    return Object.keys(certificationData.certifications)\n      .filter(\n        (code) =>\n          certificationData.certifications[code] &&\n          certificationData.certifications[code].length > 0 &&\n          (code.toLowerCase().includes(inputValue.toLowerCase()) ||\n            getCountryName(code)\n              .toLowerCase()\n              .includes(inputValue.toLowerCase()))\n      )\n      .sort((a, b) => getCountryName(a).localeCompare(getCountryName(b)))\n      .map((code) => ({\n        value: code,\n        label: getCountryName(code),\n      }));\n  };\n\n  const loadCertificationOptions = async (inputValue: string) => {\n    if (!certificationData || !certificationCountry) return [];\n\n    return (certificationData.certifications[certificationCountry] || [])\n      .sort((a, b) => {\n        if (a.order !== undefined && b.order !== undefined) {\n          return a.order - b.order;\n        }\n        return a.certification.localeCompare(b.certification);\n      })\n      .map((cert) => ({\n        value: cert.certification,\n        label: `${cert.certification}${\n          cert.meaning ? ` - ${cert.meaning}` : ''\n        }`,\n        certification: cert.certification,\n      }))\n      .filter((cert) =>\n        cert.label.toLowerCase().includes(inputValue.toLowerCase())\n      );\n  };\n\n  const handleCountryChange = (option: CertificationOption | null) => {\n    setSelectedCountry(option);\n    setSelectedCertification(null);\n    setSelectedCertificationGte(null);\n    setSelectedCertificationLte(null);\n\n    onChange({\n      certificationCountry: option?.value,\n      certification: undefined,\n      certificationGte: undefined,\n      certificationLte: undefined,\n    });\n  };\n\n  const handleCertificationChange = (option: CertificationOption | null) => {\n    setSelectedCertification(option);\n\n    onChange({\n      certificationCountry,\n      certification: option?.value,\n      certificationGte: undefined,\n      certificationLte: undefined,\n    });\n  };\n\n  const handleMinCertificationChange = (option: CertificationOption | null) => {\n    setSelectedCertificationGte(option);\n\n    onChange({\n      certificationCountry,\n      certification: undefined,\n      certificationGte: option?.value,\n      certificationLte: certificationLte,\n    });\n  };\n\n  const handleMaxCertificationChange = (option: CertificationOption | null) => {\n    setSelectedCertificationLte(option);\n\n    onChange({\n      certificationCountry,\n      certification: undefined,\n      certificationGte: certificationGte,\n      certificationLte: option?.value,\n    });\n  };\n\n  const formatCertificationLabel = (\n    option: CertificationOption,\n    { context }: { context: string }\n  ) => {\n    if (context === 'value') {\n      return option.certification || option.value;\n    }\n    // Show the full label with description in the menu\n    return option.label;\n  };\n\n  return (\n    <div className=\"space-y-2\">\n      <AsyncSelect\n        className=\"react-select-container\"\n        classNamePrefix=\"react-select\"\n        cacheOptions\n        defaultOptions\n        loadOptions={loadCountryOptions}\n        value={selectedCountry}\n        onChange={handleCountryChange}\n        placeholder={intl.formatMessage(messages.selectCountry)}\n        isClearable\n        noOptionsMessage={({ inputValue }) =>\n          inputValue === ''\n            ? intl.formatMessage(messages.starttyping)\n            : intl.formatMessage(messages.noOptions)\n        }\n      />\n\n      {certificationCountry && !showRange && (\n        <AsyncSelect\n          className=\"react-select-container\"\n          classNamePrefix=\"react-select\"\n          cacheOptions\n          defaultOptions\n          loadOptions={loadCertificationOptions}\n          value={selectedCertification}\n          onChange={handleCertificationChange}\n          placeholder={intl.formatMessage(messages.selectCertification)}\n          formatOptionLabel={formatCertificationLabel}\n          isClearable\n          noOptionsMessage={() => intl.formatMessage(messages.noOptions)}\n        />\n      )}\n\n      {certificationCountry && showRange && (\n        <div className=\"flex space-x-2\">\n          <div className=\"flex-1\">\n            <AsyncSelect\n              className=\"react-select-container\"\n              classNamePrefix=\"react-select\"\n              cacheOptions\n              defaultOptions\n              loadOptions={loadCertificationOptions}\n              value={selectedCertificationGte}\n              onChange={handleMinCertificationChange}\n              placeholder={intl.formatMessage(messages.minRating)}\n              formatOptionLabel={formatCertificationLabel}\n              isClearable\n              noOptionsMessage={() => intl.formatMessage(messages.noOptions)}\n            />\n          </div>\n          <div className=\"flex-1\">\n            <AsyncSelect\n              className=\"react-select-container\"\n              classNamePrefix=\"react-select\"\n              cacheOptions\n              defaultOptions\n              loadOptions={loadCertificationOptions}\n              value={selectedCertificationLte}\n              onChange={handleMaxCertificationChange}\n              placeholder={intl.formatMessage(messages.maxRating)}\n              formatOptionLabel={formatCertificationLabel}\n              isClearable\n              noOptionsMessage={() => intl.formatMessage(messages.noOptions)}\n            />\n          </div>\n        </div>\n      )}\n    </div>\n  );\n};\n\nexport default CertificationSelector;\n"
  },
  {
    "path": "src/components/Selector/USCertificationSelector.tsx",
    "content": "import React, { useEffect, useState } from 'react';\n\ninterface USCertificationSelectorProps {\n  type: string;\n  certification?: string;\n  onChange: (params: {\n    certificationCountry?: string;\n    certification?: string;\n  }) => void;\n}\n\nconst US_MOVIE_CERTIFICATIONS = ['NR', 'G', 'PG', 'PG-13', 'R', 'NC-17'];\nconst US_TV_CERTIFICATIONS = [\n  'NR',\n  'TV-Y',\n  'TV-Y7',\n  'TV-G',\n  'TV-PG',\n  'TV-14',\n  'TV-MA',\n];\n\nconst USCertificationSelector: React.FC<USCertificationSelectorProps> = ({\n  type,\n  certification,\n  onChange,\n}) => {\n  const [selectedRatings, setSelectedRatings] = useState<string[]>(() =>\n    certification ? certification.split('|') : []\n  );\n\n  const certifications =\n    type === 'movie' ? US_MOVIE_CERTIFICATIONS : US_TV_CERTIFICATIONS;\n\n  useEffect(() => {\n    if (certification) {\n      setSelectedRatings(certification.split('|'));\n    } else {\n      setSelectedRatings([]);\n    }\n  }, [certification]);\n\n  const toggleRating = (rating: string) => {\n    setSelectedRatings((prevSelected) => {\n      let newSelected;\n\n      if (prevSelected.includes(rating)) {\n        newSelected = prevSelected.filter((r) => r !== rating);\n      } else {\n        newSelected = [...prevSelected, rating];\n      }\n\n      const newCertification =\n        newSelected.length > 0 ? newSelected.join('|') : undefined;\n\n      onChange({\n        certificationCountry: 'US',\n        certification: newCertification,\n      });\n\n      return newSelected;\n    });\n  };\n\n  return (\n    <div className=\"mb-4\">\n      <div className=\"flex flex-wrap gap-2\">\n        {certifications.map((rating) => (\n          <button\n            key={rating}\n            onClick={() => toggleRating(rating)}\n            className={`rounded-full px-3 py-1 text-sm font-medium transition-colors ${\n              selectedRatings.includes(rating)\n                ? 'bg-indigo-600 text-white hover:bg-indigo-700'\n                : 'bg-gray-200 text-gray-700 hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600'\n            }`}\n            type=\"button\"\n          >\n            {rating}\n          </button>\n        ))}\n      </div>\n    </div>\n  );\n};\n\nexport default USCertificationSelector;\n"
  },
  {
    "path": "src/components/Selector/index.tsx",
    "content": "import CachedImage from '@app/components/Common/CachedImage';\nimport { SmallLoadingSpinner } from '@app/components/Common/LoadingSpinner';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport RegionSelector from '@app/components/RegionSelector';\nimport { encodeURIExtraParams } from '@app/hooks/useDiscover';\nimport useSettings from '@app/hooks/useSettings';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownIcon, ArrowUpIcon } from '@heroicons/react/20/solid';\nimport { CheckCircleIcon } from '@heroicons/react/24/solid';\nimport type {\n  TmdbCompanySearchResponse,\n  TmdbGenre,\n  TmdbKeywordSearchResponse,\n} from '@server/api/themoviedb/interfaces';\nimport type { UserResultsResponse } from '@server/interfaces/api/userInterfaces';\nimport type {\n  Keyword,\n  ProductionCompany,\n  WatchProviderDetails,\n} from '@server/models/common';\nimport axios from 'axios';\nimport orderBy from 'lodash/orderBy';\nimport { useEffect, useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport type { MultiValue, SingleValue } from 'react-select';\nimport AsyncSelect from 'react-select/async';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Selector', {\n  searchKeywords: 'Search keywords…',\n  searchGenres: 'Select genres…',\n  searchStudios: 'Search studios…',\n  searchUsers: 'Select users…',\n  starttyping: 'Starting typing to search.',\n  nooptions: 'No results.',\n  showmore: 'Show More',\n  showless: 'Show Less',\n  searchStatus: 'Select status...',\n  returningSeries: 'Returning Series',\n  planned: 'Planned',\n  inProduction: 'In Production',\n  ended: 'Ended',\n  canceled: 'Canceled',\n  pilot: 'Pilot',\n});\n\ntype SingleVal = {\n  label: string;\n  value: number;\n};\n\ntype BaseSelectorMultiProps = {\n  defaultValue?: string;\n  isMulti: true;\n  isDisabled?: boolean;\n  onChange: (value: MultiValue<SingleVal> | null) => void;\n};\n\ntype BaseSelectorSingleProps = {\n  defaultValue?: string;\n  isMulti?: false;\n  isDisabled?: boolean;\n  onChange: (value: SingleValue<SingleVal> | null) => void;\n};\n\nexport const CompanySelector = ({\n  defaultValue,\n  isMulti,\n  isDisabled,\n  onChange,\n}: BaseSelectorSingleProps | BaseSelectorMultiProps) => {\n  const intl = useIntl();\n  const [defaultDataValue, setDefaultDataValue] = useState<\n    { label: string; value: number }[] | null\n  >(null);\n\n  useEffect(() => {\n    const loadDefaultCompany = async (): Promise<void> => {\n      if (!defaultValue) {\n        return;\n      }\n\n      const response = await axios.get<ProductionCompany>(\n        `/api/v1/studio/${defaultValue}`\n      );\n\n      const studio = response.data;\n\n      setDefaultDataValue([\n        {\n          label: studio.name ?? '',\n          value: studio.id ?? 0,\n        },\n      ]);\n    };\n\n    loadDefaultCompany();\n  }, [defaultValue]);\n\n  const loadCompanyOptions = async (inputValue: string) => {\n    if (inputValue === '') {\n      return [];\n    }\n\n    const results = await axios.get<TmdbCompanySearchResponse>(\n      '/api/v1/search/company',\n      {\n        params: {\n          query: encodeURIExtraParams(inputValue),\n        },\n      }\n    );\n\n    return results.data.results.map((result) => ({\n      label: result.name,\n      value: result.id,\n    }));\n  };\n\n  return (\n    <AsyncSelect\n      key={`company-selector-${defaultDataValue}`}\n      className=\"react-select-container\"\n      classNamePrefix=\"react-select\"\n      isMulti={isMulti}\n      isDisabled={isDisabled}\n      defaultValue={defaultDataValue}\n      defaultOptions\n      cacheOptions\n      isClearable\n      noOptionsMessage={({ inputValue }) =>\n        inputValue === ''\n          ? intl.formatMessage(messages.starttyping)\n          : intl.formatMessage(messages.nooptions)\n      }\n      loadOptions={loadCompanyOptions}\n      placeholder={intl.formatMessage(messages.searchStudios)}\n      onChange={(value) => {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        onChange(value as any);\n      }}\n    />\n  );\n};\n\ntype GenreSelectorProps = (BaseSelectorMultiProps | BaseSelectorSingleProps) & {\n  type: 'movie' | 'tv';\n};\n\nexport const GenreSelector = ({\n  isMulti,\n  defaultValue,\n  isDisabled,\n  onChange,\n  type,\n}: GenreSelectorProps) => {\n  const intl = useIntl();\n  const [defaultDataValue, setDefaultDataValue] = useState<\n    { label: string; value: number }[] | null\n  >(null);\n\n  useEffect(() => {\n    const loadDefaultGenre = async (): Promise<void> => {\n      if (!defaultValue) {\n        return;\n      }\n\n      const genres = defaultValue.split(',');\n\n      const response = await axios.get<TmdbGenre[]>(`/api/v1/genres/${type}`);\n\n      const genreData = genres\n        .filter((genre) => response.data.find((gd) => gd.id === Number(genre)))\n        .map((g) => response.data.find((gd) => gd.id === Number(g)))\n        .map((g) => ({\n          label: g?.name ?? '',\n          value: g?.id ?? 0,\n        }));\n\n      setDefaultDataValue(genreData);\n    };\n\n    loadDefaultGenre();\n  }, [defaultValue, type]);\n\n  const loadGenreOptions = async (inputValue: string) => {\n    const results = await axios.get<TmdbGenre[]>(`/api/v1/genres/${type}`);\n\n    return results.data\n      .map((result) => ({\n        label: result.name,\n        value: result.id,\n      }))\n      .filter(({ label }) =>\n        label.toLowerCase().includes(inputValue.toLowerCase())\n      );\n  };\n\n  return (\n    <AsyncSelect\n      key={`genre-select-${type}-${defaultDataValue}`}\n      className=\"react-select-container\"\n      classNamePrefix=\"react-select\"\n      defaultValue={isMulti ? defaultDataValue : defaultDataValue?.[0]}\n      defaultOptions\n      cacheOptions\n      isMulti={isMulti}\n      isDisabled={isDisabled}\n      loadOptions={loadGenreOptions}\n      placeholder={intl.formatMessage(messages.searchGenres)}\n      onChange={(value) => {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        onChange(value as any);\n      }}\n    />\n  );\n};\n\nexport const StatusSelector = ({\n  isMulti,\n  isDisabled,\n  defaultValue,\n  onChange,\n}: BaseSelectorMultiProps | BaseSelectorSingleProps) => {\n  const intl = useIntl();\n  const [defaultDataValue, setDefaultDataValue] = useState<\n    { label: string; value: number }[] | null\n  >(null);\n\n  const options = useMemo(\n    () => [\n      { name: intl.formatMessage(messages.returningSeries), id: 0 },\n      { name: intl.formatMessage(messages.planned), id: 1 },\n      { name: intl.formatMessage(messages.inProduction), id: 2 },\n      { name: intl.formatMessage(messages.ended), id: 3 },\n      { name: intl.formatMessage(messages.canceled), id: 4 },\n      { name: intl.formatMessage(messages.pilot), id: 5 },\n    ],\n    [intl]\n  );\n\n  useEffect(() => {\n    const loadDefaultStatus = async (): Promise<void> => {\n      if (!defaultValue) {\n        return;\n      }\n      const statuses = defaultValue.split('|');\n\n      const statusData = options\n        .filter((opt) => statuses.find((s) => Number(s) === opt.id))\n        .map((o) => ({\n          label: o.name,\n          value: o.id,\n        }));\n\n      setDefaultDataValue(statusData);\n    };\n\n    loadDefaultStatus();\n  }, [defaultValue, options]);\n\n  const loadStatusOptions = async () => {\n    return options\n      .map((result) => ({\n        label: result.name,\n        value: result.id,\n      }))\n      .filter(({ label }) => label.toLowerCase());\n  };\n\n  return (\n    <AsyncSelect\n      key={`status-select-${defaultDataValue}`}\n      className=\"react-select-container\"\n      classNamePrefix=\"react-select\"\n      defaultValue={isMulti ? defaultDataValue : defaultDataValue?.[0]}\n      defaultOptions\n      isMulti={isMulti}\n      isDisabled={isDisabled}\n      loadOptions={loadStatusOptions}\n      placeholder={intl.formatMessage(messages.searchStatus)}\n      onChange={(value) => {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        onChange(value as any);\n      }}\n    />\n  );\n};\n\nexport const KeywordSelector = ({\n  isMulti,\n  isDisabled,\n  defaultValue,\n  onChange,\n}: BaseSelectorMultiProps | BaseSelectorSingleProps) => {\n  const intl = useIntl();\n  const [defaultDataValue, setDefaultDataValue] = useState<\n    { label: string; value: number }[] | null\n  >(null);\n\n  useEffect(() => {\n    const loadDefaultKeywords = async (): Promise<void> => {\n      if (!defaultValue) {\n        return;\n      }\n\n      const keywords = await Promise.all(\n        defaultValue.split(',').map(async (keywordId) => {\n          const keyword = await axios.get<Keyword | null>(\n            `/api/v1/keyword/${keywordId}`\n          );\n          return keyword.data;\n        })\n      );\n\n      const validKeywords: Keyword[] = keywords.filter(\n        (keyword): keyword is Keyword => keyword !== null\n      );\n\n      setDefaultDataValue(\n        validKeywords.map((keyword) => ({\n          label: keyword.name,\n          value: keyword.id,\n        }))\n      );\n    };\n\n    loadDefaultKeywords();\n  }, [defaultValue]);\n\n  const loadKeywordOptions = async (inputValue: string) => {\n    const results = await axios.get<TmdbKeywordSearchResponse>(\n      '/api/v1/search/keyword',\n      {\n        params: {\n          query: encodeURIExtraParams(inputValue),\n        },\n      }\n    );\n\n    return results.data.results.map((result) => ({\n      label: result.name,\n      value: result.id,\n    }));\n  };\n\n  return (\n    <AsyncSelect\n      key={`keyword-select-${defaultDataValue}`}\n      inputId=\"data\"\n      isMulti={isMulti}\n      isDisabled={isDisabled}\n      className=\"react-select-container\"\n      classNamePrefix=\"react-select\"\n      noOptionsMessage={({ inputValue }) =>\n        inputValue === ''\n          ? intl.formatMessage(messages.starttyping)\n          : intl.formatMessage(messages.nooptions)\n      }\n      defaultValue={defaultDataValue}\n      loadOptions={loadKeywordOptions}\n      placeholder={intl.formatMessage(messages.searchKeywords)}\n      onChange={(value) => {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        onChange(value as any);\n      }}\n    />\n  );\n};\n\ntype WatchProviderSelectorProps = {\n  type: 'movie' | 'tv';\n  region?: string;\n  activeProviders?: number[];\n  onChange: (region: string, value: number[]) => void;\n};\n\nexport const WatchProviderSelector = ({\n  type,\n  onChange,\n  region,\n  activeProviders,\n}: WatchProviderSelectorProps) => {\n  const intl = useIntl();\n  const { currentSettings } = useSettings();\n  const [showMore, setShowMore] = useState(false);\n  const [watchRegion, setWatchRegion] = useState(\n    region\n      ? region\n      : currentSettings.discoverRegion\n        ? currentSettings.discoverRegion\n        : 'US'\n  );\n  const [activeProvider, setActiveProvider] = useState<number[]>(\n    activeProviders ?? []\n  );\n  const { data, isLoading } = useSWR<WatchProviderDetails[]>(\n    `/api/v1/watchproviders/${\n      type === 'movie' ? 'movies' : 'tv'\n    }?watchRegion=${watchRegion}`\n  );\n\n  useEffect(() => {\n    onChange(watchRegion, activeProvider);\n    // removed onChange as a dependency as we only need to call it when the value(s) change\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [activeProvider, watchRegion]);\n\n  const orderedData = useMemo(() => {\n    if (!data) {\n      return [];\n    }\n\n    return orderBy(data, ['display_priority'], ['asc']);\n  }, [data]);\n\n  const toggleProvider = (id: number) => {\n    if (activeProvider.includes(id)) {\n      setActiveProvider(activeProvider.filter((p) => p !== id));\n    } else {\n      setActiveProvider([...activeProvider, id]);\n    }\n  };\n\n  const initialProviders = orderedData.slice(0, 24);\n  const otherProviders = orderedData.slice(24);\n\n  return (\n    <>\n      <RegionSelector\n        value={watchRegion}\n        name=\"watchRegion\"\n        onChange={(_name, value) => {\n          if (value !== watchRegion) {\n            setActiveProvider([]);\n          }\n          setWatchRegion(value);\n        }}\n        disableAll\n        watchProviders\n      />\n      {isLoading ? (\n        <SmallLoadingSpinner />\n      ) : (\n        <div className=\"grid\">\n          <div className=\"provider-icons grid gap-2\">\n            {initialProviders.map((provider) => {\n              const isActive = activeProvider.includes(provider.id);\n              return (\n                <Tooltip\n                  content={provider.name}\n                  key={`prodiver-${provider.id}`}\n                >\n                  <div\n                    className={`provider-container relative w-full cursor-pointer rounded-lg ring-1 ${\n                      isActive\n                        ? 'bg-gray-600 ring-indigo-500 hover:bg-gray-500'\n                        : 'bg-gray-700 ring-gray-500 hover:bg-gray-600'\n                    }`}\n                    onClick={() => toggleProvider(provider.id)}\n                    onKeyDown={(e) => {\n                      if (e.key === 'Enter') {\n                        toggleProvider(provider.id);\n                      }\n                    }}\n                    role=\"button\"\n                    tabIndex={0}\n                  >\n                    <div className=\"relative m-2 aspect-1\">\n                      <CachedImage\n                        type=\"tmdb\"\n                        src={`https://image.tmdb.org/t/p/original${provider.logoPath}`}\n                        alt=\"\"\n                        fill\n                        className=\"rounded-lg object-contain\"\n                      />\n                    </div>\n                    {isActive && (\n                      <div className=\"pointer-events-none absolute -left-1 -top-1 flex items-center justify-center text-indigo-100 opacity-90\">\n                        <CheckCircleIcon className=\"h-6 w-6\" />\n                      </div>\n                    )}\n                  </div>\n                </Tooltip>\n              );\n            })}\n          </div>\n          {showMore && otherProviders.length > 0 && (\n            <div className=\"provider-icons relative top-2 grid gap-2\">\n              {otherProviders.map((provider) => {\n                const isActive = activeProvider.includes(provider.id);\n                return (\n                  <Tooltip\n                    content={provider.name}\n                    key={`prodiver-${provider.id}`}\n                  >\n                    <div\n                      className={`provider-container relative w-full cursor-pointer rounded-lg ring-1 transition ${\n                        isActive\n                          ? 'bg-gray-600 ring-indigo-500 hover:bg-gray-500'\n                          : 'bg-gray-700 ring-gray-500 hover:bg-gray-600'\n                      }`}\n                      onClick={() => toggleProvider(provider.id)}\n                      onKeyDown={(e) => {\n                        if (e.key === 'Enter') {\n                          toggleProvider(provider.id);\n                        }\n                      }}\n                      role=\"button\"\n                      tabIndex={0}\n                    >\n                      <div className=\"relative m-2 aspect-1\">\n                        <CachedImage\n                          type=\"tmdb\"\n                          src={`https://image.tmdb.org/t/p/original${provider.logoPath}`}\n                          alt=\"\"\n                          fill\n                          className=\"rounded-lg object-contain\"\n                        />\n                      </div>\n                      {isActive && (\n                        <div className=\"pointer-events-none absolute -left-1 -top-1 flex items-center justify-center text-indigo-100 opacity-90\">\n                          <CheckCircleIcon className=\"h-6 w-6\" />\n                        </div>\n                      )}\n                    </div>\n                  </Tooltip>\n                );\n              })}\n            </div>\n          )}\n          {otherProviders.length > 0 && (\n            <button\n              className=\"relative top-4 flex items-center justify-center space-x-2 text-sm text-gray-400 transition hover:text-gray-200\"\n              type=\"button\"\n              onClick={() => setShowMore(!showMore)}\n            >\n              <div className=\"h-0.5 flex-1 bg-gray-600\" />\n              {showMore ? (\n                <>\n                  <ArrowUpIcon className=\"h-4 w-4\" />\n                  <span>{intl.formatMessage(messages.showless)}</span>\n                  <ArrowUpIcon className=\"h-4 w-4\" />\n                </>\n              ) : (\n                <>\n                  <ArrowDownIcon className=\"h-4 w-4\" />\n                  <span>{intl.formatMessage(messages.showmore)}</span>\n                  <ArrowDownIcon className=\"h-4 w-4\" />\n                </>\n              )}\n              <div className=\"h-0.5 flex-1 bg-gray-600\" />\n            </button>\n          )}\n        </div>\n      )}\n    </>\n  );\n};\n\nexport const UserSelector = ({\n  isMulti,\n  isDisabled,\n  defaultValue,\n  onChange,\n}: BaseSelectorMultiProps | BaseSelectorSingleProps) => {\n  const intl = useIntl();\n  const [defaultDataValue, setDefaultDataValue] = useState<\n    { label: string; value: number }[] | null\n  >(null);\n\n  useEffect(() => {\n    const loadUsers = async (): Promise<void> => {\n      if (!defaultValue) {\n        return;\n      }\n\n      const users = defaultValue.split(',');\n\n      const res = await axios.get(\n        `/api/v1/user?includeIds=${encodeURIComponent(defaultValue)}`\n      );\n      const response: UserResultsResponse = res.data;\n\n      const genreData = users\n        .filter((u) => response.results.find((user) => user.id === Number(u)))\n        .map((u) => response.results.find((user) => user.id === Number(u)))\n        .map((u) => ({\n          label: u?.displayName ?? '',\n          value: u?.id ?? 0,\n        }));\n\n      setDefaultDataValue(genreData);\n    };\n\n    loadUsers();\n  }, [defaultValue]);\n\n  const loadUserOptions = async (inputValue: string) => {\n    const res = await axios.get(\n      `/api/v1/user${inputValue ? `?q=${encodeURIComponent(inputValue)}` : ''}`\n    );\n    const results: UserResultsResponse = res.data;\n\n    return results.results\n      .map((result) => ({\n        label: result.displayName,\n        value: result.id,\n      }))\n      .filter(({ label }) =>\n        label.toLowerCase().includes(inputValue.toLowerCase())\n      );\n  };\n\n  return (\n    <AsyncSelect\n      key={`user-select-${defaultDataValue}`}\n      className=\"react-select-container\"\n      classNamePrefix=\"react-select\"\n      defaultValue={isMulti ? defaultDataValue : defaultDataValue?.[0]}\n      defaultOptions\n      cacheOptions\n      isMulti={isMulti}\n      isDisabled={isDisabled}\n      loadOptions={loadUserOptions}\n      placeholder={intl.formatMessage(messages.searchUsers)}\n      onChange={(value) => {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        onChange(value as any);\n      }}\n    />\n  );\n};\n\nexport { default as USCertificationSelector } from './USCertificationSelector';\n"
  },
  {
    "path": "src/components/ServiceWorkerSetup/index.tsx",
    "content": "/* eslint-disable no-console */\n\nimport useSettings from '@app/hooks/useSettings';\nimport { useUser } from '@app/hooks/useUser';\nimport { verifyAndResubscribePushSubscription } from '@app/utils/pushSubscriptionHelpers';\nimport { useEffect } from 'react';\n\nconst ServiceWorkerSetup = () => {\n  const { user } = useUser();\n  const { currentSettings } = useSettings();\n\n  useEffect(() => {\n    if ('serviceWorker' in navigator && user?.id) {\n      navigator.serviceWorker\n        .register('/sw.js')\n        .then(async (registration) => {\n          console.log(\n            '[SW] Registration successful, scope is:',\n            registration.scope\n          );\n\n          const pushNotificationsEnabled =\n            localStorage.getItem('pushNotificationsEnabled') === 'true';\n\n          // Reset the notifications flag if permissions were revoked\n          if (\n            Notification.permission !== 'granted' &&\n            pushNotificationsEnabled\n          ) {\n            localStorage.setItem('pushNotificationsEnabled', 'false');\n            console.warn(\n              '[SW] Push permissions not granted — skipping resubscribe'\n            );\n\n            return;\n          }\n\n          // Bypass resubscribing if we have manually disabled push notifications\n          if (!pushNotificationsEnabled) {\n            return;\n          }\n\n          const subscription = await registration.pushManager.getSubscription();\n\n          console.log(\n            '[SW] Existing push subscription:',\n            subscription?.endpoint\n          );\n\n          const verified = await verifyAndResubscribePushSubscription(\n            user.id,\n            currentSettings\n          );\n\n          if (verified) {\n            console.log('[SW] Push subscription verified or refreshed.');\n          } else {\n            console.warn(\n              '[SW] Push subscription verification failed or not available.'\n            );\n          }\n        })\n        .catch(function (error) {\n          console.log('[SW] Service worker registration failed, error:', error);\n        });\n    }\n  }, [currentSettings, user]);\n  return null;\n};\n\nexport default ServiceWorkerSetup;\n"
  },
  {
    "path": "src/components/Settings/CopyButton.tsx",
    "content": "import Tooltip from '@app/components/Common/Tooltip';\nimport { ClipboardDocumentIcon } from '@heroicons/react/24/solid';\nimport React, { useEffect } from 'react';\nimport type { Config } from 'react-popper-tooltip';\nimport { useToasts } from 'react-toast-notifications';\nimport useClipboard from 'react-use-clipboard';\n\ntype CopyButtonProps = {\n  textToCopy: string;\n  disabled?: boolean;\n  toastMessage?: string;\n\n  tooltipContent?: React.ReactNode;\n  tooltipConfig?: Partial<Config>;\n};\n\nconst CopyButton = ({\n  textToCopy,\n  disabled,\n  toastMessage,\n  tooltipContent,\n  tooltipConfig,\n}: CopyButtonProps) => {\n  const [isCopied, setCopied] = useClipboard(textToCopy, {\n    successDuration: 1000,\n  });\n  const { addToast } = useToasts();\n\n  useEffect(() => {\n    if (isCopied && toastMessage) {\n      addToast(toastMessage, {\n        appearance: 'info',\n        autoDismiss: true,\n      });\n    }\n  }, [isCopied, addToast, toastMessage]);\n\n  return (\n    <Tooltip content={tooltipContent} tooltipConfig={tooltipConfig}>\n      <button\n        onClick={(e) => {\n          e.preventDefault();\n          setCopied();\n        }}\n        className=\"input-action\"\n        type=\"button\"\n        disabled={disabled}\n      >\n        <ClipboardDocumentIcon />\n      </button>\n    </Tooltip>\n  );\n};\n\nexport default CopyButton;\n"
  },
  {
    "path": "src/components/Settings/LibraryItem.tsx",
    "content": "import { CheckIcon, XMarkIcon } from '@heroicons/react/24/solid';\n\ninterface LibraryItemProps {\n  isEnabled?: boolean;\n  name: string;\n  onToggle: () => void;\n}\n\nconst LibraryItem = ({ isEnabled, name, onToggle }: LibraryItemProps) => {\n  return (\n    <li className=\"col-span-1 flex rounded-md shadow-sm\">\n      <div className=\"flex flex-1 items-center justify-between truncate rounded-md border-b border-r border-t border-gray-700 bg-gray-600\">\n        <div className=\"flex-1 cursor-default truncate px-4 py-6 text-sm leading-5\">\n          {name}\n        </div>\n        <div className=\"flex-shrink-0 pr-2\">\n          <span\n            role=\"checkbox\"\n            tabIndex={0}\n            aria-checked={isEnabled}\n            onClick={() => onToggle()}\n            onKeyDown={(e) => {\n              if (e.key === 'Enter') {\n                onToggle();\n              }\n            }}\n            className={`${\n              isEnabled ? 'bg-indigo-600' : 'bg-gray-700'\n            } relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring`}\n          >\n            <span\n              aria-hidden=\"true\"\n              className={`${\n                isEnabled ? 'translate-x-5' : 'translate-x-0'\n              } relative inline-block h-5 w-5 rounded-full bg-white shadow transition duration-200 ease-in-out`}\n            >\n              <span\n                className={`${\n                  isEnabled\n                    ? 'opacity-0 duration-100 ease-out'\n                    : 'opacity-100 duration-200 ease-in'\n                } absolute inset-0 flex h-full w-full items-center justify-center transition-opacity`}\n              >\n                <XMarkIcon className=\"h-3 w-3 text-gray-400\" />\n              </span>\n              <span\n                className={`${\n                  isEnabled\n                    ? 'opacity-100 duration-200 ease-in'\n                    : 'opacity-0 duration-100 ease-out'\n                } absolute inset-0 flex h-full w-full items-center justify-center transition-opacity`}\n              >\n                <CheckIcon className=\"h-3 w-3 text-indigo-600\" />\n              </span>\n            </span>\n          </span>\n        </div>\n      </div>\n    </li>\n  );\n};\n\nexport default LibraryItem;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsDiscord.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport useSettings from '@app/hooks/useSettings';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Settings.Notifications', {\n  agentenabled: 'Enable Agent',\n  embedPoster: 'Embed Poster',\n  botUsername: 'Bot Username',\n  botAvatarUrl: 'Bot Avatar URL',\n  webhookUrl: 'Webhook URL',\n  webhookUrlTip:\n    'Create a <DiscordWebhookLink>webhook integration</DiscordWebhookLink> in your server',\n  webhookRoleId: 'Notification Role ID',\n  webhookRoleIdTip:\n    'The role ID to mention in the webhook message. Leave empty to disable mentions',\n  discordsettingssaved: 'Discord notification settings saved successfully!',\n  discordsettingsfailed: 'Discord notification settings failed to save.',\n  toastDiscordTestSending: 'Sending Discord test notification…',\n  toastDiscordTestSuccess: 'Discord test notification sent!',\n  toastDiscordTestFailed: 'Discord test notification failed to send.',\n  validationUrl: 'You must provide a valid URL',\n  validationWebhookRoleId: 'You must provide a valid Discord Role ID',\n  validationTypes: 'You must select at least one notification type',\n  enableMentions: 'Enable Mentions',\n});\n\nconst NotificationsDiscord = () => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR('/api/v1/settings/notifications/discord');\n\n  const NotificationsDiscordSchema = Yup.object().shape({\n    botAvatarUrl: Yup.string()\n      .nullable()\n      .url(intl.formatMessage(messages.validationUrl)),\n    webhookUrl: Yup.string()\n      .when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationUrl)),\n        otherwise: Yup.string().nullable(),\n      })\n      .url(intl.formatMessage(messages.validationUrl)),\n    webhookRoleId: Yup.string()\n      .nullable()\n      .matches(\n        /^\\d{17,19}$/,\n        intl.formatMessage(messages.validationWebhookRoleId)\n      ),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        enabled: data.enabled,\n        embedPoster: data.embedPoster,\n        types: data.types,\n        botUsername: data?.options.botUsername,\n        botAvatarUrl: data?.options.botAvatarUrl,\n        webhookUrl: data.options.webhookUrl,\n        webhookRoleId: data?.options.webhookRoleId,\n        enableMentions: data?.options.enableMentions,\n      }}\n      validationSchema={NotificationsDiscordSchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/settings/notifications/discord', {\n            enabled: values.enabled,\n            embedPoster: values.embedPoster,\n            types: values.types,\n            options: {\n              botUsername: values.botUsername,\n              botAvatarUrl: values.botAvatarUrl,\n              webhookUrl: values.webhookUrl,\n              webhookRoleId: values.webhookRoleId,\n              enableMentions: values.enableMentions,\n            },\n          });\n\n          addToast(intl.formatMessage(messages.discordsettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.discordsettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        values,\n        isValid,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        const testSettings = async () => {\n          setIsTesting(true);\n          let toastId: string | undefined;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastDiscordTestSending),\n              {\n                autoDismiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/notifications/discord/test', {\n              enabled: true,\n              embedPoster: values.embedPoster,\n              types: values.types,\n              options: {\n                botUsername: values.botUsername,\n                botAvatarUrl: values.botAvatarUrl,\n                webhookUrl: values.webhookUrl,\n                webhookRoleId: values.webhookRoleId,\n                enableMentions: values.enableMentions,\n              },\n            });\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastDiscordTestSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastDiscordTestFailed), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            setIsTesting(false);\n          }\n        };\n\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"enabled\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.agentenabled)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"embedPoster\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.embedPoster)}\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"embedPoster\" name=\"embedPoster\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"name\" className=\"text-label\">\n                {intl.formatMessage(messages.webhookUrl)}\n                <span className=\"label-required\">*</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.webhookUrlTip, {\n                    DiscordWebhookLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks\"\n                        className=\"text-white transition duration-300 hover:underline\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"webhookUrl\"\n                    name=\"webhookUrl\"\n                    type=\"text\"\n                    inputMode=\"url\"\n                  />\n                </div>\n                {errors.webhookUrl &&\n                  touched.webhookUrl &&\n                  typeof errors.webhookUrl === 'string' && (\n                    <div className=\"error\">{errors.webhookUrl}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"botUsername\" className=\"text-label\">\n                {intl.formatMessage(messages.botUsername)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"botUsername\"\n                    name=\"botUsername\"\n                    type=\"text\"\n                    placeholder={settings.currentSettings.applicationTitle}\n                    autoComplete=\"off\"\n                    data-form-type=\"other\"\n                    data-1pignore=\"true\"\n                    data-lpignore=\"true\"\n                    data-bwignore=\"true\"\n                  />\n                </div>\n                {errors.botUsername &&\n                  touched.botUsername &&\n                  typeof errors.botUsername === 'string' && (\n                    <div className=\"error\">{errors.botUsername}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"botAvatarUrl\" className=\"text-label\">\n                {intl.formatMessage(messages.botAvatarUrl)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"botAvatarUrl\"\n                    name=\"botAvatarUrl\"\n                    type=\"text\"\n                    inputMode=\"url\"\n                  />\n                </div>\n                {errors.botAvatarUrl &&\n                  touched.botAvatarUrl &&\n                  typeof errors.botAvatarUrl === 'string' && (\n                    <div className=\"error\">{errors.botAvatarUrl}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"webhookRoleId\" className=\"text-label\">\n                {intl.formatMessage(messages.webhookRoleId)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"webhookRoleId\" name=\"webhookRoleId\" type=\"text\" />\n                </div>\n                {errors.webhookRoleId &&\n                  touched.webhookRoleId &&\n                  typeof errors.webhookRoleId === 'string' && (\n                    <div className=\"error\">{errors.webhookRoleId}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"enableMentions\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.enableMentions)}\n              </label>\n              <div className=\"form-input-area\">\n                <Field\n                  type=\"checkbox\"\n                  id=\"enableMentions\"\n                  name=\"enableMentions\"\n                />\n              </div>\n            </div>\n            <NotificationTypeSelector\n              currentTypes={values.enabled ? values.types : 0}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n\n                if (newTypes) {\n                  setFieldValue('enabled', true);\n                }\n              }}\n              error={\n                values.enabled && !values.types && touched.types\n                  ? intl.formatMessage(messages.validationTypes)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"warning\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                    onClick={(e) => {\n                      e.preventDefault();\n                      testSettings();\n                    }}\n                  >\n                    <BeakerIcon />\n                    <span>\n                      {isTesting\n                        ? intl.formatMessage(globalMessages.testing)\n                        : intl.formatMessage(globalMessages.test)}\n                    </span>\n                  </Button>\n                </span>\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={\n                      isSubmitting ||\n                      !isValid ||\n                      isTesting ||\n                      (values.enabled && !values.types)\n                    }\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default NotificationsDiscord;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsEmail.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport SettingsBadge from '@app/components/Settings/SettingsBadge';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\nimport validator from 'validator';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Settings.Notifications', {\n  validationSmtpHostRequired: 'You must provide a valid hostname or IP address',\n  validationSmtpPortRequired: 'You must provide a valid port number',\n  agentenabled: 'Enable Agent',\n  embedPoster: 'Embed Poster',\n  userEmailRequired: 'Require user email',\n  emailsender: 'Sender Address',\n  smtpHost: 'SMTP Host',\n  smtpPort: 'SMTP Port',\n  encryption: 'Encryption Method',\n  encryptionTip:\n    'In most cases, Implicit TLS uses port 465 and STARTTLS uses port 587',\n  encryptionNone: 'None',\n  encryptionDefault: 'Use STARTTLS if available',\n  encryptionOpportunisticTls: 'Always use STARTTLS',\n  encryptionImplicitTls: 'Use Implicit TLS',\n  authUser: 'SMTP Username',\n  authPass: 'SMTP Password',\n  emailsettingssaved: 'Email notification settings saved successfully!',\n  emailsettingsfailed: 'Email notification settings failed to save.',\n  toastEmailTestSending: 'Sending email test notification…',\n  toastEmailTestSuccess: 'Email test notification sent!',\n  toastEmailTestFailed: 'Email test notification failed to send.',\n  allowselfsigned: 'Allow Self-Signed Certificates',\n  senderName: 'Sender Name',\n  validationEmail: 'You must provide a valid email address',\n  pgpPrivateKey: 'PGP Private Key',\n  pgpPrivateKeyTip:\n    'Sign encrypted email messages using <OpenPgpLink>OpenPGP</OpenPgpLink>',\n  validationPgpPrivateKey: 'You must provide a valid PGP private key',\n  pgpPassword: 'PGP Password',\n  pgpPasswordTip:\n    'Sign encrypted email messages using <OpenPgpLink>OpenPGP</OpenPgpLink>',\n  validationPgpPassword: 'You must provide a PGP password',\n});\n\nexport function OpenPgpLink(msg: React.ReactNode) {\n  return (\n    <a href=\"https://www.openpgp.org/\" target=\"_blank\" rel=\"noreferrer\">\n      {msg}\n    </a>\n  );\n}\n\nconst NotificationsEmail = () => {\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR('/api/v1/settings/notifications/email');\n\n  const NotificationsEmailSchema = Yup.object().shape(\n    {\n      emailFrom: Yup.string()\n        .when('enabled', {\n          is: true,\n          then: Yup.string()\n            .nullable()\n            .required(intl.formatMessage(messages.validationEmail)),\n          otherwise: Yup.string().nullable(),\n        })\n        .test(\n          'email',\n          intl.formatMessage(messages.validationEmail),\n          (value) => !value || validator.isEmail(value, { require_tld: false })\n        ),\n      smtpHost: Yup.string().when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationSmtpHostRequired)),\n        otherwise: Yup.string().nullable(),\n      }),\n      smtpPort: Yup.number().when('enabled', {\n        is: true,\n        then: Yup.number()\n          .nullable()\n          .required(intl.formatMessage(messages.validationSmtpPortRequired)),\n        otherwise: Yup.number().nullable(),\n      }),\n      pgpPrivateKey: Yup.string()\n        .when('pgpPassword', {\n          is: (value: unknown) => !!value,\n          then: Yup.string()\n            .nullable()\n            .required(intl.formatMessage(messages.validationPgpPrivateKey)),\n          otherwise: Yup.string().nullable(),\n        })\n        .matches(\n          /-----BEGIN PGP PRIVATE KEY BLOCK-----.+-----END PGP PRIVATE KEY BLOCK-----/s,\n          intl.formatMessage(messages.validationPgpPrivateKey)\n        ),\n      pgpPassword: Yup.string().when('pgpPrivateKey', {\n        is: (value: unknown) => !!value,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationPgpPassword)),\n        otherwise: Yup.string().nullable(),\n      }),\n    },\n    [['pgpPrivateKey', 'pgpPassword']]\n  );\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        enabled: data.enabled,\n        embedPoster: data.embedPoster,\n        userEmailRequired: data.options.userEmailRequired,\n        emailFrom: data.options.emailFrom,\n        smtpHost: data.options.smtpHost,\n        smtpPort: data.options.smtpPort ?? 587,\n        encryption: data.options.secure\n          ? 'implicit'\n          : data.options.requireTls\n            ? 'opportunistic'\n            : data.options.ignoreTls\n              ? 'none'\n              : 'default',\n        authUser: data.options.authUser,\n        authPass: data.options.authPass,\n        allowSelfSigned: data.options.allowSelfSigned,\n        senderName: data.options.senderName,\n        pgpPrivateKey: data.options.pgpPrivateKey,\n        pgpPassword: data.options.pgpPassword,\n      }}\n      validationSchema={NotificationsEmailSchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/settings/notifications/email', {\n            enabled: values.enabled,\n            embedPoster: values.embedPoster,\n            options: {\n              userEmailRequired: values.userEmailRequired,\n              emailFrom: values.emailFrom,\n              smtpHost: values.smtpHost,\n              smtpPort: Number(values.smtpPort),\n              secure: values.encryption === 'implicit',\n              ignoreTls: values.encryption === 'none',\n              requireTls: values.encryption === 'opportunistic',\n              authUser: values.authUser,\n              authPass: values.authPass,\n              allowSelfSigned: values.allowSelfSigned,\n              senderName: values.senderName,\n              pgpPrivateKey: values.pgpPrivateKey,\n              pgpPassword: values.pgpPassword,\n            },\n          });\n          mutate('/api/v1/settings/public');\n\n          addToast(intl.formatMessage(messages.emailsettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.emailsettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({ errors, touched, isSubmitting, values, isValid }) => {\n        const testSettings = async () => {\n          setIsTesting(true);\n          let toastId: string | undefined;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastEmailTestSending),\n              {\n                autoDismiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/notifications/email/test', {\n              enabled: true,\n              embedPoster: values.embedPoster,\n              options: {\n                emailFrom: values.emailFrom,\n                smtpHost: values.smtpHost,\n                smtpPort: Number(values.smtpPort),\n                secure: values.encryption === 'implicit',\n                ignoreTls: values.encryption === 'none',\n                requireTls: values.encryption === 'opportunistic',\n                authUser: values.authUser,\n                authPass: values.authPass,\n                allowSelfSigned: values.allowSelfSigned,\n                senderName: values.senderName,\n                pgpPrivateKey: values.pgpPrivateKey,\n                pgpPassword: values.pgpPassword,\n              },\n            });\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastEmailTestSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastEmailTestFailed), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            setIsTesting(false);\n          }\n        };\n\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"enabled\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.agentenabled)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"embedPoster\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.embedPoster)}\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"embedPoster\" name=\"embedPoster\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"userEmailRequired\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.userEmailRequired)}\n              </label>\n              <div className=\"form-input-area\">\n                <Field\n                  type=\"checkbox\"\n                  id=\"userEmailRequired\"\n                  name=\"userEmailRequired\"\n                />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"senderName\" className=\"text-label\">\n                {intl.formatMessage(messages.senderName)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"senderName\" name=\"senderName\" type=\"text\" />\n                </div>\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"emailFrom\" className=\"text-label\">\n                {intl.formatMessage(messages.emailsender)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"emailFrom\"\n                    name=\"emailFrom\"\n                    type=\"text\"\n                    inputMode=\"email\"\n                    autoComplete=\"off\"\n                    data-form-type=\"other\"\n                    data-1pignore=\"true\"\n                    data-lpignore=\"true\"\n                    data-bwignore=\"true\"\n                  />\n                </div>\n                {errors.emailFrom &&\n                  touched.emailFrom &&\n                  typeof errors.emailFrom === 'string' && (\n                    <div className=\"error\">{errors.emailFrom}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"smtpHost\" className=\"text-label\">\n                {intl.formatMessage(messages.smtpHost)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"smtpHost\"\n                    name=\"smtpHost\"\n                    type=\"text\"\n                    inputMode=\"url\"\n                    autoComplete=\"off\"\n                    data-form-type=\"other\"\n                    data-1pignore=\"true\"\n                    data-lpignore=\"true\"\n                    data-bwignore=\"true\"\n                  />\n                </div>\n                {errors.smtpHost &&\n                  touched.smtpHost &&\n                  typeof errors.smtpHost === 'string' && (\n                    <div className=\"error\">{errors.smtpHost}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"smtpPort\" className=\"text-label\">\n                {intl.formatMessage(messages.smtpPort)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field\n                  id=\"smtpPort\"\n                  name=\"smtpPort\"\n                  type=\"text\"\n                  inputMode=\"numeric\"\n                  className=\"short\"\n                  autoComplete=\"off\"\n                  data-form-type=\"other\"\n                  data-1pignore=\"true\"\n                  data-lpignore=\"true\"\n                  data-bwignore=\"true\"\n                />\n                {errors.smtpPort &&\n                  touched.smtpPort &&\n                  typeof errors.smtpPort === 'string' && (\n                    <div className=\"error\">{errors.smtpPort}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"encryption\" className=\"text-label\">\n                {intl.formatMessage(messages.encryption)}\n                <span className=\"label-required\">*</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.encryptionTip)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field as=\"select\" id=\"encryption\" name=\"encryption\">\n                    <option value=\"none\">\n                      {intl.formatMessage(messages.encryptionNone)}\n                    </option>\n                    <option value=\"default\">\n                      {intl.formatMessage(messages.encryptionDefault)}\n                    </option>\n                    <option value=\"opportunistic\">\n                      {intl.formatMessage(messages.encryptionOpportunisticTls)}\n                    </option>\n                    <option value=\"implicit\">\n                      {intl.formatMessage(messages.encryptionImplicitTls)}\n                    </option>\n                  </Field>\n                </div>\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"allowSelfSigned\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.allowselfsigned)}\n              </label>\n              <div className=\"form-input-area\">\n                <Field\n                  type=\"checkbox\"\n                  id=\"allowSelfSigned\"\n                  name=\"allowSelfSigned\"\n                />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"authUser\" className=\"text-label\">\n                {intl.formatMessage(messages.authUser)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"authUser\"\n                    name=\"authUser\"\n                    type=\"text\"\n                    autoComplete=\"off\"\n                    data-form-type=\"other\"\n                    data-1pignore=\"true\"\n                    data-lpignore=\"true\"\n                    data-bwignore=\"true\"\n                  />\n                </div>\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"authPass\" className=\"text-label\">\n                {intl.formatMessage(messages.authPass)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <SensitiveInput as=\"field\" id=\"authPass\" name=\"authPass\" />\n                </div>\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"pgpPrivateKey\" className=\"text-label\">\n                <span className=\"mr-2\">\n                  {intl.formatMessage(messages.pgpPrivateKey)}\n                </span>\n                <SettingsBadge badgeType=\"advanced\" />\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.pgpPrivateKeyTip, {\n                    OpenPgpLink: OpenPgpLink,\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <SensitiveInput\n                    as=\"field\"\n                    id=\"pgpPrivateKey\"\n                    name=\"pgpPrivateKey\"\n                    type=\"textarea\"\n                    rows=\"10\"\n                    className=\"font-mono text-xs\"\n                    autoComplete=\"off\"\n                    data-form-type=\"other\"\n                    data-1pignore=\"true\"\n                    data-lpignore=\"true\"\n                    data-bwignore=\"true\"\n                  />\n                </div>\n                {errors.pgpPrivateKey &&\n                  touched.pgpPrivateKey &&\n                  typeof errors.pgpPrivateKey === 'string' && (\n                    <div className=\"error\">{errors.pgpPrivateKey}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"pgpPassword\" className=\"text-label\">\n                <span className=\"mr-2\">\n                  {intl.formatMessage(messages.pgpPassword)}\n                </span>\n                <SettingsBadge badgeType=\"advanced\" />\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.pgpPasswordTip, {\n                    OpenPgpLink: OpenPgpLink,\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <SensitiveInput\n                    as=\"field\"\n                    id=\"pgpPassword\"\n                    name=\"pgpPassword\"\n                    autoComplete=\"off\"\n                    data-form-type=\"other\"\n                    data-1pignore=\"true\"\n                    data-lpignore=\"true\"\n                    data-bwignore=\"true\"\n                  />\n                </div>\n                {errors.pgpPassword &&\n                  touched.pgpPassword &&\n                  typeof errors.pgpPassword === 'string' && (\n                    <div className=\"error\">{errors.pgpPassword}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"warning\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                    onClick={(e) => {\n                      e.preventDefault();\n                      testSettings();\n                    }}\n                  >\n                    <BeakerIcon />\n                    <span>\n                      {isTesting\n                        ? intl.formatMessage(globalMessages.testing)\n                        : intl.formatMessage(globalMessages.test)}\n                    </span>\n                  </Button>\n                </span>\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default NotificationsEmail;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsGotify/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { isValidURL } from '@app/utils/urlValidationHelper';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/solid';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.Settings.Notifications.NotificationsGotify',\n  {\n    agentenabled: 'Enable Agent',\n    url: 'Server URL',\n    token: 'Application Token',\n    priority: 'Priority',\n    validationUrlRequired: 'You must provide a valid URL',\n    validationUrlTrailingSlash: 'URL must not end in a trailing slash',\n    validationTokenRequired: 'You must provide an application token',\n    validationPriorityRequired: 'You must set a priority number',\n    gotifysettingssaved: 'Gotify notification settings saved successfully!',\n    gotifysettingsfailed: 'Gotify notification settings failed to save.',\n    toastGotifyTestSending: 'Sending Gotify test notification…',\n    toastGotifyTestSuccess: 'Gotify test notification sent!',\n    toastGotifyTestFailed: 'Gotify test notification failed to send.',\n    validationTypes: 'You must select at least one notification type',\n  }\n);\n\nconst NotificationsGotify = () => {\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR('/api/v1/settings/notifications/gotify');\n\n  const NotificationsGotifySchema = Yup.object().shape({\n    url: Yup.string()\n      .when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationUrlRequired)),\n        otherwise: Yup.string().nullable(),\n      })\n      .test(\n        'valid-url',\n        intl.formatMessage(messages.validationUrlRequired),\n        isValidURL\n      )\n      .test(\n        'no-trailing-slash',\n        intl.formatMessage(messages.validationUrlTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n    token: Yup.string().when('enabled', {\n      is: true,\n      then: Yup.string()\n        .nullable()\n        .required(intl.formatMessage(messages.validationTokenRequired)),\n      otherwise: Yup.string().nullable(),\n    }),\n    priority: Yup.string().when('enabled', {\n      is: true,\n      then: Yup.string()\n        .nullable()\n        .min(0)\n        .max(9)\n        .required(intl.formatMessage(messages.validationPriorityRequired)),\n      otherwise: Yup.string().nullable(),\n    }),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        enabled: data?.enabled,\n        types: data?.types,\n        url: data?.options.url,\n        token: data?.options.token,\n        priority: data?.options.priority,\n      }}\n      validationSchema={NotificationsGotifySchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/settings/notifications/gotify', {\n            enabled: values.enabled,\n            types: values.types,\n            options: {\n              url: values.url,\n              token: values.token,\n              priority: Number(values.priority),\n            },\n          });\n          addToast(intl.formatMessage(messages.gotifysettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.gotifysettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        values,\n        isValid,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        const testSettings = async () => {\n          setIsTesting(true);\n          let toastId: string | undefined;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastGotifyTestSending),\n              {\n                autoDsmiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/notifications/gotify/test', {\n              enabled: true,\n              types: values.types,\n              options: {\n                url: values.url,\n                token: values.token,\n                priority: Number(values.priority),\n              },\n            });\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastGotifyTestSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastGotifyTestFailed), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            setIsTesting(false);\n          }\n        };\n\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"enabled\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.agentenabled)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"url\" className=\"text-label\">\n                {intl.formatMessage(messages.url)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"url\" name=\"url\" type=\"text\" />\n                </div>\n                {errors.url &&\n                  touched.url &&\n                  typeof errors.url === 'string' && (\n                    <div className=\"error\">{errors.url}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"token\" className=\"text-label\">\n                {intl.formatMessage(messages.token)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"token\" name=\"token\" type=\"text\" />\n                </div>\n                {errors.token &&\n                  touched.token &&\n                  typeof errors.token === 'string' && (\n                    <div className=\"error\">{errors.token}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"priority\" className=\"text-label\">\n                {intl.formatMessage(messages.priority)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field\n                  id=\"priority\"\n                  name=\"priority\"\n                  type=\"text\"\n                  inputMode=\"numeric\"\n                  className=\"short\"\n                  autoComplete=\"off\"\n                  data-1pignore=\"true\"\n                  data-lpignore=\"true\"\n                  data-bwignore=\"true\"\n                />\n                {errors.priority &&\n                  touched.priority &&\n                  typeof errors.priority === 'string' && (\n                    <div className=\"error\">{errors.priority}</div>\n                  )}\n              </div>\n            </div>\n            <NotificationTypeSelector\n              currentTypes={values.enabled ? values.types : 0}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n\n                if (newTypes) {\n                  setFieldValue('enabled', true);\n                }\n              }}\n              error={\n                values.enabled && !values.types && touched.types\n                  ? intl.formatMessage(messages.validationTypes)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"warning\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                    onClick={(e) => {\n                      e.preventDefault();\n                      testSettings();\n                    }}\n                  >\n                    <BeakerIcon />\n                    <span>\n                      {isTesting\n                        ? intl.formatMessage(globalMessages.testing)\n                        : intl.formatMessage(globalMessages.test)}\n                    </span>\n                  </Button>\n                </span>\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={\n                      isSubmitting ||\n                      !isValid ||\n                      isTesting ||\n                      (values.enabled && !values.types)\n                    }\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default NotificationsGotify;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsNtfy/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { isValidURL } from '@app/utils/urlValidationHelper';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';\nimport type { NotificationAgentNtfy } from '@server/lib/settings';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.Settings.Notifications.NotificationsNtfy',\n  {\n    agentenabled: 'Enable Agent',\n    embedPoster: 'Embed Poster',\n    url: 'Server root URL',\n    topic: 'Topic',\n    usernamePasswordAuth: 'Username + Password authentication',\n    username: 'Username',\n    password: 'Password',\n    tokenAuth: 'Token authentication',\n    token: 'Token',\n    priority: 'Priority',\n    ntfysettingssaved: 'Ntfy notification settings saved successfully!',\n    ntfysettingsfailed: 'Ntfy notification settings failed to save.',\n    toastNtfyTestSending: 'Sending ntfy test notification…',\n    toastNtfyTestSuccess: 'Ntfy test notification sent!',\n    toastNtfyTestFailed: 'Ntfy test notification failed to send.',\n    validationNtfyUrl: 'You must provide a valid URL',\n    validationNtfyTopic: 'You must provide a topic',\n    validationPriorityRequired: 'You must provide a priority between 1 and 5',\n    validationTypes: 'You must select at least one notification type',\n  }\n);\n\nconst NotificationsNtfy = () => {\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<NotificationAgentNtfy>('/api/v1/settings/notifications/ntfy');\n\n  const NotificationsNtfySchema = Yup.object().shape({\n    url: Yup.string()\n      .when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationNtfyUrl)),\n        otherwise: Yup.string().nullable(),\n      })\n      .test(\n        'valid-url',\n        intl.formatMessage(messages.validationNtfyUrl),\n        isValidURL\n      ),\n    topic: Yup.string()\n      .when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationNtfyUrl)),\n        otherwise: Yup.string().nullable(),\n      })\n      .defined(intl.formatMessage(messages.validationNtfyTopic)),\n    priority: Yup.number().when('enabled', {\n      is: true,\n      then: Yup.number()\n        .min(1)\n        .max(5)\n        .required(intl.formatMessage(messages.validationPriorityRequired)),\n      otherwise: Yup.number().nullable(),\n    }),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        enabled: data?.enabled,\n        embedPoster: data?.embedPoster,\n        types: data?.types,\n        url: data?.options.url,\n        topic: data?.options.topic,\n        authMethodUsernamePassword: data?.options.authMethodUsernamePassword,\n        username: data?.options.username,\n        password: data?.options.password,\n        authMethodToken: data?.options.authMethodToken,\n        token: data?.options.token,\n        priority: data?.options.priority,\n      }}\n      validationSchema={NotificationsNtfySchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/settings/notifications/ntfy', {\n            enabled: values.enabled,\n            embedPoster: values.embedPoster,\n            types: values.types,\n            options: {\n              url: values.url,\n              topic: values.topic,\n              authMethodUsernamePassword: values.authMethodUsernamePassword,\n              username: values.username,\n              password: values.password,\n              authMethodToken: values.authMethodToken,\n              token: values.token,\n              priority: values.priority,\n            },\n          });\n\n          addToast(intl.formatMessage(messages.ntfysettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.ntfysettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        values,\n        isValid,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        const testSettings = async () => {\n          setIsTesting(true);\n          let toastId: string | undefined;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastNtfyTestSending),\n              {\n                autoDismiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/notifications/ntfy/test', {\n              enabled: true,\n              types: values.types,\n              options: {\n                url: values.url,\n                topic: values.topic,\n                authMethodUsernamePassword: values.authMethodUsernamePassword,\n                username: values.username,\n                password: values.password,\n                authMethodToken: values.authMethodToken,\n                token: values.token,\n                priority: values.priority,\n              },\n            });\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastNtfyTestSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastNtfyTestFailed), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            setIsTesting(false);\n          }\n        };\n\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"enabled\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.agentenabled)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"embedPoster\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.embedPoster)}\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"embedPoster\" name=\"embedPoster\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"url\" className=\"text-label\">\n                {intl.formatMessage(messages.url)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"url\" name=\"url\" type=\"text\" inputMode=\"url\" />\n                </div>\n                {errors.url &&\n                  touched.url &&\n                  typeof errors.url === 'string' && (\n                    <div className=\"error\">{errors.url}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"topic\" className=\"text-label\">\n                {intl.formatMessage(messages.topic)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"topic\" name=\"topic\" type=\"text\" />\n                </div>\n                {errors.topic &&\n                  touched.topic &&\n                  typeof errors.topic === 'string' && (\n                    <div className=\"error\">{errors.topic}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label\n                htmlFor=\"authMethodUsernamePassword\"\n                className=\"checkbox-label\"\n              >\n                <span className=\"mr-2\">\n                  {intl.formatMessage(messages.usernamePasswordAuth)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field\n                  type=\"checkbox\"\n                  id=\"authMethodUsernamePassword\"\n                  name=\"authMethodUsernamePassword\"\n                  disabled={values.authMethodToken}\n                  onChange={() => {\n                    setFieldValue(\n                      'authMethodUsernamePassword',\n                      !values.authMethodUsernamePassword\n                    );\n                  }}\n                />\n              </div>\n            </div>\n            {values.authMethodUsernamePassword && (\n              <div className=\"ml-4 mr-2\">\n                <div className=\"form-row\">\n                  <label htmlFor=\"username\" className=\"text-label\">\n                    {intl.formatMessage(messages.username)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field id=\"username\" name=\"username\" type=\"text\" />\n                    </div>\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"password\" className=\"text-label\">\n                    {intl.formatMessage(messages.password)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <SensitiveInput\n                        as=\"field\"\n                        id=\"password\"\n                        name=\"password\"\n                      />\n                    </div>\n                  </div>\n                </div>\n              </div>\n            )}\n            <div className=\"form-row\">\n              <label htmlFor=\"authMethodToken\" className=\"checkbox-label\">\n                <span className=\"mr-2\">\n                  {intl.formatMessage(messages.tokenAuth)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field\n                  type=\"checkbox\"\n                  id=\"authMethodToken\"\n                  name=\"authMethodToken\"\n                  disabled={values.authMethodUsernamePassword}\n                  onChange={() => {\n                    setFieldValue('authMethodToken', !values.authMethodToken);\n                  }}\n                />\n              </div>\n            </div>\n            {values.authMethodToken && (\n              <div className=\"form-row ml-4 mr-2\">\n                <label htmlFor=\"token\" className=\"text-label\">\n                  {intl.formatMessage(messages.token)}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <SensitiveInput as=\"field\" id=\"token\" name=\"token\" />\n                  </div>\n                </div>\n              </div>\n            )}\n            <div className=\"form-row\">\n              <label htmlFor=\"priority\" className=\"text-label\">\n                {intl.formatMessage(messages.priority)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field as=\"select\" id=\"priority\" name=\"priority\">\n                    <option value={1}>Minimum</option>\n                    <option value={2}>Low</option>\n                    <option value={3}>Default</option>\n                    <option value={4}>High</option>\n                    <option value={5}>Urgent</option>\n                  </Field>\n                </div>\n              </div>\n            </div>\n            <NotificationTypeSelector\n              currentTypes={values.enabled ? values.types || 0 : 0}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n\n                if (newTypes) {\n                  setFieldValue('enabled', true);\n                }\n              }}\n              error={\n                values.enabled && !values.types && touched.types\n                  ? intl.formatMessage(messages.validationTypes)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"warning\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                    onClick={(e) => {\n                      e.preventDefault();\n                      testSettings();\n                    }}\n                  >\n                    <BeakerIcon />\n                    <span>\n                      {isTesting\n                        ? intl.formatMessage(globalMessages.testing)\n                        : intl.formatMessage(globalMessages.test)}\n                    </span>\n                  </Button>\n                </span>\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={\n                      isSubmitting ||\n                      !isValid ||\n                      isTesting ||\n                      (values.enabled && !values.types)\n                    }\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default NotificationsNtfy;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsPushbullet/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.Settings.Notifications.NotificationsPushbullet',\n  {\n    agentEnabled: 'Enable Agent',\n    accessToken: 'Access Token',\n    accessTokenTip:\n      'Create a token from your <PushbulletSettingsLink>Account Settings</PushbulletSettingsLink>',\n    validationAccessTokenRequired: 'You must provide an access token',\n    channelTag: 'Channel Tag',\n    pushbulletSettingsSaved:\n      'Pushbullet notification settings saved successfully!',\n    pushbulletSettingsFailed:\n      'Pushbullet notification settings failed to save.',\n    toastPushbulletTestSending: 'Sending Pushbullet test notification…',\n    toastPushbulletTestSuccess: 'Pushbullet test notification sent!',\n    toastPushbulletTestFailed: 'Pushbullet test notification failed to send.',\n    validationTypes: 'You must select at least one notification type',\n  }\n);\n\nconst NotificationsPushbullet = () => {\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR('/api/v1/settings/notifications/pushbullet');\n\n  const NotificationsPushbulletSchema = Yup.object().shape({\n    accessToken: Yup.string().when('enabled', {\n      is: true,\n      then: Yup.string()\n        .nullable()\n        .required(intl.formatMessage(messages.validationAccessTokenRequired)),\n      otherwise: Yup.string().nullable(),\n    }),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        enabled: data?.enabled,\n        types: data?.types,\n        accessToken: data?.options.accessToken,\n        channelTag: data.options.channelTag,\n      }}\n      validationSchema={NotificationsPushbulletSchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/settings/notifications/pushbullet', {\n            enabled: values.enabled,\n            types: values.types,\n            options: {\n              accessToken: values.accessToken,\n              channelTag: values.channelTag,\n            },\n          });\n          addToast(intl.formatMessage(messages.pushbulletSettingsSaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.pushbulletSettingsFailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        values,\n        isValid,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        const testSettings = async () => {\n          setIsTesting(true);\n          let toastId: string | undefined;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastPushbulletTestSending),\n              {\n                autoDismiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/notifications/pushbullet/test', {\n              enabled: true,\n              types: values.types,\n              options: {\n                accessToken: values.accessToken,\n                channelTag: values.channelTag,\n              },\n            });\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastPushbulletTestSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastPushbulletTestFailed), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            setIsTesting(false);\n          }\n        };\n\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"enabled\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.agentEnabled)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"accessToken\" className=\"text-label\">\n                {intl.formatMessage(messages.accessToken)}\n                <span className=\"label-required\">*</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.accessTokenTip, {\n                    PushbulletSettingsLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://www.pushbullet.com/#settings/account\"\n                        className=\"text-white transition duration-300 hover:underline\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <SensitiveInput\n                    as=\"field\"\n                    id=\"accessToken\"\n                    name=\"accessToken\"\n                    autoComplete=\"one-time-code\"\n                  />\n                </div>\n                {errors.accessToken &&\n                  touched.accessToken &&\n                  typeof errors.accessToken === 'string' && (\n                    <div className=\"error\">{errors.accessToken}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"channelTag\" className=\"text-label\">\n                {intl.formatMessage(messages.channelTag)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"channelTag\" name=\"channelTag\" type=\"text\" />\n                </div>\n              </div>\n            </div>\n            <NotificationTypeSelector\n              currentTypes={values.enabled ? values.types : 0}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n\n                if (newTypes) {\n                  setFieldValue('enabled', true);\n                }\n              }}\n              error={\n                values.enabled && !values.types && touched.types\n                  ? intl.formatMessage(messages.validationTypes)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"warning\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                    onClick={(e) => {\n                      e.preventDefault();\n                      testSettings();\n                    }}\n                  >\n                    <BeakerIcon />\n                    <span>\n                      {isTesting\n                        ? intl.formatMessage(globalMessages.testing)\n                        : intl.formatMessage(globalMessages.test)}\n                    </span>\n                  </Button>\n                </span>\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={\n                      isSubmitting ||\n                      !isValid ||\n                      isTesting ||\n                      (values.enabled && !values.types)\n                    }\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default NotificationsPushbullet;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsPushover/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';\nimport type { PushoverSound } from '@server/api/pushover';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.Settings.Notifications.NotificationsPushover',\n  {\n    agentenabled: 'Enable Agent',\n    embedPoster: 'Embed Poster',\n    accessToken: 'Application API Token',\n    accessTokenTip:\n      '<ApplicationRegistrationLink>Register an application</ApplicationRegistrationLink> for use with Seerr',\n    userToken: 'User or Group Key',\n    userTokenTip:\n      'Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>',\n    sound: 'Notification Sound',\n    deviceDefault: 'Device Default',\n    validationAccessTokenRequired: 'You must provide a valid application token',\n    validationUserTokenRequired: 'You must provide a valid user or group key',\n    pushoversettingssaved: 'Pushover notification settings saved successfully!',\n    pushoversettingsfailed: 'Pushover notification settings failed to save.',\n    toastPushoverTestSending: 'Sending Pushover test notification…',\n    toastPushoverTestSuccess: 'Pushover test notification sent!',\n    toastPushoverTestFailed: 'Pushover test notification failed to send.',\n    validationTypes: 'You must select at least one notification type',\n  }\n);\n\nconst NotificationsPushover = () => {\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR('/api/v1/settings/notifications/pushover');\n  const { data: soundsData } = useSWR<PushoverSound[]>(\n    data?.options.accessToken\n      ? `/api/v1/settings/notifications/pushover/sounds?token=${data.options.accessToken}`\n      : null,\n    {\n      revalidateOnFocus: false,\n      revalidateOnReconnect: false,\n      shouldRetryOnError: false,\n    }\n  );\n\n  const NotificationsPushoverSchema = Yup.object().shape({\n    accessToken: Yup.string()\n      .when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationAccessTokenRequired)),\n        otherwise: Yup.string().nullable(),\n      })\n      .matches(\n        /^[a-z\\d]{30}$/i,\n        intl.formatMessage(messages.validationAccessTokenRequired)\n      ),\n    userToken: Yup.string()\n      .when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationUserTokenRequired)),\n        otherwise: Yup.string().nullable(),\n      })\n      .matches(\n        /^[a-z\\d]{30}$/i,\n        intl.formatMessage(messages.validationUserTokenRequired)\n      ),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        enabled: data?.enabled,\n        embedPoster: data?.embedPoster,\n        types: data?.types,\n        accessToken: data?.options.accessToken,\n        userToken: data?.options.userToken,\n        sound: data?.options.sound,\n      }}\n      validationSchema={NotificationsPushoverSchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/settings/notifications/pushover', {\n            enabled: values.enabled,\n            embedPoster: values.embedPoster,\n            types: values.types,\n            options: {\n              accessToken: values.accessToken,\n              userToken: values.userToken,\n              sound: values.sound,\n            },\n          });\n          addToast(intl.formatMessage(messages.pushoversettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.pushoversettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        values,\n        isValid,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        const testSettings = async () => {\n          setIsTesting(true);\n          let toastId: string | undefined;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastPushoverTestSending),\n              {\n                autoDismiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/notifications/pushover/test', {\n              enabled: true,\n              embedPoster: values.embedPoster,\n              types: values.types,\n              options: {\n                accessToken: values.accessToken,\n                userToken: values.userToken,\n                sound: values.sound,\n              },\n            });\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastPushoverTestSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastPushoverTestFailed), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            setIsTesting(false);\n          }\n        };\n\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"enabled\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.agentenabled)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"embedPoster\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.embedPoster)}\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"embedPoster\" name=\"embedPoster\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"accessToken\" className=\"text-label\">\n                {intl.formatMessage(messages.accessToken)}\n                <span className=\"label-required\">*</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.accessTokenTip, {\n                    ApplicationRegistrationLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://pushover.net/api#registration\"\n                        className=\"text-white transition duration-300 hover:underline\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"accessToken\" name=\"accessToken\" type=\"text\" />\n                </div>\n                {errors.accessToken &&\n                  touched.accessToken &&\n                  typeof errors.accessToken === 'string' && (\n                    <div className=\"error\">{errors.accessToken}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"userToken\" className=\"text-label\">\n                {intl.formatMessage(messages.userToken)}\n                <span className=\"label-required\">*</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.userTokenTip, {\n                    UsersGroupsLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://pushover.net/api#identifiers\"\n                        className=\"text-white transition duration-300 hover:underline\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"userToken\" name=\"userToken\" type=\"text\" />\n                </div>\n                {errors.userToken &&\n                  touched.userToken &&\n                  typeof errors.userToken === 'string' && (\n                    <div className=\"error\">{errors.userToken}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"sound\" className=\"text-label\">\n                {intl.formatMessage(messages.sound)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    as=\"select\"\n                    id=\"sound\"\n                    name=\"sound\"\n                    disabled={!soundsData?.length}\n                  >\n                    <option value=\"\">\n                      {intl.formatMessage(messages.deviceDefault)}\n                    </option>\n                    {soundsData?.map((sound, index) => (\n                      <option key={`sound-${index}`} value={sound.name}>\n                        {sound.description}\n                      </option>\n                    ))}\n                  </Field>\n                </div>\n              </div>\n            </div>\n            <NotificationTypeSelector\n              currentTypes={values.enabled ? values.types : 0}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n\n                if (newTypes) {\n                  setFieldValue('enabled', true);\n                }\n              }}\n              error={\n                values.enabled && !values.types && touched.types\n                  ? intl.formatMessage(messages.validationTypes)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"warning\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                    onClick={(e) => {\n                      e.preventDefault();\n                      testSettings();\n                    }}\n                  >\n                    <BeakerIcon />\n                    <span>\n                      {isTesting\n                        ? intl.formatMessage(globalMessages.testing)\n                        : intl.formatMessage(globalMessages.test)}\n                    </span>\n                  </Button>\n                </span>\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={\n                      isSubmitting ||\n                      !isValid ||\n                      isTesting ||\n                      (values.enabled && !values.types)\n                    }\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default NotificationsPushover;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsSlack/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.Settings.Notifications.NotificationsSlack',\n  {\n    agentenabled: 'Enable Agent',\n    embedPoster: 'Embed Poster',\n    webhookUrl: 'Webhook URL',\n    webhookUrlTip:\n      'Create an <WebhookLink>Incoming Webhook</WebhookLink> integration',\n    slacksettingssaved: 'Slack notification settings saved successfully!',\n    slacksettingsfailed: 'Slack notification settings failed to save.',\n    toastSlackTestSending: 'Sending Slack test notification…',\n    toastSlackTestSuccess: 'Slack test notification sent!',\n    toastSlackTestFailed: 'Slack test notification failed to send.',\n    validationWebhookUrl: 'You must provide a valid URL',\n    validationTypes: 'You must select at least one notification type',\n  }\n);\n\nconst NotificationsSlack = () => {\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR('/api/v1/settings/notifications/slack');\n\n  const NotificationsSlackSchema = Yup.object().shape({\n    webhookUrl: Yup.string()\n      .when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationWebhookUrl)),\n        otherwise: Yup.string().nullable(),\n      })\n      .url(intl.formatMessage(messages.validationWebhookUrl)),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        enabled: data.enabled,\n        embedPoster: data.embedPoster,\n        types: data.types,\n        webhookUrl: data.options.webhookUrl,\n      }}\n      validationSchema={NotificationsSlackSchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/settings/notifications/slack', {\n            enabled: values.enabled,\n            embedPoster: values.embedPoster,\n            types: values.types,\n            options: {\n              webhookUrl: values.webhookUrl,\n            },\n          });\n          addToast(intl.formatMessage(messages.slacksettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.slacksettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        values,\n        isValid,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        const testSettings = async () => {\n          setIsTesting(true);\n          let toastId: string | undefined;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastSlackTestSending),\n              {\n                autoDismiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/notifications/slack/test', {\n              enabled: true,\n              embedPoster: values.embedPoster,\n              types: values.types,\n              options: {\n                webhookUrl: values.webhookUrl,\n              },\n            });\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastSlackTestSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastSlackTestFailed), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            setIsTesting(false);\n          }\n        };\n\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"isDefault\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.agentenabled)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"embedPoster\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.embedPoster)}\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"embedPoster\" name=\"embedPoster\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"name\" className=\"text-label\">\n                {intl.formatMessage(messages.webhookUrl)}\n                <span className=\"label-required\">*</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.webhookUrlTip, {\n                    WebhookLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://my.slack.com/services/new/incoming-webhook/\"\n                        className=\"text-white transition duration-300 hover:underline\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"webhookUrl\"\n                    name=\"webhookUrl\"\n                    type=\"text\"\n                    inputMode=\"url\"\n                  />\n                </div>\n                {errors.webhookUrl &&\n                  touched.webhookUrl &&\n                  typeof errors.webhookUrl === 'string' && (\n                    <div className=\"error\">{errors.webhookUrl}</div>\n                  )}\n              </div>\n            </div>\n            <NotificationTypeSelector\n              currentTypes={values.enabled ? values.types : 0}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n\n                if (newTypes) {\n                  setFieldValue('enabled', true);\n                }\n              }}\n              error={\n                values.enabled && !values.types && touched.types\n                  ? intl.formatMessage(messages.validationTypes)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"warning\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                    onClick={(e) => {\n                      e.preventDefault();\n                      testSettings();\n                    }}\n                  >\n                    <BeakerIcon />\n                    <span>\n                      {isTesting\n                        ? intl.formatMessage(globalMessages.testing)\n                        : intl.formatMessage(globalMessages.test)}\n                    </span>\n                  </Button>\n                </span>\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={\n                      isSubmitting ||\n                      !isValid ||\n                      isTesting ||\n                      (values.enabled && !values.types)\n                    }\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default NotificationsSlack;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsTelegram.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Settings.Notifications', {\n  agentenabled: 'Enable Agent',\n  embedPoster: 'Embed Poster',\n  botUsername: 'Bot Username',\n  botUsernameTip:\n    'Allow users to also start a chat with your bot and configure their own notifications',\n  botAPI: 'Bot Authorization Token',\n  botApiTip: '<CreateBotLink>Create a bot</CreateBotLink> for use with Seerr',\n  chatId: 'Chat ID',\n  chatIdTip:\n    'Start a chat with your bot, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command',\n  messageThreadId: 'Thread/Topic ID',\n  messageThreadIdTip:\n    \"If your group-chat has topics enabled, you can specify a thread/topic's ID here\",\n  validationBotAPIRequired: 'You must provide a bot authorization token',\n  validationChatIdRequired: 'You must provide a valid chat ID',\n  validationMessageThreadId:\n    'The thread/topic ID must be a positive whole number',\n  telegramsettingssaved: 'Telegram notification settings saved successfully!',\n  telegramsettingsfailed: 'Telegram notification settings failed to save.',\n  toastTelegramTestSending: 'Sending Telegram test notification…',\n  toastTelegramTestSuccess: 'Telegram test notification sent!',\n  toastTelegramTestFailed: 'Telegram test notification failed to send.',\n  sendSilently: 'Send Silently',\n  sendSilentlyTip: 'Send notifications with no sound',\n});\n\nconst NotificationsTelegram = () => {\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR('/api/v1/settings/notifications/telegram');\n\n  const NotificationsTelegramSchema = Yup.object().shape({\n    botAPI: Yup.string().when('enabled', {\n      is: true,\n      then: Yup.string()\n        .nullable()\n        .required(intl.formatMessage(messages.validationBotAPIRequired)),\n      otherwise: Yup.string().nullable(),\n    }),\n    chatId: Yup.string()\n      .when(['enabled', 'types'], {\n        is: (enabled: boolean, types: number) => enabled && !!types,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationChatIdRequired)),\n        otherwise: Yup.string().nullable(),\n      })\n      .matches(\n        /^-?\\d+$/,\n        intl.formatMessage(messages.validationChatIdRequired)\n      ),\n    messageThreadId: Yup.string()\n      .when(['types'], {\n        is: (enabled: boolean, types: number) => enabled && !!types,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationMessageThreadId)),\n        otherwise: Yup.string().nullable(),\n      })\n      .matches(/^\\d+$/, intl.formatMessage(messages.validationMessageThreadId)),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        enabled: data?.enabled,\n        embedPoster: data?.embedPoster,\n        types: data?.types,\n        botUsername: data?.options.botUsername,\n        botAPI: data?.options.botAPI,\n        chatId: data?.options.chatId,\n        messageThreadId: data?.options.messageThreadId,\n        sendSilently: data?.options.sendSilently,\n      }}\n      validationSchema={NotificationsTelegramSchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/settings/notifications/telegram', {\n            enabled: values.enabled,\n            embedPoster: values.embedPoster,\n            types: values.types,\n            options: {\n              botAPI: values.botAPI,\n              chatId: values.chatId,\n              messageThreadId: values.messageThreadId,\n              sendSilently: values.sendSilently,\n              botUsername: values.botUsername,\n            },\n          });\n\n          addToast(intl.formatMessage(messages.telegramsettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.telegramsettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        values,\n        isValid,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        const testSettings = async () => {\n          setIsTesting(true);\n          let toastId: string | undefined;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastTelegramTestSending),\n              {\n                autoDismiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/notifications/telegram/test', {\n              enabled: true,\n              types: values.types,\n              options: {\n                botAPI: values.botAPI,\n                chatId: values.chatId,\n                messageThreadId: values.messageThreadId,\n                sendSilently: values.sendSilently,\n                botUsername: values.botUsername,\n              },\n            });\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastTelegramTestSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastTelegramTestFailed), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            setIsTesting(false);\n          }\n        };\n\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"enabled\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.agentenabled)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"embedPoster\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.embedPoster)}\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"embedPoster\" name=\"embedPoster\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"botAPI\" className=\"text-label\">\n                {intl.formatMessage(messages.botAPI)}\n                <span className=\"label-required\">*</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.botApiTip, {\n                    CreateBotLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://core.telegram.org/bots#6-botfather\"\n                        className=\"text-white transition duration-300 hover:underline\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                    GetIdBotLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://telegram.me/get_id_bot\"\n                        className=\"text-white transition duration-300 hover:underline\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                    code: (msg: React.ReactNode) => (\n                      <code className=\"bg-gray-800/50\">{msg}</code>\n                    ),\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <SensitiveInput\n                    as=\"field\"\n                    id=\"botAPI\"\n                    name=\"botAPI\"\n                    type=\"text\"\n                  />\n                </div>\n                {errors.botAPI &&\n                  touched.botAPI &&\n                  typeof errors.botAPI === 'string' && (\n                    <div className=\"error\">{errors.botAPI}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"botUsername\" className=\"text-label\">\n                {intl.formatMessage(messages.botUsername)}\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.botUsernameTip)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"botUsername\"\n                    name=\"botUsername\"\n                    type=\"text\"\n                    autoComplete=\"off\"\n                    data-form-type=\"other\"\n                    data-1pignore=\"true\"\n                    data-lpignore=\"true\"\n                    data-bwignore=\"true\"\n                  />\n                </div>\n                {errors.botUsername &&\n                  touched.botUsername &&\n                  typeof errors.botUsername === 'string' && (\n                    <div className=\"error\">{errors.botUsername}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"chatId\" className=\"text-label\">\n                {intl.formatMessage(messages.chatId)}\n                <span className=\"label-required\">*</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.chatIdTip, {\n                    GetIdBotLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://telegram.me/get_id_bot\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                    code: (msg: React.ReactNode) => <code>{msg}</code>,\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"chatId\"\n                    name=\"chatId\"\n                    type=\"text\"\n                    autoComplete=\"off\"\n                    data-form-type=\"other\"\n                    data-1pignore=\"true\"\n                    data-lpignore=\"true\"\n                    data-bwignore=\"true\"\n                  />\n                </div>\n                {errors.chatId &&\n                  touched.chatId &&\n                  typeof errors.chatId === 'string' && (\n                    <div className=\"error\">{errors.chatId}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"messageThreadId\" className=\"text-label\">\n                {intl.formatMessage(messages.messageThreadId)}\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.messageThreadIdTip)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"messageThreadId\"\n                    name=\"messageThreadId\"\n                    type=\"text\"\n                  />\n                </div>\n                {errors.messageThreadId &&\n                  touched.messageThreadId &&\n                  typeof errors.messageThreadId === 'string' && (\n                    <div className=\"error\">{errors.messageThreadId}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"sendSilently\" className=\"checkbox-label\">\n                <span>{intl.formatMessage(messages.sendSilently)}</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.sendSilentlyTip)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"sendSilently\" name=\"sendSilently\" />\n              </div>\n            </div>\n            <NotificationTypeSelector\n              currentTypes={values.enabled ? values.types : 0}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n\n                if (newTypes) {\n                  setFieldValue('enabled', true);\n                }\n              }}\n              error={\n                errors.types && touched.types\n                  ? (errors.types as string)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"warning\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                    onClick={(e) => {\n                      e.preventDefault();\n                      testSettings();\n                    }}\n                  >\n                    <BeakerIcon />\n                    <span>\n                      {isTesting\n                        ? intl.formatMessage(globalMessages.testing)\n                        : intl.formatMessage(globalMessages.test)}\n                    </span>\n                  </Button>\n                </span>\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default NotificationsTelegram;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsWebPush/index.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\n\nconst messages = defineMessages(\n  'components.Settings.Notifications.NotificationsWebPush',\n  {\n    agentenabled: 'Enable Agent',\n    embedPoster: 'Embed Poster',\n    webpushsettingssaved: 'Web push notification settings saved successfully!',\n    webpushsettingsfailed: 'Web push notification settings failed to save.',\n    toastWebPushTestSending: 'Sending web push test notification…',\n    toastWebPushTestSuccess: 'Web push test notification sent!',\n    toastWebPushTestFailed: 'Web push test notification failed to send.',\n    httpsRequirement:\n      'In order to receive web push notifications, Seerr must be served over HTTPS.',\n  }\n);\n\nconst NotificationsWebPush = () => {\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const [isHttps, setIsHttps] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR('/api/v1/settings/notifications/webpush');\n\n  useEffect(() => {\n    setIsHttps(window.location.protocol.startsWith('https'));\n  }, []);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <>\n      {!isHttps && (\n        <Alert\n          title={intl.formatMessage(messages.httpsRequirement)}\n          type=\"warning\"\n        />\n      )}\n      <Formik\n        initialValues={{\n          enabled: data.enabled,\n          embedPoster: data.embedPoster,\n        }}\n        onSubmit={async (values) => {\n          try {\n            await axios.post('/api/v1/settings/notifications/webpush', {\n              enabled: values.enabled,\n              embedPoster: values.embedPoster,\n              options: {},\n            });\n            mutate('/api/v1/settings/public');\n            addToast(intl.formatMessage(messages.webpushsettingssaved), {\n              appearance: 'success',\n              autoDismiss: true,\n            });\n          } catch {\n            addToast(intl.formatMessage(messages.webpushsettingsfailed), {\n              appearance: 'error',\n              autoDismiss: true,\n            });\n          } finally {\n            revalidate();\n          }\n        }}\n      >\n        {({ isSubmitting, values }) => {\n          const testSettings = async () => {\n            setIsTesting(true);\n            let toastId: string | undefined;\n            try {\n              addToast(\n                intl.formatMessage(messages.toastWebPushTestSending),\n                {\n                  autoDismiss: false,\n                  appearance: 'info',\n                },\n                (id) => {\n                  toastId = id;\n                }\n              );\n              await axios.post('/api/v1/settings/notifications/webpush/test', {\n                enabled: true,\n                embedPoster: values.embedPoster,\n                options: {},\n              });\n\n              if (toastId) {\n                removeToast(toastId);\n              }\n              addToast(intl.formatMessage(messages.toastWebPushTestSuccess), {\n                autoDismiss: true,\n                appearance: 'success',\n              });\n            } catch {\n              if (toastId) {\n                removeToast(toastId);\n              }\n              addToast(intl.formatMessage(messages.toastWebPushTestFailed), {\n                autoDismiss: true,\n                appearance: 'error',\n              });\n            } finally {\n              setIsTesting(false);\n            }\n          };\n\n          return (\n            <Form className=\"section\">\n              <div className=\"form-row\">\n                <label htmlFor=\"enabled\" className=\"checkbox-label\">\n                  {intl.formatMessage(messages.agentenabled)}\n                  <span className=\"label-required\">*</span>\n                </label>\n                <div className=\"form-input-area\">\n                  <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"embedPoster\" className=\"checkbox-label\">\n                  {intl.formatMessage(messages.embedPoster)}\n                  <span className=\"label-required\">*</span>\n                </label>\n                <div className=\"form-input-area\">\n                  <Field type=\"checkbox\" id=\"embedPoster\" name=\"embedPoster\" />\n                </div>\n              </div>\n              <div className=\"actions\">\n                <div className=\"flex justify-end\">\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"warning\"\n                      disabled={isSubmitting || isTesting}\n                      onClick={(e) => {\n                        e.preventDefault();\n                        testSettings();\n                      }}\n                    >\n                      <BeakerIcon />\n                      <span>\n                        {isTesting\n                          ? intl.formatMessage(globalMessages.testing)\n                          : intl.formatMessage(globalMessages.test)}\n                      </span>\n                    </Button>\n                  </span>\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"primary\"\n                      type=\"submit\"\n                      disabled={isSubmitting || isTesting}\n                    >\n                      <ArrowDownOnSquareIcon />\n                      <span>\n                        {isSubmitting\n                          ? intl.formatMessage(globalMessages.saving)\n                          : intl.formatMessage(globalMessages.save)}\n                      </span>\n                    </Button>\n                  </span>\n                </div>\n              </div>\n            </Form>\n          );\n        }}\n      </Formik>\n    </>\n  );\n};\n\nexport default NotificationsWebPush;\n"
  },
  {
    "path": "src/components/Settings/Notifications/NotificationsWebhook/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport SettingsBadge from '@app/components/Settings/SettingsBadge';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { isValidURL } from '@app/utils/urlValidationHelper';\nimport {\n  ArrowDownOnSquareIcon,\n  BeakerIcon,\n  PlusIcon,\n  TrashIcon,\n} from '@heroicons/react/24/outline';\nimport {\n  ArrowPathIcon,\n  QuestionMarkCircleIcon,\n} from '@heroicons/react/24/solid';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport dynamic from 'next/dynamic';\nimport Link from 'next/link';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst JSONEditor = dynamic(() => import('@app/components/JSONEditor'), {\n  ssr: false,\n});\n\nconst defaultPayload = {\n  notification_type: '{{notification_type}}',\n  event: '{{event}}',\n  subject: '{{subject}}',\n  message: '{{message}}',\n  image: '{{image}}',\n  '{{media}}': {\n    media_type: '{{media_type}}',\n    tmdbId: '{{media_tmdbid}}',\n    tvdbId: '{{media_tvdbid}}',\n    jellyfinMediaId: '{{media_jellyfinMediaId}}',\n    status: '{{media_status}}',\n    status4k: '{{media_status4k}}',\n  },\n  '{{request}}': {\n    request_id: '{{request_id}}',\n    requestedBy_email: '{{requestedBy_email}}',\n    requestedBy_username: '{{requestedBy_username}}',\n    requestedBy_avatar: '{{requestedBy_avatar}}',\n    requestedBy_jellyfinUserId: '{{requestedBy_jellyfinUserId}}',\n    requestedBy_settings_discordId: '{{requestedBy_settings_discordId}}',\n    requestedBy_settings_telegramChatId:\n      '{{requestedBy_settings_telegramChatId}}',\n  },\n  '{{issue}}': {\n    issue_id: '{{issue_id}}',\n    issue_type: '{{issue_type}}',\n    issue_status: '{{issue_status}}',\n    reportedBy_email: '{{reportedBy_email}}',\n    reportedBy_username: '{{reportedBy_username}}',\n    reportedBy_avatar: '{{reportedBy_avatar}}',\n    reportedBy_settings_discordId: '{{reportedBy_settings_discordId}}',\n    reportedBy_settings_telegramChatId:\n      '{{reportedBy_settings_telegramChatId}}',\n  },\n  '{{comment}}': {\n    comment_message: '{{comment_message}}',\n    commentedBy_email: '{{commentedBy_email}}',\n    commentedBy_username: '{{commentedBy_username}}',\n    commentedBy_avatar: '{{commentedBy_avatar}}',\n    commentedBy_settings_discordId: '{{commentedBy_settings_discordId}}',\n    commentedBy_settings_telegramChatId:\n      '{{commentedBy_settings_telegramChatId}}',\n  },\n  '{{extra}}': [],\n};\n\nconst messages = defineMessages(\n  'components.Settings.Notifications.NotificationsWebhook',\n  {\n    agentenabled: 'Enable Agent',\n    webhookUrl: 'Webhook URL',\n    webhookUrlTip:\n      'Test Notification URL is set to {testUrl} instead of the actual webhook URL.',\n    supportVariables: 'Support URL Variables',\n    supportVariablesTip:\n      'Available variables are documented in the webhook template variables section',\n    authheader: 'Authorization Header',\n    customHeaders: 'Custom Headers',\n    customHeadersTip:\n      'Add custom HTTP headers to include with webhook requests',\n    customHeadersAdd: 'Add Header',\n    customHeadersRemove: 'Remove',\n    customHeadersKey: 'Header Name',\n    customHeadersValue: 'Header Value',\n    customHeadersIncomplete: 'All headers must have both name and value',\n    customHeadersAuthConflict:\n      'Cannot use both Authorization Header and custom Authorization header. Please remove one.',\n    validationJsonPayloadRequired: 'You must provide a valid JSON payload',\n    webhooksettingssaved: 'Webhook notification settings saved successfully!',\n    webhooksettingsfailed: 'Webhook notification settings failed to save.',\n    toastWebhookTestSending: 'Sending webhook test notification…',\n    toastWebhookTestSuccess: 'Webhook test notification sent!',\n    toastWebhookTestFailed: 'Webhook test notification failed to send.',\n    resetPayload: 'Reset to Default',\n    resetPayloadSuccess: 'JSON payload reset successfully!',\n    customJson: 'JSON Payload',\n    templatevariablehelp: 'Template Variable Help',\n    validationWebhookUrl: 'You must provide a valid URL',\n    validationTypes: 'You must select at least one notification type',\n  }\n);\n\nconst NotificationsWebhook = () => {\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR('/api/v1/settings/notifications/webhook');\n\n  const NotificationsWebhookSchema = Yup.object().shape({\n    webhookUrl: Yup.string()\n      .when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationWebhookUrl)),\n        otherwise: Yup.string().nullable(),\n      })\n      .test(\n        'valid-url',\n        intl.formatMessage(messages.validationWebhookUrl),\n        function (value) {\n          const { supportVariables } = this.parent;\n          return supportVariables || isValidURL(value);\n        }\n      ),\n\n    supportVariables: Yup.boolean(),\n\n    customHeaders: Yup.array()\n      .of(\n        Yup.object().shape({\n          key: Yup.string(),\n          value: Yup.string(),\n        })\n      )\n      .test(\n        'complete-headers',\n        intl.formatMessage(messages.customHeadersIncomplete),\n        function (headers) {\n          if (!headers || headers.length === 0) return true;\n          return headers.every(\n            (header) =>\n              (!header.key || !header.key.trim()) ===\n              (!header.value || !header.value.trim())\n          );\n        }\n      )\n      .test(\n        'auth-conflict',\n        intl.formatMessage(messages.customHeadersAuthConflict),\n        function (headers) {\n          const { authHeader } = this.parent;\n          if (!authHeader || !headers || headers.length === 0) return true;\n\n          const hasCustomAuthHeader = headers.some(\n            (header) =>\n              header.key &&\n              header.value &&\n              header.key.trim().toLowerCase() === 'authorization'\n          );\n\n          return !hasCustomAuthHeader;\n        }\n      ),\n\n    jsonPayload: Yup.string()\n      .when('enabled', {\n        is: true,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationJsonPayloadRequired)),\n        otherwise: Yup.string().nullable(),\n      })\n      .test(\n        'validate-json',\n        intl.formatMessage(messages.validationJsonPayloadRequired),\n        (value) => {\n          try {\n            JSON.parse(value ?? '');\n            return true;\n          } catch {\n            return false;\n          }\n        }\n      ),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        enabled: data.enabled,\n        types: data.types,\n        webhookUrl: data.options.webhookUrl,\n        jsonPayload: data.options.jsonPayload,\n        authHeader: data.options.authHeader,\n        customHeaders: data.options.customHeaders ?? [],\n        supportVariables: data.options.supportVariables ?? false,\n      }}\n      validationSchema={NotificationsWebhookSchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/settings/notifications/webhook', {\n            enabled: values.enabled,\n            types: values.types,\n            options: {\n              webhookUrl: values.webhookUrl,\n              jsonPayload: JSON.stringify(values.jsonPayload),\n              authHeader: values.authHeader,\n              customHeaders: (values.customHeaders ?? [])\n                .map((h: { key: string; value: string }) => ({\n                  key: h.key?.trim() ?? '',\n                  value: h.value?.trim() ?? '',\n                }))\n                .filter(\n                  (h: { key: string; value: string }) =>\n                    h.key.length > 0 && h.value.length > 0\n                ),\n              supportVariables: values.supportVariables,\n            },\n          });\n          addToast(intl.formatMessage(messages.webhooksettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.webhooksettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        values,\n        isValid,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        const resetPayload = () => {\n          setFieldValue(\n            'jsonPayload',\n            JSON.stringify(defaultPayload, undefined, '    ')\n          );\n          addToast(intl.formatMessage(messages.resetPayloadSuccess), {\n            appearance: 'info',\n            autoDismiss: true,\n          });\n        };\n\n        const testSettings = async () => {\n          setIsTesting(true);\n          let toastId: string | undefined;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastWebhookTestSending),\n              {\n                autoDismiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/notifications/webhook/test', {\n              enabled: true,\n              types: values.types,\n              options: {\n                webhookUrl: values.webhookUrl,\n                jsonPayload: JSON.stringify(values.jsonPayload),\n                authHeader: values.authHeader,\n                customHeaders: (values.customHeaders ?? [])\n                  .map((h: { key: string; value: string }) => ({\n                    key: h.key?.trim() ?? '',\n                    value: h.value?.trim() ?? '',\n                  }))\n                  .filter(\n                    (h: { key: string; value: string }) =>\n                      h.key.length > 0 && h.value.length > 0\n                  ),\n                supportVariables: values.supportVariables ?? false,\n              },\n            });\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastWebhookTestSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastWebhookTestFailed), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            setIsTesting(false);\n          }\n        };\n\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"enabled\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.agentenabled)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field type=\"checkbox\" id=\"enabled\" name=\"enabled\" />\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"supportVariables\" className=\"checkbox-label\">\n                <span className=\"mr-2\">\n                  {intl.formatMessage(messages.supportVariables)}\n                </span>\n                <SettingsBadge badgeType=\"experimental\" />\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.supportVariablesTip)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field\n                  type=\"checkbox\"\n                  id=\"supportVariables\"\n                  name=\"supportVariables\"\n                  onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n                    setFieldValue('supportVariables', e.target.checked)\n                  }\n                />\n              </div>\n            </div>\n            {values.supportVariables && (\n              <div className=\"mt-2\">\n                <Link\n                  href=\"https://docs.seerr.dev/using-seerr/notifications/webhook#template-variables\"\n                  passHref\n                  legacyBehavior\n                >\n                  <Button\n                    as=\"a\"\n                    buttonSize=\"sm\"\n                    target=\"_blank\"\n                    rel=\"noreferrer\"\n                  >\n                    <QuestionMarkCircleIcon />\n                    <span>\n                      {intl.formatMessage(messages.templatevariablehelp)}\n                    </span>\n                  </Button>\n                </Link>\n              </div>\n            )}\n            <div className=\"form-row\">\n              <label htmlFor=\"webhookUrl\" className=\"text-label\">\n                {intl.formatMessage(messages.webhookUrl)}\n                <span className=\"label-required\">*</span>\n                {values.supportVariables && (\n                  <div className=\"label-tip\">\n                    {intl.formatMessage(messages.webhookUrlTip, {\n                      testUrl: '/test',\n                    })}\n                  </div>\n                )}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"webhookUrl\"\n                    name=\"webhookUrl\"\n                    type=\"text\"\n                    inputMode=\"url\"\n                  />\n                </div>\n                {errors.webhookUrl &&\n                  touched.webhookUrl &&\n                  typeof errors.webhookUrl === 'string' && (\n                    <div className=\"error\">{errors.webhookUrl}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"authHeader\" className=\"text-label\">\n                {intl.formatMessage(messages.authheader)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"authHeader\" name=\"authHeader\" type=\"text\" />\n                </div>\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"customHeaders\" className=\"text-label\">\n                {intl.formatMessage(messages.customHeaders)}\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.customHeadersTip)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"space-y-2\">\n                  {values.customHeaders.map(\n                    (header: { key: string; value: string }, index: number) => (\n                      <div key={index} className=\"flex gap-2\">\n                        <div className=\"flex-1\">\n                          <div className=\"form-input-field\">\n                            <Field\n                              name={`customHeaders.${index}.key`}\n                              type=\"text\"\n                              placeholder={intl.formatMessage(\n                                messages.customHeadersKey\n                              )}\n                            />\n                          </div>\n                        </div>\n                        <div className=\"flex-1\">\n                          <div className=\"form-input-field\">\n                            <Field\n                              name={`customHeaders.${index}.value`}\n                              type=\"text\"\n                              placeholder={intl.formatMessage(\n                                messages.customHeadersValue\n                              )}\n                            />\n                          </div>\n                        </div>\n                        <div className=\"flex items-center\">\n                          <Button\n                            buttonType=\"danger\"\n                            buttonSize=\"sm\"\n                            onClick={(e) => {\n                              e.preventDefault();\n                              const newHeaders = values.customHeaders.filter(\n                                (\n                                  _: { key: string; value: string },\n                                  i: number\n                                ) => i !== index\n                              );\n                              setFieldValue('customHeaders', newHeaders);\n                            }}\n                            title={intl.formatMessage(\n                              messages.customHeadersRemove\n                            )}\n                          >\n                            <TrashIcon />\n                          </Button>\n                        </div>\n                      </div>\n                    )\n                  )}\n                  <Button\n                    buttonType=\"default\"\n                    buttonSize=\"sm\"\n                    onClick={(e) => {\n                      e.preventDefault();\n                      setFieldValue('customHeaders', [\n                        ...values.customHeaders,\n                        { key: '', value: '' },\n                      ]);\n                    }}\n                  >\n                    <PlusIcon />\n                    <span>{intl.formatMessage(messages.customHeadersAdd)}</span>\n                  </Button>\n                </div>\n                {errors.customHeaders &&\n                  touched.customHeaders &&\n                  typeof errors.customHeaders === 'string' && (\n                    <div className=\"error\">{errors.customHeaders}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"webhook-json-payload\" className=\"text-label\">\n                {intl.formatMessage(messages.customJson)}\n                <span className=\"label-required\">*</span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <JSONEditor\n                    name=\"webhook-json-payload\"\n                    onUpdate={(value) => setFieldValue('jsonPayload', value)}\n                    value={values.jsonPayload}\n                    onBlur={() => setFieldTouched('jsonPayload')}\n                  />\n                </div>\n                {errors.jsonPayload &&\n                  touched.jsonPayload &&\n                  typeof errors.jsonPayload === 'string' && (\n                    <div className=\"error\">{errors.jsonPayload}</div>\n                  )}\n                <div className=\"mt-2\">\n                  <Button\n                    buttonSize=\"sm\"\n                    onClick={(e) => {\n                      e.preventDefault();\n                      resetPayload();\n                    }}\n                    className=\"mr-2\"\n                  >\n                    <ArrowPathIcon />\n                    <span>{intl.formatMessage(messages.resetPayload)}</span>\n                  </Button>\n                  <Link\n                    href=\"https://docs.seerr.dev/using-seerr/notifications/webhook#template-variables\"\n                    passHref\n                    legacyBehavior\n                  >\n                    <Button\n                      as=\"a\"\n                      buttonSize=\"sm\"\n                      target=\"_blank\"\n                      rel=\"noreferrer\"\n                    >\n                      <QuestionMarkCircleIcon />\n                      <span>\n                        {intl.formatMessage(messages.templatevariablehelp)}\n                      </span>\n                    </Button>\n                  </Link>\n                </div>\n              </div>\n            </div>\n            <NotificationTypeSelector\n              currentTypes={values.enabled ? values.types : 0}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n\n                if (newTypes) {\n                  setFieldValue('enabled', true);\n                }\n              }}\n              error={\n                values.enabled && !values.types && touched.types\n                  ? intl.formatMessage(messages.validationTypes)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"warning\"\n                    disabled={isSubmitting || !isValid || isTesting}\n                    onClick={(e) => {\n                      e.preventDefault();\n                      testSettings();\n                    }}\n                  >\n                    <BeakerIcon />\n                    <span>\n                      {isTesting\n                        ? intl.formatMessage(globalMessages.testing)\n                        : intl.formatMessage(globalMessages.test)}\n                    </span>\n                  </Button>\n                </span>\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={\n                      isSubmitting ||\n                      !isValid ||\n                      isTesting ||\n                      (values.enabled && !values.types)\n                    }\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default NotificationsWebhook;\n"
  },
  {
    "path": "src/components/Settings/OverrideRule/OverrideRuleModal.tsx",
    "content": "import Modal from '@app/components/Common/Modal';\nimport LanguageSelector from '@app/components/LanguageSelector';\nimport {\n  GenreSelector,\n  KeywordSelector,\n  UserSelector,\n} from '@app/components/Selector';\nimport type { DVRTestResponse } from '@app/components/Settings/SettingsServices';\nimport useSettings from '@app/hooks/useSettings';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport type OverrideRule from '@server/entity/OverrideRule';\nimport type { RadarrSettings, SonarrSettings } from '@server/lib/settings';\nimport axios from 'axios';\nimport { Field, Formik } from 'formik';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport Select from 'react-select';\nimport { useToasts } from 'react-toast-notifications';\n\nconst messages = defineMessages('components.Settings.OverrideRuleModal', {\n  createrule: 'New Override Rule',\n  editrule: 'Edit Override Rule',\n  create: 'Create rule',\n  service: 'Service',\n  serviceDescription: 'Apply this rule to the selected service.',\n  selectService: 'Select service',\n  conditions: 'Conditions',\n  conditionsDescription:\n    'Specifies conditions before applying parameter changes. Each field must be validated for the rules to be applied (AND operation). A field is considered verified if any of its properties match (OR operation).',\n  settings: 'Settings',\n  settingsDescription:\n    'Specifies which settings will be changed when the above conditions are met.',\n  users: 'Users',\n  genres: 'Genres',\n  languages: 'Languages',\n  keywords: 'Keywords',\n  rootfolder: 'Root Folder',\n  selectRootFolder: 'Select root folder',\n  qualityprofile: 'Quality Profile',\n  selectQualityProfile: 'Select quality profile',\n  tags: 'Tags',\n  notagoptions: 'No tags.',\n  selecttags: 'Select tags',\n  ruleCreated: 'Override rule created successfully!',\n  ruleUpdated: 'Override rule updated successfully!',\n});\n\ntype OptionType = {\n  value: number;\n  label: string;\n};\n\ninterface OverrideRuleModalProps {\n  rule: OverrideRule | null;\n  onClose: () => void;\n  radarrServices: RadarrSettings[];\n  sonarrServices: SonarrSettings[];\n}\n\nconst OverrideRuleModal = ({\n  onClose,\n  rule,\n  radarrServices,\n  sonarrServices,\n}: OverrideRuleModalProps) => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const { currentSettings } = useSettings();\n  const [isValidated, setIsValidated] = useState(rule ? true : false);\n  const [isTesting, setIsTesting] = useState(false);\n  const [testResponse, setTestResponse] = useState<DVRTestResponse>({\n    profiles: [],\n    rootFolders: [],\n    tags: [],\n  });\n\n  const getServiceInfos = useCallback(\n    async (\n      {\n        hostname,\n        port,\n        apiKey,\n        baseUrl,\n        useSsl = false,\n      }: {\n        hostname: string;\n        port: number;\n        apiKey: string;\n        baseUrl?: string;\n        useSsl?: boolean;\n      },\n      type: 'radarr' | 'sonarr'\n    ) => {\n      setIsTesting(true);\n      try {\n        const response = await axios.post<DVRTestResponse>(\n          `/api/v1/settings/${type}/test`,\n          {\n            hostname,\n            apiKey,\n            port: Number(port),\n            baseUrl,\n            useSsl,\n          }\n        );\n\n        setIsValidated(true);\n        setTestResponse(response.data);\n      } catch {\n        setIsValidated(false);\n      } finally {\n        setIsTesting(false);\n      }\n    },\n    []\n  );\n\n  useEffect(() => {\n    if (\n      rule?.radarrServiceId !== null &&\n      rule?.radarrServiceId !== undefined &&\n      radarrServices[rule?.radarrServiceId]\n    ) {\n      getServiceInfos(radarrServices[rule?.radarrServiceId], 'radarr');\n    }\n    if (\n      rule?.sonarrServiceId !== null &&\n      rule?.sonarrServiceId !== undefined &&\n      sonarrServices[rule?.sonarrServiceId]\n    ) {\n      getServiceInfos(sonarrServices[rule?.sonarrServiceId], 'sonarr');\n    }\n  }, [\n    getServiceInfos,\n    radarrServices,\n    rule?.radarrServiceId,\n    rule?.sonarrServiceId,\n    sonarrServices,\n  ]);\n\n  return (\n    <Transition\n      as=\"div\"\n      appear\n      show\n      enter=\"transition-opacity ease-in-out duration-300\"\n      enterFrom=\"opacity-0\"\n      enterTo=\"opacity-100\"\n      leave=\"transition-opacity ease-in-out duration-300\"\n      leaveFrom=\"opacity-100\"\n      leaveTo=\"opacity-0\"\n    >\n      <Formik\n        initialValues={{\n          radarrServiceId: rule?.radarrServiceId,\n          sonarrServiceId: rule?.sonarrServiceId,\n          users: rule?.users,\n          genre: rule?.genre,\n          language: rule?.language,\n          keywords: rule?.keywords,\n          profileId: rule?.profileId,\n          rootFolder: rule?.rootFolder,\n          tags: rule?.tags,\n        }}\n        onSubmit={async (values) => {\n          try {\n            const submission = {\n              users: values.users || null,\n              genre: values.genre || null,\n              language: values.language || null,\n              keywords: values.keywords || null,\n              profileId: Number(values.profileId) || null,\n              rootFolder: values.rootFolder || null,\n              tags: values.tags || null,\n              radarrServiceId: values.radarrServiceId,\n              sonarrServiceId: values.sonarrServiceId,\n            };\n            if (!rule) {\n              await axios.post('/api/v1/overrideRule', submission);\n              addToast(intl.formatMessage(messages.ruleCreated), {\n                appearance: 'success',\n                autoDismiss: true,\n              });\n            } else {\n              await axios.put(`/api/v1/overrideRule/${rule.id}`, submission);\n              addToast(intl.formatMessage(messages.ruleUpdated), {\n                appearance: 'success',\n                autoDismiss: true,\n              });\n            }\n            onClose();\n          } catch {\n            // set error here\n          }\n        }}\n      >\n        {({\n          errors,\n          touched,\n          values,\n          handleSubmit,\n          setFieldValue,\n          isSubmitting,\n          isValid,\n        }) => {\n          return (\n            <Modal\n              onCancel={onClose}\n              okButtonType=\"primary\"\n              okText={\n                isSubmitting\n                  ? intl.formatMessage(globalMessages.saving)\n                  : rule\n                    ? intl.formatMessage(globalMessages.save)\n                    : intl.formatMessage(messages.create)\n              }\n              okDisabled={\n                isSubmitting ||\n                !isValid ||\n                (!values.users &&\n                  !values.genre &&\n                  !values.language &&\n                  !values.keywords) ||\n                (!values.rootFolder && !values.profileId && !values.tags)\n              }\n              onOk={() => handleSubmit()}\n              title={\n                !rule\n                  ? intl.formatMessage(messages.createrule)\n                  : intl.formatMessage(messages.editrule)\n              }\n            >\n              <div className=\"mb-6\">\n                <h3 className=\"text-lg font-bold leading-8 text-gray-100\">\n                  {intl.formatMessage(messages.service)}\n                </h3>\n                <p className=\"description\">\n                  {intl.formatMessage(messages.serviceDescription)}\n                </p>\n                <div className=\"form-row\">\n                  <label htmlFor=\"service\" className=\"text-label\">\n                    {intl.formatMessage(messages.service)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <select\n                        id=\"service\"\n                        name=\"service\"\n                        defaultValue={\n                          values.radarrServiceId !== null\n                            ? `radarr-${values.radarrServiceId}`\n                            : `sonarr-${values.sonarrServiceId}`\n                        }\n                        onChange={(e) => {\n                          const id = Number(e.target.value.split('-')[1]);\n                          if (e.target.value.startsWith('radarr-')) {\n                            setFieldValue('radarrServiceId', id);\n                            setFieldValue('sonarrServiceId', null);\n                            if (radarrServices[id]) {\n                              getServiceInfos(radarrServices[id], 'radarr');\n                            }\n                          } else if (e.target.value.startsWith('sonarr-')) {\n                            setFieldValue('radarrServiceId', null);\n                            setFieldValue('sonarrServiceId', id);\n                            if (sonarrServices[id]) {\n                              getServiceInfos(sonarrServices[id], 'sonarr');\n                            }\n                          } else {\n                            setFieldValue('radarrServiceId', null);\n                            setFieldValue('sonarrServiceId', null);\n                            setIsValidated(false);\n                          }\n                        }}\n                      >\n                        <option value=\"\">\n                          {intl.formatMessage(messages.selectService)}\n                        </option>\n                        {radarrServices.map((radarr) => (\n                          <option\n                            key={`radarr-${radarr.id}`}\n                            value={`radarr-${radarr.id}`}\n                          >\n                            {radarr.name}\n                          </option>\n                        ))}\n                        {sonarrServices.map((sonarr) => (\n                          <option\n                            key={`sonarr-${sonarr.id}`}\n                            value={`sonarr-${sonarr.id}`}\n                          >\n                            {sonarr.name}\n                          </option>\n                        ))}\n                      </select>\n                    </div>\n                    {errors.rootFolder &&\n                      touched.rootFolder &&\n                      typeof errors.rootFolder === 'string' && (\n                        <div className=\"error\">{errors.rootFolder}</div>\n                      )}\n                  </div>\n                </div>\n                <h3 className=\"text-lg font-bold leading-8 text-gray-100\">\n                  {intl.formatMessage(messages.conditions)}\n                </h3>\n                <p className=\"description\">\n                  {intl.formatMessage(messages.conditionsDescription)}\n                </p>\n                <div className=\"form-row\">\n                  <label htmlFor=\"users\" className=\"text-label\">\n                    {intl.formatMessage(messages.users)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <UserSelector\n                        defaultValue={values.users}\n                        isDisabled={!isValidated || isTesting}\n                        isMulti\n                        onChange={(users) => {\n                          setFieldValue(\n                            'users',\n                            users?.map((v) => v.value).join(',')\n                          );\n                        }}\n                      />\n                    </div>\n                    {errors.users &&\n                      touched.users &&\n                      typeof errors.users === 'string' && (\n                        <div className=\"error\">{errors.users}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"genre\" className=\"text-label\">\n                    {intl.formatMessage(messages.genres)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <GenreSelector\n                        type={\n                          values.radarrServiceId != null\n                            ? 'movie'\n                            : values.sonarrServiceId != null\n                              ? 'tv'\n                              : 'tv'\n                        }\n                        defaultValue={values.genre}\n                        isMulti\n                        isDisabled={!isValidated || isTesting}\n                        onChange={(genres) => {\n                          setFieldValue(\n                            'genre',\n                            genres?.map((v) => v.value).join(',')\n                          );\n                        }}\n                      />\n                    </div>\n                    {errors.genre &&\n                      touched.genre &&\n                      typeof errors.genre === 'string' && (\n                        <div className=\"error\">{errors.genre}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"language\" className=\"text-label\">\n                    {intl.formatMessage(messages.languages)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <LanguageSelector\n                        value={values.language}\n                        serverValue={currentSettings.originalLanguage}\n                        setFieldValue={(_key, value) => {\n                          setFieldValue('language', value);\n                        }}\n                        isDisabled={!isValidated || isTesting}\n                      />\n                    </div>\n                    {errors.language &&\n                      touched.language &&\n                      typeof errors.language === 'string' && (\n                        <div className=\"error\">{errors.language}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"keywords\" className=\"text-label\">\n                    {intl.formatMessage(messages.keywords)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <KeywordSelector\n                        defaultValue={values.keywords}\n                        isMulti\n                        isDisabled={!isValidated || isTesting}\n                        onChange={(value) => {\n                          setFieldValue(\n                            'keywords',\n                            value?.map((v) => v.value).join(',')\n                          );\n                        }}\n                      />\n                    </div>\n                    {errors.keywords &&\n                      touched.keywords &&\n                      typeof errors.keywords === 'string' && (\n                        <div className=\"error\">{errors.keywords}</div>\n                      )}\n                  </div>\n                </div>\n                <h3 className=\"mt-4 text-lg font-bold leading-8 text-gray-100\">\n                  {intl.formatMessage(messages.settings)}\n                </h3>\n                <p className=\"description\">\n                  {intl.formatMessage(messages.settingsDescription)}\n                </p>\n                <div className=\"form-row\">\n                  <label htmlFor=\"rootFolderRule\" className=\"text-label\">\n                    {intl.formatMessage(messages.rootfolder)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"rootFolderRule\"\n                        name=\"rootFolder\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"\">\n                          {intl.formatMessage(messages.selectRootFolder)}\n                        </option>\n                        {testResponse.rootFolders.length > 0 &&\n                          testResponse.rootFolders.map((folder) => (\n                            <option\n                              key={`loaded-profile-${folder.id}`}\n                              value={folder.path}\n                            >\n                              {folder.path}\n                            </option>\n                          ))}\n                      </Field>\n                    </div>\n                    {errors.rootFolder &&\n                      touched.rootFolder &&\n                      typeof errors.rootFolder === 'string' && (\n                        <div className=\"error\">{errors.rootFolder}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"profileIdRule\" className=\"text-label\">\n                    {intl.formatMessage(messages.qualityprofile)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"profileIdRule\"\n                        name=\"profileId\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"\">\n                          {intl.formatMessage(messages.selectQualityProfile)}\n                        </option>\n                        {testResponse.profiles.length > 0 &&\n                          testResponse.profiles.map((profile) => (\n                            <option\n                              key={`loaded-profile-${profile.id}`}\n                              value={profile.id}\n                            >\n                              {profile.name}\n                            </option>\n                          ))}\n                      </Field>\n                    </div>\n                    {errors.profileId &&\n                      touched.profileId &&\n                      typeof errors.profileId === 'string' && (\n                        <div className=\"error\">{errors.profileId}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"tags\" className=\"text-label\">\n                    {intl.formatMessage(messages.tags)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Select<OptionType, true>\n                      options={testResponse.tags.map((tag) => ({\n                        label: tag.label,\n                        value: tag.id,\n                      }))}\n                      isMulti\n                      isDisabled={!isValidated || isTesting}\n                      placeholder={intl.formatMessage(messages.selecttags)}\n                      className=\"react-select-container\"\n                      classNamePrefix=\"react-select\"\n                      value={\n                        (values?.tags\n                          ?.split(',')\n                          .map((tagId) => {\n                            const foundTag = testResponse.tags.find(\n                              (tag) => tag.id === Number(tagId)\n                            );\n\n                            if (!foundTag) {\n                              return undefined;\n                            }\n\n                            return {\n                              value: foundTag.id,\n                              label: foundTag.label,\n                            };\n                          })\n                          .filter(\n                            (option) => option !== undefined\n                          ) as OptionType[]) || []\n                      }\n                      onChange={(value) => {\n                        setFieldValue(\n                          'tags',\n                          value.map((option) => option.value).join(',')\n                        );\n                      }}\n                      noOptionsMessage={() =>\n                        intl.formatMessage(messages.notagoptions)\n                      }\n                    />\n                  </div>\n                </div>\n              </div>\n            </Modal>\n          );\n        }}\n      </Formik>\n    </Transition>\n  );\n};\n\nexport default OverrideRuleModal;\n"
  },
  {
    "path": "src/components/Settings/OverrideRule/OverrideRuleTiles.tsx",
    "content": "import type { DVRTestResponse } from '@app/components/Settings/SettingsServices';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { PencilIcon, TrashIcon } from '@heroicons/react/24/solid';\nimport type { TmdbGenre } from '@server/api/themoviedb/interfaces';\nimport type OverrideRule from '@server/entity/OverrideRule';\nimport type { User } from '@server/entity/User';\nimport type {\n  DVRSettings,\n  Language,\n  RadarrSettings,\n  SonarrSettings,\n} from '@server/lib/settings';\nimport type { Keyword } from '@server/models/common';\nimport axios from 'axios';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Settings.OverrideRuleTile', {\n  qualityprofile: 'Quality Profile',\n  rootfolder: 'Root Folder',\n  tags: 'Tags',\n  users: 'Users',\n  genre: 'Genre',\n  language: 'Language',\n  keywords: 'Keywords',\n  conditions: 'Conditions',\n  settings: 'Settings',\n});\n\ninterface OverrideRuleTilesProps {\n  rules: OverrideRule[];\n  setOverrideRuleModal: ({\n    open,\n    rule,\n  }: {\n    open: boolean;\n    rule: OverrideRule | null;\n  }) => void;\n  revalidate: () => void;\n  radarrServices: RadarrSettings[];\n  sonarrServices: SonarrSettings[];\n}\n\nconst OverrideRuleTiles = ({\n  rules,\n  setOverrideRuleModal,\n  revalidate,\n  radarrServices,\n  sonarrServices,\n}: OverrideRuleTilesProps) => {\n  const intl = useIntl();\n  const [users, setUsers] = useState<User[] | null>(null);\n  const [keywords, setKeywords] = useState<Keyword[] | null>(null);\n  const { data: languages } = useSWR<Language[]>('/api/v1/languages');\n  const { data: genres } = useSWR<TmdbGenre[]>('/api/v1/genres/movie');\n  const [testResponses, setTestResponses] = useState<\n    (DVRTestResponse & { type: string; id: number })[]\n  >([]);\n\n  const getServiceInfos = useCallback(async () => {\n    const results: (DVRTestResponse & { type: string; id: number })[] = [];\n    const services: DVRSettings[] = [...radarrServices, ...sonarrServices];\n    for (const service of services) {\n      const { hostname, port, apiKey, baseUrl, useSsl = false } = service;\n      try {\n        const response = await axios.post<DVRTestResponse>(\n          `/api/v1/settings/${\n            radarrServices.includes(service as RadarrSettings)\n              ? 'radarr'\n              : 'sonarr'\n          }/test`,\n          {\n            hostname,\n            apiKey,\n            port: Number(port),\n            baseUrl,\n            useSsl,\n          }\n        );\n        results.push({\n          type: radarrServices.includes(service as RadarrSettings)\n            ? 'radarr'\n            : 'sonarr',\n          id: service.id,\n          ...response.data,\n        });\n      } catch {\n        results.push({\n          type: radarrServices.includes(service as RadarrSettings)\n            ? 'radarr'\n            : 'sonarr',\n          id: service.id,\n          profiles: [],\n          rootFolders: [],\n          tags: [],\n        });\n      }\n    }\n    setTestResponses(results);\n  }, [radarrServices, sonarrServices]);\n\n  useEffect(() => {\n    getServiceInfos();\n  }, [getServiceInfos]);\n\n  useEffect(() => {\n    (async () => {\n      const keywords = await Promise.all(\n        rules\n          .map((rule) => rule.keywords?.split(','))\n          .flat()\n          .filter((keywordId) => keywordId)\n          .map(async (keywordId) => {\n            const response = await axios.get<Keyword | null>(\n              `/api/v1/keyword/${keywordId}`\n            );\n            return response.data;\n          })\n      );\n      const validKeywords: Keyword[] = keywords.filter(\n        (keyword): keyword is Keyword => keyword !== null\n      );\n      setKeywords(validKeywords);\n      const allUsersFromRules = rules\n        .map((rule) => rule.users)\n        .filter((users) => users)\n        .join(',');\n      if (allUsersFromRules) {\n        const response = await axios.get(\n          `/api/v1/user?includeIds=${encodeURIComponent(allUsersFromRules)}`\n        );\n        const users: User[] = response.data.results;\n        setUsers(users);\n      }\n    })();\n  }, [rules, users]);\n\n  return (\n    <>\n      {rules.map((rule) => (\n        <li className=\"flex h-full flex-col rounded-lg bg-gray-800 text-left shadow ring-1 ring-gray-500\">\n          <div className=\"flex w-full flex-1 items-center justify-between space-x-6 p-6\">\n            <div className=\"flex-1 truncate\">\n              <span className=\"text-lg\">\n                {intl.formatMessage(messages.conditions)}\n              </span>\n              {rule.users && (\n                <p className=\"truncate text-sm leading-5 text-gray-300\">\n                  <span className=\"mr-2 font-bold\">\n                    {intl.formatMessage(messages.users)}\n                  </span>\n                  <div className=\"inline-flex gap-2\">\n                    {rule.users.split(',').map((userId) => {\n                      return (\n                        <span>\n                          {\n                            users?.find((user) => user.id === Number(userId))\n                              ?.displayName\n                          }\n                        </span>\n                      );\n                    })}\n                  </div>\n                </p>\n              )}\n              {rule.genre && (\n                <p className=\"truncate text-sm leading-5 text-gray-300\">\n                  <span className=\"mr-2 font-bold\">\n                    {intl.formatMessage(messages.genre)}\n                  </span>\n                  <div className=\"inline-flex gap-2\">\n                    {rule.genre.split(',').map((genreId) => (\n                      <span>\n                        {genres?.find((g) => g.id === Number(genreId))?.name}\n                      </span>\n                    ))}\n                  </div>\n                </p>\n              )}\n              {rule.language && (\n                <p className=\"truncate text-sm leading-5 text-gray-300\">\n                  <span className=\"mr-2 font-bold\">\n                    {intl.formatMessage(messages.language)}\n                  </span>\n                  <div className=\"inline-flex gap-2\">\n                    {rule.language\n                      .split('|')\n                      .filter((languageId) => languageId !== 'server')\n                      .map((languageId) => {\n                        const language = languages?.find(\n                          (language) => language.iso_639_1 === languageId\n                        );\n                        if (!language) return null;\n                        const languageName =\n                          intl.formatDisplayName(language.iso_639_1, {\n                            type: 'language',\n                            fallback: 'none',\n                          }) ?? language.english_name;\n                        return <span>{languageName}</span>;\n                      })}\n                  </div>\n                </p>\n              )}\n              {rule.keywords && (\n                <p className=\"truncate text-sm leading-5 text-gray-300\">\n                  <span className=\"mr-2 font-bold\">\n                    {intl.formatMessage(messages.keywords)}\n                  </span>\n                  <div className=\"inline-flex gap-2\">\n                    {rule.keywords.split(',').map((keywordId) => {\n                      return (\n                        <span>\n                          {\n                            keywords?.find(\n                              (keyword) => keyword.id === Number(keywordId)\n                            )?.name\n                          }\n                        </span>\n                      );\n                    })}\n                  </div>\n                </p>\n              )}\n              <span className=\"text-lg\">\n                {intl.formatMessage(messages.settings)}\n              </span>\n              {rule.profileId && (\n                <p className=\"runcate text-sm leading-5 text-gray-300\">\n                  <span className=\"mr-2 font-bold\">\n                    {intl.formatMessage(messages.qualityprofile)}\n                  </span>\n                  {testResponses\n                    .find(\n                      (r) =>\n                        (r.id === rule.radarrServiceId &&\n                          r.type === 'radarr') ||\n                        (r.id === rule.sonarrServiceId && r.type === 'sonarr')\n                    )\n                    ?.profiles.find((profile) => rule.profileId === profile.id)\n                    ?.name || rule.profileId}\n                </p>\n              )}\n              {rule.rootFolder && (\n                <p className=\"truncate text-sm leading-5 text-gray-300\">\n                  <span className=\"mr-2 font-bold\">\n                    {intl.formatMessage(messages.rootfolder)}\n                  </span>\n                  {rule.rootFolder}\n                </p>\n              )}\n              {rule.tags && rule.tags.length > 0 && (\n                <p className=\"truncate text-sm leading-5 text-gray-300\">\n                  <span className=\"mr-2 font-bold\">\n                    {intl.formatMessage(messages.tags)}\n                  </span>\n                  <div className=\"inline-flex gap-2\">\n                    {rule.tags.split(',').map((tag) => (\n                      <span>\n                        {testResponses\n                          .find(\n                            (r) =>\n                              (r.id === rule.radarrServiceId &&\n                                r.type === 'radarr') ||\n                              (r.id === rule.sonarrServiceId &&\n                                r.type === 'sonarr')\n                          )\n                          ?.tags?.find((t) => t.id === Number(tag))?.label ||\n                          tag}\n                      </span>\n                    ))}\n                  </div>\n                </p>\n              )}\n            </div>\n          </div>\n          <div className=\"border-t border-gray-500\">\n            <div className=\"-mt-px flex\">\n              <div className=\"flex w-0 flex-1 border-r border-gray-500\">\n                <button\n                  onClick={() => setOverrideRuleModal({ open: true, rule })}\n                  className=\"focus:ring-blue relative -mr-px inline-flex w-0 flex-1 items-center justify-center rounded-bl-lg border border-transparent py-4 text-sm font-medium leading-5 text-gray-200 transition duration-150 ease-in-out hover:text-white focus:z-10 focus:border-gray-500 focus:outline-none\"\n                >\n                  <PencilIcon className=\"mr-2 h-5 w-5\" />\n                  <span>{intl.formatMessage(globalMessages.edit)}</span>\n                </button>\n              </div>\n              <div className=\"-ml-px flex w-0 flex-1\">\n                <button\n                  onClick={async () => {\n                    await axios.delete(`/api/v1/overrideRule/${rule.id}`);\n                    revalidate();\n                  }}\n                  className=\"focus:ring-blue relative inline-flex w-0 flex-1 items-center justify-center rounded-br-lg border border-transparent py-4 text-sm font-medium leading-5 text-gray-200 transition duration-150 ease-in-out hover:text-white focus:z-10 focus:border-gray-500 focus:outline-none\"\n                >\n                  <TrashIcon className=\"mr-2 h-5 w-5\" />\n                  <span>{intl.formatMessage(globalMessages.delete)}</span>\n                </button>\n              </div>\n            </div>\n          </div>\n        </li>\n      ))}\n    </>\n  );\n};\n\nexport default OverrideRuleTiles;\n"
  },
  {
    "path": "src/components/Settings/RadarrModal/index.tsx",
    "content": "import Modal from '@app/components/Common/Modal';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport type { RadarrTestResponse } from '@app/components/Settings/SettingsServices';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { isValidURL } from '@app/utils/urlValidationHelper';\nimport { Transition } from '@headlessui/react';\nimport type { RadarrSettings } from '@server/lib/settings';\nimport axios from 'axios';\nimport { Field, Formik } from 'formik';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport Select from 'react-select';\nimport { useToasts } from 'react-toast-notifications';\nimport * as Yup from 'yup';\n\ntype OptionType = {\n  value: number;\n  label: string;\n};\n\nconst messages = defineMessages('components.Settings.RadarrModal', {\n  createradarr: 'Add New Radarr Server',\n  create4kradarr: 'Add New 4K Radarr Server',\n  editradarr: 'Edit Radarr Server',\n  edit4kradarr: 'Edit 4K Radarr Server',\n  validationNameRequired: 'You must provide a server name',\n  validationHostnameRequired: 'You must provide a valid hostname or IP address',\n  validationPortRequired: 'You must provide a valid port number',\n  validationApiKeyRequired: 'You must provide an API key',\n  validationRootFolderRequired: 'You must select a root folder',\n  validationProfileRequired: 'You must select a quality profile',\n  validationMinimumAvailabilityRequired:\n    'You must select a minimum availability',\n  toastRadarrTestSuccess: 'Radarr connection established successfully!',\n  toastRadarrTestFailure: 'Failed to connect to Radarr.',\n  add: 'Add Server',\n  defaultserver: 'Default Server',\n  default4kserver: 'Default 4K Server',\n  servername: 'Server Name',\n  hostname: 'Hostname or IP Address',\n  port: 'Port',\n  ssl: 'Use SSL',\n  apiKey: 'API Key',\n  baseUrl: 'URL Base',\n  syncEnabled: 'Enable Scan',\n  externalUrl: 'External URL',\n  qualityprofile: 'Quality Profile',\n  rootfolder: 'Root Folder',\n  minimumAvailability: 'Minimum Availability',\n  server4k: '4K Server',\n  selectQualityProfile: 'Select quality profile',\n  selectRootFolder: 'Select root folder',\n  selectMinimumAvailability: 'Select minimum availability',\n  loadingprofiles: 'Loading quality profiles…',\n  testFirstQualityProfiles: 'Test connection to load quality profiles',\n  loadingrootfolders: 'Loading root folders…',\n  testFirstRootFolders: 'Test connection to load root folders',\n  loadingTags: 'Loading tags…',\n  testFirstTags: 'Test connection to load tags',\n  tags: 'Tags',\n  enableSearch: 'Enable Automatic Search',\n  tagRequests: 'Tag Requests',\n  tagRequestsInfo:\n    \"Automatically add an additional tag with the requester's user ID & display name\",\n  validationApplicationUrl: 'You must provide a valid URL',\n  validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',\n  validationBaseUrlLeadingSlash: 'URL base must have a leading slash',\n  validationBaseUrlTrailingSlash: 'URL base must not end in a trailing slash',\n  notagoptions: 'No tags.',\n  selecttags: 'Select tags',\n  announced: 'Announced',\n  inCinemas: 'In Cinemas',\n  released: 'Released',\n});\n\ninterface RadarrModalProps {\n  radarr: RadarrSettings | null;\n  onClose: () => void;\n  onSave: () => void;\n}\n\nconst RadarrModal = ({ onClose, radarr, onSave }: RadarrModalProps) => {\n  const intl = useIntl();\n  const initialLoad = useRef(false);\n  const { addToast } = useToasts();\n  const [isValidated, setIsValidated] = useState(radarr ? true : false);\n  const [isTesting, setIsTesting] = useState(false);\n  const [testResponse, setTestResponse] = useState<RadarrTestResponse>({\n    profiles: [],\n    rootFolders: [],\n    tags: [],\n  });\n\n  const RadarrSettingsSchema = Yup.object().shape({\n    name: Yup.string().required(\n      intl.formatMessage(messages.validationNameRequired)\n    ),\n    hostname: Yup.string().required(\n      intl.formatMessage(messages.validationHostnameRequired)\n    ),\n    port: Yup.number()\n      .nullable()\n      .required(intl.formatMessage(messages.validationPortRequired)),\n    apiKey: Yup.string().required(\n      intl.formatMessage(messages.validationApiKeyRequired)\n    ),\n    rootFolder: Yup.string().required(\n      intl.formatMessage(messages.validationRootFolderRequired)\n    ),\n    activeProfileId: Yup.string().required(\n      intl.formatMessage(messages.validationProfileRequired)\n    ),\n    minimumAvailability: Yup.string().required(\n      intl.formatMessage(messages.validationMinimumAvailabilityRequired)\n    ),\n    externalUrl: Yup.string()\n      .test(\n        'valid-url',\n        intl.formatMessage(messages.validationApplicationUrl),\n        isValidURL\n      )\n      .test(\n        'no-trailing-slash',\n        intl.formatMessage(messages.validationApplicationUrlTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n    baseUrl: Yup.string()\n      .test(\n        'leading-slash',\n        intl.formatMessage(messages.validationBaseUrlLeadingSlash),\n        (value) => !value || value.startsWith('/')\n      )\n      .test(\n        'no-trailing-slash',\n        intl.formatMessage(messages.validationBaseUrlTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n  });\n\n  const testConnection = useCallback(\n    async ({\n      hostname,\n      port,\n      apiKey,\n      baseUrl,\n      useSsl = false,\n    }: {\n      hostname: string;\n      port: number;\n      apiKey: string;\n      baseUrl?: string;\n      useSsl?: boolean;\n    }) => {\n      setIsTesting(true);\n      try {\n        const response = await axios.post<RadarrTestResponse>(\n          '/api/v1/settings/radarr/test',\n          {\n            hostname,\n            apiKey,\n            port: Number(port),\n            baseUrl,\n            useSsl,\n          }\n        );\n\n        setIsValidated(true);\n        setTestResponse(response.data);\n        if (initialLoad.current) {\n          addToast(intl.formatMessage(messages.toastRadarrTestSuccess), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        }\n      } catch {\n        setIsValidated(false);\n        if (initialLoad.current) {\n          addToast(intl.formatMessage(messages.toastRadarrTestFailure), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        }\n      } finally {\n        setIsTesting(false);\n        initialLoad.current = true;\n      }\n    },\n    [addToast, intl]\n  );\n\n  useEffect(() => {\n    if (radarr) {\n      testConnection({\n        apiKey: radarr.apiKey,\n        hostname: radarr.hostname,\n        port: radarr.port,\n        baseUrl: radarr.baseUrl,\n        useSsl: radarr.useSsl,\n      });\n    }\n  }, [radarr, testConnection]);\n\n  return (\n    <Transition\n      as=\"div\"\n      appear\n      show\n      enter=\"transition-opacity ease-in-out duration-300\"\n      enterFrom=\"opacity-0\"\n      enterTo=\"opacity-100\"\n      leave=\"transition-opacity ease-in-out duration-300\"\n      leaveFrom=\"opacity-100\"\n      leaveTo=\"opacity-0\"\n    >\n      <Formik\n        initialValues={{\n          name: radarr?.name,\n          hostname: radarr?.hostname,\n          port: radarr?.port ?? 7878,\n          ssl: radarr?.useSsl ?? false,\n          apiKey: radarr?.apiKey,\n          baseUrl: radarr?.baseUrl,\n          activeProfileId: radarr?.activeProfileId,\n          rootFolder: radarr?.activeDirectory,\n          minimumAvailability: radarr?.minimumAvailability ?? 'released',\n          tags: radarr?.tags ?? [],\n          isDefault: radarr?.isDefault ?? false,\n          is4k: radarr?.is4k ?? false,\n          externalUrl: radarr?.externalUrl,\n          syncEnabled: radarr?.syncEnabled ?? false,\n          enableSearch: !radarr?.preventSearch,\n          tagRequests: radarr?.tagRequests ?? false,\n        }}\n        validationSchema={RadarrSettingsSchema}\n        onSubmit={async (values) => {\n          try {\n            const profileName = testResponse.profiles.find(\n              (profile) => profile.id === Number(values.activeProfileId)\n            )?.name;\n\n            const submission = {\n              name: values.name,\n              hostname: values.hostname,\n              port: Number(values.port),\n              apiKey: values.apiKey,\n              useSsl: values.ssl,\n              baseUrl: values.baseUrl,\n              activeProfileId: Number(values.activeProfileId),\n              activeProfileName: profileName,\n              activeDirectory: values.rootFolder,\n              is4k: values.is4k,\n              minimumAvailability: values.minimumAvailability,\n              tags: values.tags,\n              isDefault: values.isDefault,\n              externalUrl: values.externalUrl,\n              syncEnabled: values.syncEnabled,\n              preventSearch: !values.enableSearch,\n              tagRequests: values.tagRequests,\n            };\n            if (!radarr) {\n              await axios.post('/api/v1/settings/radarr', submission);\n            } else {\n              await axios.put(\n                `/api/v1/settings/radarr/${radarr.id}`,\n                submission\n              );\n            }\n\n            onSave();\n          } catch {\n            // set error here\n          }\n        }}\n      >\n        {({\n          errors,\n          touched,\n          values,\n          handleSubmit,\n          setFieldValue,\n          isSubmitting,\n          isValid,\n        }) => {\n          return (\n            <Modal\n              onCancel={onClose}\n              okButtonType=\"primary\"\n              okText={\n                isSubmitting\n                  ? intl.formatMessage(globalMessages.saving)\n                  : radarr\n                    ? intl.formatMessage(globalMessages.save)\n                    : intl.formatMessage(messages.add)\n              }\n              secondaryButtonType=\"warning\"\n              secondaryText={\n                isTesting\n                  ? intl.formatMessage(globalMessages.testing)\n                  : intl.formatMessage(globalMessages.test)\n              }\n              onSecondary={() => {\n                if (values.apiKey && values.hostname && values.port) {\n                  testConnection({\n                    apiKey: values.apiKey,\n                    baseUrl: values.baseUrl,\n                    hostname: values.hostname,\n                    port: values.port,\n                    useSsl: values.ssl,\n                  });\n                  if (!values.baseUrl || values.baseUrl === '/') {\n                    setFieldValue('baseUrl', testResponse.urlBase);\n                  }\n                }\n              }}\n              secondaryDisabled={\n                !values.apiKey ||\n                !values.hostname ||\n                !values.port ||\n                isTesting ||\n                isSubmitting\n              }\n              okDisabled={!isValidated || isSubmitting || isTesting || !isValid}\n              onOk={() => handleSubmit()}\n              title={\n                !radarr\n                  ? intl.formatMessage(\n                      values.is4k\n                        ? messages.create4kradarr\n                        : messages.createradarr\n                    )\n                  : intl.formatMessage(\n                      values.is4k ? messages.edit4kradarr : messages.editradarr\n                    )\n              }\n            >\n              <div className=\"mb-6\">\n                <div className=\"form-row\">\n                  <label htmlFor=\"isDefault\" className=\"checkbox-label\">\n                    {intl.formatMessage(\n                      values.is4k\n                        ? messages.default4kserver\n                        : messages.defaultserver\n                    )}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field type=\"checkbox\" id=\"isDefault\" name=\"isDefault\" />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"is4k\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.server4k)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field type=\"checkbox\" id=\"is4k\" name=\"is4k\" />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"name\" className=\"text-label\">\n                    {intl.formatMessage(messages.servername)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"name\"\n                        name=\"name\"\n                        type=\"text\"\n                        autoComplete=\"off\"\n                        data-form-type=\"other\"\n                        data-1pignore=\"true\"\n                        data-lpignore=\"true\"\n                        data-bwignore=\"true\"\n                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                          setIsValidated(false);\n                          setFieldValue('name', e.target.value);\n                        }}\n                      />\n                    </div>\n                    {errors.name &&\n                      touched.name &&\n                      typeof errors.name === 'string' && (\n                        <div className=\"error\">{errors.name}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"hostname\" className=\"text-label\">\n                    {intl.formatMessage(messages.hostname)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <span className=\"protocol\">\n                        {values.ssl ? 'https://' : 'http://'}\n                      </span>\n                      <Field\n                        id=\"hostname\"\n                        name=\"hostname\"\n                        type=\"text\"\n                        inputMode=\"url\"\n                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                          setIsValidated(false);\n                          setFieldValue('hostname', e.target.value);\n                        }}\n                        className=\"rounded-r-only\"\n                      />\n                    </div>\n                    {errors.hostname &&\n                      touched.hostname &&\n                      typeof errors.hostname === 'string' && (\n                        <div className=\"error\">{errors.hostname}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"port\" className=\"text-label\">\n                    {intl.formatMessage(messages.port)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      id=\"port\"\n                      name=\"port\"\n                      type=\"text\"\n                      inputMode=\"numeric\"\n                      className=\"short\"\n                      onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                        setIsValidated(false);\n                        setFieldValue('port', e.target.value);\n                      }}\n                    />\n                    {errors.port &&\n                      touched.port &&\n                      typeof errors.port === 'string' && (\n                        <div className=\"error\">{errors.port}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"ssl\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.ssl)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"ssl\"\n                      name=\"ssl\"\n                      onChange={() => {\n                        setIsValidated(false);\n                        setFieldValue('ssl', !values.ssl);\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"apiKey\" className=\"text-label\">\n                    {intl.formatMessage(messages.apiKey)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <SensitiveInput\n                        as=\"field\"\n                        id=\"apiKey\"\n                        name=\"apiKey\"\n                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                          setIsValidated(false);\n                          setFieldValue('apiKey', e.target.value);\n                        }}\n                      />\n                    </div>\n                    {errors.apiKey &&\n                      touched.apiKey &&\n                      typeof errors.apiKey === 'string' && (\n                        <div className=\"error\">{errors.apiKey}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"baseUrl\" className=\"text-label\">\n                    {intl.formatMessage(messages.baseUrl)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"baseUrl\"\n                        name=\"baseUrl\"\n                        type=\"text\"\n                        inputMode=\"url\"\n                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                          setIsValidated(false);\n                          setFieldValue('baseUrl', e.target.value);\n                        }}\n                      />\n                    </div>\n                    {errors.baseUrl &&\n                      touched.baseUrl &&\n                      typeof errors.baseUrl === 'string' && (\n                        <div className=\"error\">{errors.baseUrl}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"activeProfileId\" className=\"text-label\">\n                    {intl.formatMessage(messages.qualityprofile)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"activeProfileId\"\n                        name=\"activeProfileId\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"\">\n                          {isTesting\n                            ? intl.formatMessage(messages.loadingprofiles)\n                            : !isValidated\n                              ? intl.formatMessage(\n                                  messages.testFirstQualityProfiles\n                                )\n                              : intl.formatMessage(\n                                  messages.selectQualityProfile\n                                )}\n                        </option>\n                        {testResponse.profiles.length > 0 &&\n                          testResponse.profiles\n                            .toSorted((a, b) =>\n                              a.name.localeCompare(b.name, intl.locale, {\n                                numeric: true,\n                                sensitivity: 'base',\n                              })\n                            )\n                            .map((profile) => (\n                              <option\n                                key={`loaded-profile-${profile.id}`}\n                                value={profile.id}\n                              >\n                                {profile.name}\n                              </option>\n                            ))}\n                      </Field>\n                    </div>\n                    {errors.activeProfileId &&\n                      touched.activeProfileId &&\n                      typeof errors.activeProfileId === 'string' && (\n                        <div className=\"error\">{errors.activeProfileId}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"rootFolder\" className=\"text-label\">\n                    {intl.formatMessage(messages.rootfolder)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"rootFolder\"\n                        name=\"rootFolder\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"\">\n                          {isTesting\n                            ? intl.formatMessage(messages.loadingrootfolders)\n                            : !isValidated\n                              ? intl.formatMessage(\n                                  messages.testFirstRootFolders\n                                )\n                              : intl.formatMessage(messages.selectRootFolder)}\n                        </option>\n                        {testResponse.rootFolders.length > 0 &&\n                          testResponse.rootFolders.map((folder) => (\n                            <option\n                              key={`loaded-profile-${folder.id}`}\n                              value={folder.path}\n                            >\n                              {folder.path}\n                            </option>\n                          ))}\n                      </Field>\n                    </div>\n                    {errors.rootFolder &&\n                      touched.rootFolder &&\n                      typeof errors.rootFolder === 'string' && (\n                        <div className=\"error\">{errors.rootFolder}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"minimumAvailability\" className=\"text-label\">\n                    {intl.formatMessage(messages.minimumAvailability)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"minimumAvailability\"\n                        name=\"minimumAvailability\"\n                      >\n                        <option value=\"announced\">\n                          {intl.formatMessage(messages.announced)}\n                        </option>\n                        <option value=\"inCinemas\">\n                          {intl.formatMessage(messages.inCinemas)}\n                        </option>\n                        <option value=\"released\">\n                          {intl.formatMessage(messages.released)}\n                        </option>\n                      </Field>\n                    </div>\n                    {errors.minimumAvailability &&\n                      touched.minimumAvailability && (\n                        <div className=\"error\">\n                          {errors.minimumAvailability}\n                        </div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"tags\" className=\"text-label\">\n                    {intl.formatMessage(messages.tags)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Select<OptionType, true>\n                      options={\n                        isValidated\n                          ? testResponse.tags.map((tag) => ({\n                              label: tag.label,\n                              value: tag.id,\n                            }))\n                          : []\n                      }\n                      isMulti\n                      isDisabled={!isValidated || isTesting}\n                      placeholder={\n                        !isValidated\n                          ? intl.formatMessage(messages.testFirstTags)\n                          : isTesting\n                            ? intl.formatMessage(messages.loadingTags)\n                            : intl.formatMessage(messages.selecttags)\n                      }\n                      className=\"react-select-container\"\n                      classNamePrefix=\"react-select\"\n                      value={\n                        values.tags\n                          .map((tagId) => {\n                            const foundTag = testResponse.tags.find(\n                              (tag) => tag.id === tagId\n                            );\n\n                            if (!foundTag) {\n                              return undefined;\n                            }\n\n                            return {\n                              value: foundTag.id,\n                              label: foundTag.label,\n                            };\n                          })\n                          .filter(\n                            (option) => option !== undefined\n                          ) as OptionType[]\n                      }\n                      onChange={(value) => {\n                        setFieldValue(\n                          'tags',\n                          value.map((option) => option.value)\n                        );\n                      }}\n                      noOptionsMessage={() =>\n                        intl.formatMessage(messages.notagoptions)\n                      }\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"externalUrl\" className=\"text-label\">\n                    {intl.formatMessage(messages.externalUrl)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"externalUrl\"\n                        name=\"externalUrl\"\n                        type=\"text\"\n                        inputMode=\"url\"\n                      />\n                    </div>\n                    {errors.externalUrl &&\n                      touched.externalUrl &&\n                      typeof errors.externalUrl === 'string' && (\n                        <div className=\"error\">{errors.externalUrl}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"syncEnabled\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.syncEnabled)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"syncEnabled\"\n                      name=\"syncEnabled\"\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"enableSearch\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.enableSearch)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"enableSearch\"\n                      name=\"enableSearch\"\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"tagRequests\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.tagRequests)}\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.tagRequestsInfo)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"tagRequests\"\n                      name=\"tagRequests\"\n                    />\n                  </div>\n                </div>\n              </div>\n            </Modal>\n          );\n        }}\n      </Formik>\n    </Transition>\n  );\n};\n\nexport default RadarrModal;\n"
  },
  {
    "path": "src/components/Settings/SettingsAbout/Releases/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport Modal from '@app/components/Common/Modal';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport { DocumentTextIcon } from '@heroicons/react/24/outline';\nimport dynamic from 'next/dynamic';\nimport { Fragment, useState } from 'react';\nimport { FormattedRelativeTime, useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\n// dyanmic is having trouble extracting the props for react-markdown here so we are just ignoring it since its really\n// only children we are using\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst ReactMarkdown = dynamic<any>(() => import('react-markdown'), {\n  ssr: false,\n});\n\nconst messages = defineMessages('components.Settings.SettingsAbout.Releases', {\n  releases: 'Releases',\n  releasedataMissing: 'Release data is currently unavailable.',\n  versionChangelog: '{version} Changelog',\n  viewongithub: 'View on GitHub',\n  latestversion: 'Latest',\n  currentversion: 'Current',\n  viewchangelog: 'View Changelog',\n});\n\nconst REPO_RELEASE_API =\n  'https://api.github.com/repos/seerr-team/seerr/releases?per_page=20';\n\ninterface GitHubRelease {\n  url: string;\n  assets_url: string;\n  upload_url: string;\n  html_url: string;\n  id: number;\n  node_id: string;\n  tag_name: string;\n  target_commitish: string;\n  name: string;\n  draft: boolean;\n  prerelease: boolean;\n  created_at: string;\n  published_at: string;\n  tarball_url: string;\n  zipball_url: string;\n  body: string;\n}\n\ninterface ReleaseProps {\n  release: GitHubRelease;\n  isLatest: boolean;\n  currentVersion: string;\n}\n\nconst Release = ({ currentVersion, release, isLatest }: ReleaseProps) => {\n  const intl = useIntl();\n  const [isModalOpen, setModalOpen] = useState(false);\n\n  return (\n    <div className=\"flex w-full flex-col space-y-3 rounded-md bg-gray-800 px-4 py-2 shadow-md ring-1 ring-gray-700 sm:flex-row sm:space-x-3 sm:space-y-0\">\n      <Transition\n        as={Fragment}\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={isModalOpen}\n      >\n        <Modal\n          onCancel={() => setModalOpen(false)}\n          title={intl.formatMessage(messages.versionChangelog, {\n            version: release.name,\n          })}\n          cancelText={intl.formatMessage(globalMessages.close)}\n          okText={intl.formatMessage(messages.viewongithub)}\n          onOk={() => {\n            window.open(release.html_url, '_blank');\n          }}\n        >\n          <div className=\"prose\">\n            <ReactMarkdown>{release.body}</ReactMarkdown>\n          </div>\n        </Modal>\n      </Transition>\n      <div className=\"flex w-full flex-grow items-center justify-center space-x-2 truncate sm:justify-start\">\n        <span className=\"truncate text-lg font-bold\">\n          <span className=\"mr-2 whitespace-nowrap text-xs font-normal\">\n            <FormattedRelativeTime\n              value={Math.floor(\n                (new Date(release.created_at).getTime() - Date.now()) / 1000\n              )}\n              updateIntervalInSeconds={1}\n              numeric=\"auto\"\n            />\n          </span>\n          {release.name}\n        </span>\n        {isLatest && (\n          <Badge badgeType=\"success\">\n            {intl.formatMessage(messages.latestversion)}\n          </Badge>\n        )}\n        {release.name.includes(currentVersion) && (\n          <Badge badgeType=\"primary\">\n            {intl.formatMessage(messages.currentversion)}\n          </Badge>\n        )}\n      </div>\n      <Button buttonType=\"primary\" onClick={() => setModalOpen(true)}>\n        <DocumentTextIcon />\n        <span>{intl.formatMessage(messages.viewchangelog)}</span>\n      </Button>\n    </div>\n  );\n};\n\ninterface ReleasesProps {\n  currentVersion: string;\n}\n\nconst Releases = ({ currentVersion }: ReleasesProps) => {\n  const intl = useIntl();\n  const { data, error } = useSWR<GitHubRelease[]>(REPO_RELEASE_API);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return (\n      <div className=\"text-gray-300\">\n        {intl.formatMessage(messages.releasedataMissing)}\n      </div>\n    );\n  }\n\n  return (\n    <div>\n      <h3 className=\"heading\">{intl.formatMessage(messages.releases)}</h3>\n      <div className=\"section space-y-3\">\n        {data.map((release, index) => {\n          return (\n            <div key={`release-${release.id}`}>\n              <Release\n                release={release}\n                currentVersion={currentVersion}\n                isLatest={index === 0}\n              />\n            </div>\n          );\n        })}\n      </div>\n    </div>\n  );\n};\n\nexport default Releases;\n"
  },
  {
    "path": "src/components/Settings/SettingsAbout/index.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Badge from '@app/components/Common/Badge';\nimport List from '@app/components/Common/List';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport Releases from '@app/components/Settings/SettingsAbout/Releases';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type {\n  SettingsAboutResponse,\n  StatusResponse,\n} from '@server/interfaces/api/settingsInterfaces';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Settings.SettingsAbout', {\n  about: 'About',\n  aboutseerr: 'About Seerr',\n  version: 'Version',\n  totalmedia: 'Total Media',\n  totalrequests: 'Total Requests',\n  gettingsupport: 'Getting Support',\n  githubdiscussions: 'GitHub Discussions',\n  timezone: 'Time Zone',\n  appDataPath: 'Data Directory',\n  supportseerr: 'Support Seerr',\n  contribute: 'Make a Contribution',\n  documentation: 'Documentation',\n  outofdate: 'Out of Date',\n  uptodate: 'Up to Date',\n  runningDevelop:\n    'You are running the <code>develop</code> branch of Seerr, which is only recommended for those contributing to development or assisting with bleeding-edge testing.',\n});\n\nconst SettingsAbout = () => {\n  const intl = useIntl();\n  const { data, error } = useSWR<SettingsAboutResponse>(\n    '/api/v1/settings/about'\n  );\n\n  const { data: status } = useSWR<StatusResponse>('/api/v1/status');\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.about),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n      <div className=\"section\">\n        <List title={intl.formatMessage(messages.aboutseerr)}>\n          {data.version.startsWith('develop-') && (\n            <Alert\n              title={intl.formatMessage(messages.runningDevelop, {\n                code: (msg: React.ReactNode) => (\n                  <code className=\"bg-gray-800/50\">{msg}</code>\n                ),\n              })}\n            />\n          )}\n          <List.Item\n            title={intl.formatMessage(messages.version)}\n            className=\"flex flex-row items-center truncate\"\n          >\n            <code className=\"truncate\">\n              {data.version.replace('develop-', '')}\n            </code>\n            {status?.commitTag !== 'local' &&\n              (status?.updateAvailable ? (\n                <a\n                  href={\n                    data.version.startsWith('develop-')\n                      ? `https://github.com/seerr-team/seerr/compare/${status.commitTag}...develop`\n                      : 'https://github.com/seerr-team/seerr/releases'\n                  }\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                >\n                  <Badge\n                    badgeType=\"warning\"\n                    className=\"ml-2 !cursor-pointer transition hover:bg-yellow-400\"\n                  >\n                    {intl.formatMessage(messages.outofdate)}\n                  </Badge>\n                </a>\n              ) : (\n                <a\n                  href={\n                    data.version.startsWith('develop-')\n                      ? 'https://github.com/seerr-team/seerr/commits/develop'\n                      : 'https://github.com/seerr-team/seerr/releases'\n                  }\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                >\n                  <Badge\n                    badgeType=\"success\"\n                    className=\"ml-2 !cursor-pointer transition hover:bg-green-400\"\n                  >\n                    {intl.formatMessage(messages.uptodate)}\n                  </Badge>\n                </a>\n              ))}\n          </List.Item>\n          <List.Item title={intl.formatMessage(messages.totalmedia)}>\n            {intl.formatNumber(data.totalMediaItems)}\n          </List.Item>\n          <List.Item title={intl.formatMessage(messages.totalrequests)}>\n            {intl.formatNumber(data.totalRequests)}\n          </List.Item>\n          <List.Item title={intl.formatMessage(messages.appDataPath)}>\n            <code>{data.appDataPath}</code>\n          </List.Item>\n          {data.tz && (\n            <List.Item title={intl.formatMessage(messages.timezone)}>\n              <code>{data.tz}</code>\n            </List.Item>\n          )}\n        </List>\n      </div>\n      <div className=\"section\">\n        <List title={intl.formatMessage(messages.gettingsupport)}>\n          <List.Item title={intl.formatMessage(messages.documentation)}>\n            <a\n              href=\"https://docs.seerr.dev\"\n              target=\"_blank\"\n              rel=\"noreferrer\"\n              className=\"text-indigo-500 transition duration-300 hover:underline\"\n            >\n              https://docs.seerr.dev\n            </a>\n          </List.Item>\n          <List.Item title={intl.formatMessage(messages.githubdiscussions)}>\n            <a\n              href=\"https://github.com/seerr-team/seerr/discussions\"\n              target=\"_blank\"\n              rel=\"noreferrer\"\n              className=\"text-indigo-500 transition duration-300 hover:underline\"\n            >\n              https://github.com/seerr-team/seerr/discussions\n            </a>\n          </List.Item>\n          <List.Item title=\"Discord\">\n            <a\n              href=\"https://discord.gg/seerr\"\n              target=\"_blank\"\n              rel=\"noreferrer\"\n              className=\"text-indigo-500 transition duration-300 hover:underline\"\n            >\n              https://discord.gg/seerr\n            </a>\n          </List.Item>\n        </List>\n      </div>\n      <div className=\"section\">\n        <List title={intl.formatMessage(messages.supportseerr)}>\n          <List.Item title={intl.formatMessage(messages.contribute)}>\n            <a\n              href=\"https://opencollective.com/seerr\"\n              target=\"_blank\"\n              rel=\"noreferrer\"\n              className=\"text-indigo-500 transition duration-300 hover:underline\"\n            >\n              https://opencollective.com/seerr\n            </a>\n          </List.Item>\n        </List>\n      </div>\n      <div className=\"section\">\n        <Releases currentVersion={data.version} />\n      </div>\n    </>\n  );\n};\n\nexport default SettingsAbout;\n"
  },
  {
    "path": "src/components/Settings/SettingsBadge.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Settings', {\n  advancedTooltip:\n    'Incorrectly configuring this setting may result in broken functionality',\n  experimentalTooltip:\n    'Enabling this setting may result in unexpected application behavior',\n  restartrequiredTooltip:\n    'Seerr must be restarted for changes to this setting to take effect',\n});\n\nconst SettingsBadge = ({\n  badgeType,\n  className,\n}: {\n  badgeType: 'advanced' | 'experimental' | 'restartRequired';\n  className?: string;\n}) => {\n  const intl = useIntl();\n\n  switch (badgeType) {\n    case 'advanced':\n      return (\n        <Tooltip content={intl.formatMessage(messages.advancedTooltip)}>\n          <Badge badgeType=\"danger\" className={className}>\n            {intl.formatMessage(globalMessages.advanced)}\n          </Badge>\n        </Tooltip>\n      );\n    case 'experimental':\n      return (\n        <Tooltip content={intl.formatMessage(messages.experimentalTooltip)}>\n          <Badge badgeType=\"warning\">\n            {intl.formatMessage(globalMessages.experimental)}\n          </Badge>\n        </Tooltip>\n      );\n    case 'restartRequired':\n      return (\n        <Tooltip content={intl.formatMessage(messages.restartrequiredTooltip)}>\n          <Badge badgeType=\"primary\" className={className}>\n            {intl.formatMessage(globalMessages.restartRequired)}\n          </Badge>\n        </Tooltip>\n      );\n    default:\n      return null;\n  }\n};\n\nexport default SettingsBadge;\n"
  },
  {
    "path": "src/components/Settings/SettingsJellyfin.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport LibraryItem from '@app/components/Settings/LibraryItem';\nimport useSettings from '@app/hooks/useSettings';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { isValidURL } from '@app/utils/urlValidationHelper';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport { ApiErrorCode } from '@server/constants/error';\nimport { MediaServerType } from '@server/constants/server';\nimport type { JellyfinSettings } from '@server/lib/settings';\nimport axios from 'axios';\nimport { Field, Formik } from 'formik';\nimport { useState } from 'react';\nimport { FormattedMessage, useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Settings', {\n  jellyfinsettings: '{mediaServerName} Settings',\n  jellyfinsettingsDescription:\n    'Configure the settings for your {mediaServerName} server. {mediaServerName} scans your {mediaServerName} libraries to see what content is available.',\n  timeout: 'Timeout',\n  save: 'Save Changes',\n  saving: 'Saving…',\n  jellyfinlibraries: '{mediaServerName} Libraries',\n  jellyfinlibrariesDescription:\n    'The libraries {mediaServerName} scans for titles. Click the button below if no libraries are listed.',\n  jellyfinSettingsFailure:\n    'Something went wrong while saving {mediaServerName} settings.',\n  jellyfinSettingsSuccess: '{mediaServerName} settings saved successfully!',\n  jellyfinSettings: '{mediaServerName} Settings',\n  jellyfinSettingsDescription:\n    'Optionally configure the internal and external endpoints for your {mediaServerName} server. In most cases, the external URL is different to the internal URL. A custom password reset URL can also be set for {mediaServerName} login, in case you would like to redirect to a different password reset page. You can also change the Jellyfin API key, which was automatically generated previously.',\n  externalUrl: 'External URL',\n  hostname: 'Hostname or IP Address',\n  port: 'Port',\n  enablessl: 'Use SSL',\n  urlBase: 'URL Base',\n  jellyfinForgotPasswordUrl: 'Forgot Password URL',\n  apiKey: 'API key',\n  jellyfinSyncFailedNoLibrariesFound: 'No libraries were found',\n  jellyfinSyncFailedAutomaticGroupedFolders:\n    'Custom authentication with Automatic Library Grouping not supported',\n  jellyfinSyncFailedGenericError:\n    'Something went wrong while syncing libraries',\n  invalidurlerror: 'Unable to connect to {mediaServerName} server.',\n  syncing: 'Syncing',\n  syncJellyfin: 'Sync Libraries',\n  manualscanJellyfin: 'Manual Library Scan',\n  manualscanDescriptionJellyfin:\n    \"Normally, this will only be run once every 24 hours. Seerr will check your {mediaServerName} server's recently added more aggressively. If this is your first time configuring Seerr, a one-time full manual library scan is recommended!\",\n  notrunning: 'Not Running',\n  currentlibrary: 'Current Library: {name}',\n  librariesRemaining: 'Libraries Remaining: {count}',\n  startscan: 'Start Scan',\n  cancelscan: 'Cancel Scan',\n  validationUrl: 'You must provide a valid URL',\n  validationHostnameRequired: 'You must provide a valid hostname or IP address',\n  validationPortRequired: 'You must provide a valid port number',\n  validationUrlTrailingSlash: 'URL must not end in a trailing slash',\n  validationUrlBaseLeadingSlash: 'URL base must have a leading slash',\n  validationUrlBaseTrailingSlash: 'URL base must not end in a trailing slash',\n  tip: 'Tip',\n  scanbackground:\n    'Scanning will run in the background. You can continue the setup process in the meantime.',\n});\n\ninterface Library {\n  id: string;\n  name: string;\n  enabled: boolean;\n}\n\ninterface SyncStatus {\n  running: boolean;\n  progress: number;\n  total: number;\n  currentLibrary?: Library;\n  libraries: Library[];\n}\n\ninterface SettingsJellyfinProps {\n  isSetupSettings?: boolean;\n  onComplete?: () => void;\n}\n\nconst SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({\n  onComplete,\n  isSetupSettings,\n}) => {\n  const [isSyncing, setIsSyncing] = useState(false);\n  const toasts = useToasts();\n\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<JellyfinSettings>('/api/v1/settings/jellyfin');\n  const { data: dataSync, mutate: revalidateSync } = useSWR<SyncStatus>(\n    '/api/v1/settings/jellyfin/sync',\n    {\n      refreshInterval: 1000,\n    }\n  );\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const settings = useSettings();\n\n  const JellyfinSettingsSchema = Yup.object().shape({\n    hostname: Yup.string()\n      .nullable()\n      .required(intl.formatMessage(messages.validationHostnameRequired)),\n    port: Yup.number().when(['hostname'], {\n      is: (value: unknown) => !!value,\n      then: Yup.number()\n        .typeError(intl.formatMessage(messages.validationPortRequired))\n        .nullable()\n        .required(intl.formatMessage(messages.validationPortRequired)),\n      otherwise: Yup.number()\n        .typeError(intl.formatMessage(messages.validationPortRequired))\n        .nullable(),\n    }),\n    urlBase: Yup.string()\n      .test(\n        'leading-slash',\n        intl.formatMessage(messages.validationUrlBaseLeadingSlash),\n        (value) => !value || value.startsWith('/')\n      )\n      .test(\n        'trailing-slash',\n        intl.formatMessage(messages.validationUrlBaseTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n    jellyfinExternalUrl: Yup.string()\n      .nullable()\n      .test('valid-url', intl.formatMessage(messages.validationUrl), isValidURL)\n      .test(\n        'no-trailing-slash',\n        intl.formatMessage(messages.validationUrlTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n    jellyfinForgotPasswordUrl: Yup.string()\n      .nullable()\n      .test('valid-url', intl.formatMessage(messages.validationUrl), isValidURL)\n      .test(\n        'no-trailing-slash',\n        intl.formatMessage(messages.validationUrlTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n  });\n\n  const activeLibraries =\n    data?.libraries\n      .filter((library) => library.enabled)\n      .map((library) => library.id) ?? [];\n\n  const syncLibraries = async () => {\n    setIsSyncing(true);\n\n    const params: { sync: boolean; enable?: string } = {\n      sync: true,\n    };\n\n    if (activeLibraries.length > 0) {\n      params.enable = activeLibraries.join(',');\n    }\n\n    try {\n      await axios.get('/api/v1/settings/jellyfin/library', {\n        params,\n      });\n      setIsSyncing(false);\n      revalidate();\n    } catch (e) {\n      if (e?.response?.data?.message === 'SYNC_ERROR_GROUPED_FOLDERS') {\n        toasts.addToast(\n          intl.formatMessage(\n            messages.jellyfinSyncFailedAutomaticGroupedFolders\n          ),\n          {\n            autoDismiss: true,\n            appearance: 'warning',\n          }\n        );\n      } else if (e?.response?.data?.message === 'SYNC_ERROR_NO_LIBRARIES') {\n        toasts.addToast(\n          intl.formatMessage(messages.jellyfinSyncFailedNoLibrariesFound),\n          {\n            autoDismiss: true,\n            appearance: 'error',\n          }\n        );\n      } else {\n        toasts.addToast(\n          intl.formatMessage(messages.jellyfinSyncFailedGenericError),\n          {\n            autoDismiss: true,\n            appearance: 'error',\n          }\n        );\n      }\n      setIsSyncing(false);\n      revalidate();\n    }\n  };\n\n  const startScan = async () => {\n    await axios.post('/api/v1/settings/jellyfin/sync', {\n      start: true,\n    });\n    revalidateSync();\n  };\n\n  const cancelScan = async () => {\n    await axios.post('/api/v1/settings/jellyfin/sync', {\n      cancel: true,\n    });\n    revalidateSync();\n  };\n\n  const toggleLibrary = async (libraryId: string) => {\n    setIsSyncing(true);\n    if (activeLibraries.includes(libraryId)) {\n      const params: { enable?: string } = {};\n\n      if (activeLibraries.length > 1) {\n        params.enable = activeLibraries\n          .filter((id) => id !== libraryId)\n          .join(',');\n      }\n\n      await axios.get('/api/v1/settings/jellyfin/library', {\n        params,\n      });\n    } else {\n      await axios.get('/api/v1/settings/jellyfin/library', {\n        params: {\n          enable: [...activeLibraries, libraryId].join(','),\n        },\n      });\n    }\n    if (onComplete) {\n      onComplete();\n    }\n    setIsSyncing(false);\n    revalidate();\n  };\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  const mediaServerFormatValues = {\n    mediaServerName:\n      settings.currentSettings.mediaServerType === MediaServerType.JELLYFIN\n        ? 'Jellyfin'\n        : settings.currentSettings.mediaServerType === MediaServerType.EMBY\n          ? 'Emby'\n          : undefined,\n  };\n\n  return (\n    <>\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(\n            messages.jellyfinlibraries,\n            mediaServerFormatValues\n          )}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(\n            messages.jellyfinlibrariesDescription,\n            mediaServerFormatValues\n          )}\n        </p>\n      </div>\n      <div className=\"section\">\n        <Button onClick={() => syncLibraries()} disabled={isSyncing}>\n          <svg\n            className={`${isSyncing ? 'animate-spin' : ''} mr-1 h-5 w-5`}\n            fill=\"currentColor\"\n            viewBox=\"0 0 20 20\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n          >\n            <path\n              fillRule=\"evenodd\"\n              d=\"M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z\"\n              clipRule=\"evenodd\"\n            />\n          </svg>\n          {isSyncing\n            ? intl.formatMessage(messages.syncing)\n            : intl.formatMessage(messages.syncJellyfin)}\n        </Button>\n        <ul className=\"mt-6 grid grid-cols-1 gap-5 sm:grid-cols-2 sm:gap-6 lg:grid-cols-4\">\n          {data?.libraries.map((library) => (\n            <LibraryItem\n              name={library.name}\n              isEnabled={library.enabled}\n              key={`setting-library-${library.id}`}\n              onToggle={() => toggleLibrary(library.id)}\n            />\n          ))}\n        </ul>\n      </div>\n      <div className=\"mb-6 mt-10\">\n        <h3 className=\"heading\">\n          <FormattedMessage {...messages.manualscanJellyfin} />\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(\n            messages.manualscanDescriptionJellyfin,\n            mediaServerFormatValues\n          )}\n        </p>\n      </div>\n      <div className=\"section\">\n        <div className=\"rounded-md bg-gray-800 p-4\">\n          <div className=\"relative mb-6 h-8 w-full overflow-hidden rounded-full bg-gray-600\">\n            {dataSync?.running && (\n              <div\n                className=\"h-8 bg-indigo-600 transition-all duration-200 ease-in-out\"\n                style={{\n                  width: `${Math.round(\n                    (dataSync.progress / dataSync.total) * 100\n                  )}%`,\n                }}\n              />\n            )}\n            <div className=\"absolute inset-0 flex h-8 w-full items-center justify-center text-sm\">\n              <span>\n                {dataSync?.running\n                  ? `${dataSync.progress} of ${dataSync.total}`\n                  : 'Not running'}\n              </span>\n            </div>\n          </div>\n          <div className=\"flex w-full flex-col sm:flex-row\">\n            {dataSync?.running && (\n              <>\n                {dataSync.currentLibrary && (\n                  <div className=\"mb-2 mr-0 flex items-center sm:mb-0 sm:mr-2\">\n                    <Badge>\n                      <FormattedMessage\n                        {...messages.currentlibrary}\n                        values={{ name: dataSync.currentLibrary.name }}\n                      />\n                    </Badge>\n                  </div>\n                )}\n                <div className=\"flex items-center\">\n                  <Badge badgeType=\"warning\">\n                    <FormattedMessage\n                      {...messages.librariesRemaining}\n                      values={{\n                        count: dataSync.currentLibrary\n                          ? dataSync.libraries.slice(\n                              dataSync.libraries.findIndex(\n                                (library) =>\n                                  library.id === dataSync.currentLibrary?.id\n                              ) + 1\n                            ).length\n                          : 0,\n                      }}\n                    />\n                  </Badge>\n                </div>\n              </>\n            )}\n            <div className=\"flex-1 text-right\">\n              {!dataSync?.running && (\n                <Button buttonType=\"warning\" onClick={() => startScan()}>\n                  <svg\n                    className=\"mr-1 h-5 w-5\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    viewBox=\"0 0 24 24\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                  >\n                    <path\n                      strokeLinecap=\"round\"\n                      strokeLinejoin=\"round\"\n                      strokeWidth={2}\n                      d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n                    />\n                  </svg>\n                  <FormattedMessage {...messages.startscan} />\n                </Button>\n              )}\n\n              {dataSync?.running && (\n                <Button buttonType=\"danger\" onClick={() => cancelScan()}>\n                  <svg\n                    className=\"mr-1 h-5 w-5\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    viewBox=\"0 0 24 24\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                  >\n                    <path\n                      strokeLinecap=\"round\"\n                      strokeLinejoin=\"round\"\n                      strokeWidth={2}\n                      d=\"M6 18L18 6M6 6l12 12\"\n                    />\n                  </svg>\n                  <FormattedMessage {...messages.cancelscan} />\n                </Button>\n              )}\n            </div>\n          </div>\n        </div>\n      </div>\n      {isSetupSettings && (\n        <div className=\"text-sm text-gray-500\">\n          <span className=\"mr-2\">\n            <Badge>{intl.formatMessage(messages.tip)}</Badge>\n          </span>\n          {intl.formatMessage(messages.scanbackground)}\n        </div>\n      )}\n      <div className=\"mb-6 mt-10\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(\n            messages.jellyfinSettings,\n            mediaServerFormatValues\n          )}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(\n            messages.jellyfinSettingsDescription,\n            mediaServerFormatValues\n          )}\n        </p>\n      </div>\n      <Formik\n        initialValues={{\n          hostname: data?.ip,\n          port: data?.port ?? 8096,\n          useSsl: data?.useSsl,\n          urlBase: data?.urlBase || '',\n          jellyfinExternalUrl: data?.externalHostname || '',\n          jellyfinForgotPasswordUrl: data?.jellyfinForgotPasswordUrl || '',\n          apiKey: data?.apiKey,\n        }}\n        validationSchema={JellyfinSettingsSchema}\n        onSubmit={async (values) => {\n          try {\n            await axios.post('/api/v1/settings/jellyfin', {\n              ip: values.hostname,\n              port: Number(values.port),\n              useSsl: values.useSsl,\n              urlBase: values.urlBase,\n              externalHostname: values.jellyfinExternalUrl,\n              jellyfinForgotPasswordUrl: values.jellyfinForgotPasswordUrl,\n              apiKey: values.apiKey,\n            } as JellyfinSettings);\n\n            addToast(\n              intl.formatMessage(\n                messages.jellyfinSettingsSuccess,\n                mediaServerFormatValues\n              ),\n              {\n                autoDismiss: true,\n                appearance: 'success',\n              }\n            );\n          } catch (e) {\n            if (e?.response?.data?.message === ApiErrorCode.InvalidUrl) {\n              addToast(\n                intl.formatMessage(\n                  messages.invalidurlerror,\n                  mediaServerFormatValues\n                ),\n                {\n                  autoDismiss: true,\n                  appearance: 'error',\n                }\n              );\n            } else {\n              addToast(\n                intl.formatMessage(\n                  messages.jellyfinSettingsFailure,\n                  mediaServerFormatValues\n                ),\n                {\n                  autoDismiss: true,\n                  appearance: 'error',\n                }\n              );\n            }\n          } finally {\n            revalidate();\n          }\n        }}\n      >\n        {({\n          errors,\n          touched,\n          values,\n          setFieldValue,\n          handleSubmit,\n          isSubmitting,\n          isValid,\n        }) => {\n          return (\n            <form className=\"section\" onSubmit={handleSubmit}>\n              {!isSetupSettings && (\n                <>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"hostname\" className=\"text-label\">\n                      {intl.formatMessage(messages.hostname)}\n                      <span className=\"text-red-500\">*</span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-gray-100 sm:text-sm\">\n                          {values.useSsl ? 'https://' : 'http://'}\n                        </span>\n                        <Field\n                          type=\"text\"\n                          inputMode=\"url\"\n                          id=\"hostname\"\n                          name=\"hostname\"\n                          className=\"rounded-r-only\"\n                        />\n                      </div>\n                      {errors.hostname &&\n                        touched.hostname &&\n                        typeof errors.hostname === 'string' && (\n                          <div className=\"error\">{errors.hostname}</div>\n                        )}\n                    </div>\n                  </div>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"port\" className=\"text-label\">\n                      {intl.formatMessage(messages.port)}\n                      <span className=\"label-required\">*</span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <Field\n                        type=\"text\"\n                        inputMode=\"numeric\"\n                        id=\"port\"\n                        name=\"port\"\n                        className=\"short\"\n                      />\n                      {errors.port &&\n                        touched.port &&\n                        typeof errors.port === 'string' && (\n                          <div className=\"error\">{errors.port}</div>\n                        )}\n                    </div>\n                  </div>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"useSsl\" className=\"checkbox-label\">\n                      {intl.formatMessage(messages.enablessl)}\n                    </label>\n                    <div className=\"form-input-area\">\n                      <Field\n                        type=\"checkbox\"\n                        id=\"useSsl\"\n                        name=\"useSsl\"\n                        onChange={() => {\n                          setFieldValue('useSsl', !values.useSsl);\n                          setFieldValue('port', values.useSsl ? 8096 : 443);\n                        }}\n                      />\n                    </div>\n                  </div>\n                </>\n              )}\n              <div className=\"form-row\">\n                <label htmlFor=\"apiKey\" className=\"text-label\">\n                  {intl.formatMessage(messages.apiKey)}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <SensitiveInput\n                      as=\"field\"\n                      type=\"text\"\n                      inputMode=\"url\"\n                      id=\"apiKey\"\n                      name=\"apiKey\"\n                    />\n                  </div>\n                  {errors.apiKey && touched.apiKey && (\n                    <div className=\"error\">{errors.apiKey}</div>\n                  )}\n                </div>\n              </div>\n              {!isSetupSettings && (\n                <>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"urlBase\" className=\"text-label\">\n                      {intl.formatMessage(messages.urlBase)}\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <Field\n                          type=\"text\"\n                          inputMode=\"url\"\n                          id=\"urlBase\"\n                          name=\"urlBase\"\n                        />\n                      </div>\n                      {errors.urlBase &&\n                        touched.urlBase &&\n                        typeof errors.urlBase === 'string' && (\n                          <div className=\"error\">{errors.urlBase}</div>\n                        )}\n                    </div>\n                  </div>\n                </>\n              )}\n              <div className=\"form-row\">\n                <label htmlFor=\"jellyfinExternalUrl\" className=\"text-label\">\n                  {intl.formatMessage(messages.externalUrl)}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <Field\n                      type=\"text\"\n                      inputMode=\"url\"\n                      id=\"jellyfinExternalUrl\"\n                      name=\"jellyfinExternalUrl\"\n                    />\n                  </div>\n                  {errors.jellyfinExternalUrl &&\n                    touched.jellyfinExternalUrl && (\n                      <div className=\"error\">{errors.jellyfinExternalUrl}</div>\n                    )}\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label\n                  htmlFor=\"jellyfinForgotPasswordUrl\"\n                  className=\"text-label\"\n                >\n                  {intl.formatMessage(messages.jellyfinForgotPasswordUrl)}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <Field\n                      type=\"text\"\n                      inputMode=\"url\"\n                      id=\"jellyfinForgotPasswordUrl\"\n                      name=\"jellyfinForgotPasswordUrl\"\n                    />\n                  </div>\n                  {errors.jellyfinForgotPasswordUrl &&\n                    touched.jellyfinForgotPasswordUrl && (\n                      <div className=\"error\">\n                        {errors.jellyfinForgotPasswordUrl}\n                      </div>\n                    )}\n                </div>\n              </div>\n              <div\n                className={`actions ${isSetupSettings ? 'mt-0 border-0' : ''}`}\n              >\n                <div className=\"flex justify-end\">\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"primary\"\n                      type=\"submit\"\n                      disabled={isSubmitting || !isValid}\n                    >\n                      <ArrowDownOnSquareIcon />\n                      <span>\n                        {isSubmitting\n                          ? intl.formatMessage(globalMessages.saving)\n                          : intl.formatMessage(globalMessages.save)}\n                      </span>\n                    </Button>\n                  </span>\n                </div>\n              </div>\n            </form>\n          );\n        }}\n      </Formik>\n    </>\n  );\n};\n\nexport default SettingsJellyfin;\n"
  },
  {
    "path": "src/components/Settings/SettingsJobsCache/index.tsx",
    "content": "import Spinner from '@app/assets/spinner.svg';\nimport Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport Modal from '@app/components/Common/Modal';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport Table from '@app/components/Common/Table';\nimport useLocale from '@app/hooks/useLocale';\nimport useSettings from '@app/hooks/useSettings';\n\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { formatBytes } from '@app/utils/numberHelpers';\nimport { Transition } from '@headlessui/react';\nimport { PlayIcon, StopIcon, TrashIcon } from '@heroicons/react/24/outline';\nimport { PencilIcon } from '@heroicons/react/24/solid';\nimport { MediaServerType } from '@server/constants/server';\nimport type {\n  CacheItem,\n  CacheResponse,\n} from '@server/interfaces/api/settingsInterfaces';\nimport type { JobId } from '@server/lib/settings';\nimport axios from 'axios';\nimport cronstrue from 'cronstrue/i18n';\nimport { formatDuration, intervalToDuration } from 'date-fns';\nimport { Fragment, useReducer, useState } from 'react';\nimport type { MessageDescriptor } from 'react-intl';\nimport { FormattedRelativeTime, useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\nconst messages: { [messageName: string]: MessageDescriptor } = defineMessages(\n  'components.Settings.SettingsJobsCache',\n  {\n    jobsandcache: 'Jobs & Cache',\n    jobs: 'Jobs',\n    jobsDescription:\n      'Seerr performs certain maintenance tasks as regularly-scheduled jobs, but they can also be manually triggered below. Manually running a job will not alter its schedule.',\n    jobname: 'Job Name',\n    jobtype: 'Type',\n    nextexecution: 'Next Execution',\n    runnow: 'Run Now',\n    canceljob: 'Cancel Job',\n    jobstarted: '{jobname} started.',\n    jobcancelled: '{jobname} canceled.',\n    process: 'Process',\n    command: 'Command',\n    cache: 'Cache',\n    cacheDescription:\n      'Seerr caches requests to external API endpoints to optimize performance and avoid making unnecessary API calls.',\n    cacheflushed: '{cachename} cache flushed.',\n    cachename: 'Cache Name',\n    cachehits: 'Hits',\n    cachemisses: 'Misses',\n    cachekeys: 'Total Keys',\n    cacheksize: 'Key Size',\n    cachevsize: 'Value Size',\n    flushcache: 'Flush Cache',\n    dnsCache: 'DNS Cache',\n    dnsCacheDescription:\n      'Seerr caches DNS lookups to optimize performance and avoid making unnecessary API calls.',\n    dnscacheflushed: '{hostname} dns cache flushed.',\n    dnscachename: 'Hostname',\n    dnscacheactiveaddress: 'Active Address',\n    dnscachehits: 'Hits',\n    dnscachemisses: 'Misses',\n    dnscacheage: 'Age',\n    flushdnscache: 'Flush DNS Cache',\n    dnsCacheGlobalStats: 'Global DNS Cache Stats',\n    dnsCacheGlobalStatsDescription:\n      'These stats are aggregated across all DNS cache entries.',\n    dnsNoCacheEntries: 'No DNS lookups have been cached yet.',\n    size: 'Size',\n    hits: 'Hits',\n    misses: 'Misses',\n    failures: 'Failures',\n    ipv4Fallbacks: 'IPv4 Fallbacks',\n    hitRate: 'Hit Rate',\n    unknownJob: 'Unknown Job',\n    'plex-recently-added-scan': 'Plex Recently Added Scan',\n    'plex-full-scan': 'Plex Full Library Scan',\n    'plex-watchlist-sync': 'Plex Watchlist Sync',\n    'plex-refresh-token': 'Plex Refresh Token',\n    'jellyfin-full-scan': 'Jellyfin Full Library Scan',\n    'jellyfin-recently-added-scan': 'Jellyfin Recently Added Scan',\n    'availability-sync': 'Media Availability Sync',\n    'radarr-scan': 'Radarr Scan',\n    'sonarr-scan': 'Sonarr Scan',\n    'download-sync': 'Download Sync',\n    'download-sync-reset': 'Download Sync Reset',\n    'image-cache-cleanup': 'Image Cache Cleanup',\n    'process-blocklisted-tags': 'Process Blocklisted Tags',\n    editJobSchedule: 'Modify Job',\n    jobScheduleEditSaved: 'Job edited successfully!',\n    jobScheduleEditFailed: 'Something went wrong while saving the job.',\n    editJobScheduleCurrent: 'Current Frequency',\n    editJobSchedulePrompt: 'New Frequency',\n    editJobScheduleSelectorDays:\n      'Every {jobScheduleDays, plural, one {day} other {{jobScheduleDays} days}}',\n    editJobScheduleSelectorHours:\n      'Every {jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}',\n    editJobScheduleSelectorMinutes:\n      'Every {jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}',\n    editJobScheduleSelectorSeconds:\n      'Every {jobScheduleSeconds, plural, one {second} other {{jobScheduleSeconds} seconds}}',\n    imagecache: 'Image Cache',\n    imagecacheDescription:\n      'When enabled in settings, Seerr will proxy and cache images from pre-configured external sources. Cached images are saved into your config folder. You can find the files in <code>{appDataPath}/cache/images</code>.',\n    imagecachecount: 'Images Cached',\n    imagecachesize: 'Total Cache Size',\n    usersavatars: \"Users' Avatars\",\n  }\n);\n\ninterface Job {\n  id: JobId;\n  name: string;\n  type: 'process' | 'command';\n  interval: 'seconds' | 'minutes' | 'hours' | 'days' | 'fixed';\n  cronSchedule: string;\n  nextExecutionTime: string;\n  running: boolean;\n}\n\ntype JobModalState = {\n  isOpen?: boolean;\n  job?: Job;\n  scheduleDays: number;\n  scheduleHours: number;\n  scheduleMinutes: number;\n  scheduleSeconds: number;\n};\n\ntype JobModalAction =\n  | {\n      type: 'set';\n      days?: number;\n      hours?: number;\n      minutes?: number;\n      seconds?: number;\n    }\n  | {\n      type: 'close';\n    }\n  | { type: 'open'; job?: Job };\n\nconst jobModalReducer = (\n  state: JobModalState,\n  action: JobModalAction\n): JobModalState => {\n  switch (action.type) {\n    case 'close':\n      return {\n        ...state,\n        isOpen: false,\n      };\n\n    case 'open':\n      return {\n        isOpen: true,\n        job: action.job,\n        scheduleDays: 1,\n        scheduleHours: 1,\n        scheduleMinutes: 5,\n        scheduleSeconds: 30,\n      };\n\n    case 'set':\n      return {\n        ...state,\n        scheduleDays: action.days ?? state.scheduleDays,\n        scheduleHours: action.hours ?? state.scheduleHours,\n        scheduleMinutes: action.minutes ?? state.scheduleMinutes,\n        scheduleSeconds: action.seconds ?? state.scheduleSeconds,\n      };\n  }\n};\n\nconst SettingsJobs = () => {\n  const intl = useIntl();\n  const { locale } = useLocale();\n  const { addToast } = useToasts();\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<Job[]>('/api/v1/settings/jobs', {\n    refreshInterval: 5000,\n  });\n  const { data: appData } = useSWR('/api/v1/status/appdata');\n  const { data: cacheData, mutate: cacheRevalidate } = useSWR<CacheResponse>(\n    '/api/v1/settings/cache',\n    {\n      refreshInterval: 10000,\n    }\n  );\n\n  const [jobModalState, dispatch] = useReducer(jobModalReducer, {\n    isOpen: false,\n    scheduleDays: 1,\n    scheduleHours: 1,\n    scheduleMinutes: 5,\n    scheduleSeconds: 30,\n  });\n  const [isSaving, setIsSaving] = useState(false);\n  const settings = useSettings();\n\n  if (settings.currentSettings.mediaServerType === MediaServerType.EMBY) {\n    messages['jellyfin-recently-added-scan'] = {\n      id: 'jellyfin-recently-added-scan',\n      defaultMessage: 'Emby Recently Added Scan',\n    };\n  }\n\n  if (settings.currentSettings.mediaServerType === MediaServerType.EMBY) {\n    messages['jellyfin-full-scan'] = {\n      id: 'jellyfin-full-scan',\n      defaultMessage: 'Emby Full Library Scan',\n    };\n  }\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  const runJob = async (job: Job) => {\n    await axios.post(`/api/v1/settings/jobs/${job.id}/run`);\n    addToast(\n      intl.formatMessage(messages.jobstarted, {\n        jobname: intl.formatMessage(messages[job.id] ?? messages.unknownJob),\n      }),\n      {\n        appearance: 'success',\n        autoDismiss: true,\n      }\n    );\n    revalidate();\n  };\n\n  const cancelJob = async (job: Job) => {\n    await axios.post(`/api/v1/settings/jobs/${job.id}/cancel`);\n    addToast(\n      intl.formatMessage(messages.jobcancelled, {\n        jobname: intl.formatMessage(messages[job.id] ?? messages.unknownJob),\n      }),\n      {\n        appearance: 'error',\n        autoDismiss: true,\n      }\n    );\n    revalidate();\n  };\n\n  const flushCache = async (cache: CacheItem) => {\n    await axios.post(`/api/v1/settings/cache/${cache.id}/flush`);\n    addToast(\n      intl.formatMessage(messages.cacheflushed, { cachename: cache.name }),\n      {\n        appearance: 'success',\n        autoDismiss: true,\n      }\n    );\n    cacheRevalidate();\n  };\n\n  const flushDnsCache = async (hostname: string) => {\n    await axios.post(`/api/v1/settings/cache/dns/${hostname}/flush`);\n    addToast(\n      intl.formatMessage(messages.dnscacheflushed, { hostname: hostname }),\n      {\n        appearance: 'success',\n        autoDismiss: true,\n      }\n    );\n    cacheRevalidate();\n  };\n\n  const scheduleJob = async () => {\n    const jobScheduleCron = ['0', '0', '*', '*', '*', '*'];\n\n    try {\n      if (jobModalState.job?.interval === 'seconds') {\n        jobScheduleCron.splice(0, 2, `*/${jobModalState.scheduleSeconds}`, '*');\n      } else if (jobModalState.job?.interval === 'minutes') {\n        jobScheduleCron[1] = `*/${jobModalState.scheduleMinutes}`;\n      } else if (jobModalState.job?.interval === 'hours') {\n        jobScheduleCron[2] = `*/${jobModalState.scheduleHours}`;\n      } else if (jobModalState.job?.interval === 'days') {\n        jobScheduleCron[2] = '1';\n        jobScheduleCron[3] = `*/${jobModalState.scheduleDays}`;\n      } else {\n        // jobs with interval: fixed should not be editable\n        throw new Error();\n      }\n\n      setIsSaving(true);\n      await axios.post(\n        `/api/v1/settings/jobs/${jobModalState.job.id}/schedule`,\n        {\n          schedule: jobScheduleCron.join(' '),\n        }\n      );\n\n      addToast(intl.formatMessage(messages.jobScheduleEditSaved), {\n        appearance: 'success',\n        autoDismiss: true,\n      });\n\n      dispatch({ type: 'close' });\n      revalidate();\n    } catch {\n      addToast(intl.formatMessage(messages.jobScheduleEditFailed), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      setIsSaving(false);\n    }\n  };\n\n  const formatAge = (milliseconds: number): string => {\n    const duration = intervalToDuration({\n      start: 0,\n      end: milliseconds,\n    });\n\n    return formatDuration(duration, {\n      format: ['minutes', 'seconds'],\n      zero: false,\n    });\n  };\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.jobsandcache),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n      <Transition\n        as={Fragment}\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={jobModalState.isOpen}\n      >\n        <Modal\n          title={intl.formatMessage(messages.editJobSchedule)}\n          okText={\n            isSaving\n              ? intl.formatMessage(globalMessages.saving)\n              : intl.formatMessage(globalMessages.save)\n          }\n          onCancel={() => dispatch({ type: 'close' })}\n          okDisabled={isSaving}\n          onOk={() => scheduleJob()}\n        >\n          <div className=\"section\">\n            <form className=\"mb-6\">\n              <div className=\"form-row\">\n                <label className=\"text-label\">\n                  {intl.formatMessage(messages.editJobScheduleCurrent)}\n                </label>\n                <div className=\"form-input-area mb-1 mt-2\">\n                  <div>\n                    {jobModalState.job &&\n                      cronstrue.toString(jobModalState.job.cronSchedule, {\n                        locale,\n                      })}\n                  </div>\n                  <div className=\"text-sm text-gray-500\">\n                    {jobModalState.job?.cronSchedule}\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"jobSchedule\" className=\"text-label\">\n                  {intl.formatMessage(messages.editJobSchedulePrompt)}\n                </label>\n                <div className=\"form-input-area\">\n                  {jobModalState.job?.interval === 'seconds' ? (\n                    <select\n                      name=\"jobScheduleSeconds\"\n                      className=\"inline\"\n                      value={jobModalState.scheduleSeconds}\n                      onChange={(e) =>\n                        dispatch({\n                          type: 'set',\n                          seconds: Number(e.target.value),\n                        })\n                      }\n                    >\n                      {[30, 45, 60].map((v) => (\n                        <option value={v} key={`jobScheduleSeconds-${v}`}>\n                          {intl.formatMessage(\n                            messages.editJobScheduleSelectorSeconds,\n                            {\n                              jobScheduleSeconds: v,\n                            }\n                          )}\n                        </option>\n                      ))}\n                    </select>\n                  ) : jobModalState.job?.interval === 'minutes' ? (\n                    <select\n                      name=\"jobScheduleMinutes\"\n                      className=\"inline\"\n                      value={jobModalState.scheduleMinutes}\n                      onChange={(e) =>\n                        dispatch({\n                          type: 'set',\n                          minutes: Number(e.target.value),\n                        })\n                      }\n                    >\n                      {[5, 10, 15, 20, 30, 60].map((v) => (\n                        <option value={v} key={`jobScheduleMinutes-${v}`}>\n                          {intl.formatMessage(\n                            messages.editJobScheduleSelectorMinutes,\n                            {\n                              jobScheduleMinutes: v,\n                            }\n                          )}\n                        </option>\n                      ))}\n                    </select>\n                  ) : jobModalState.job?.interval === 'days' ? (\n                    <select\n                      name=\"jobScheduleDays\"\n                      className=\"inline\"\n                      value={jobModalState.scheduleDays}\n                      onChange={(e) =>\n                        dispatch({\n                          type: 'set',\n                          days: Number(e.target.value),\n                        })\n                      }\n                    >\n                      {[1, 2, 3, 4, 5, 6, 7, 10, 14, 21].map((v) => (\n                        <option value={v} key={`jobScheduleDays-${v}`}>\n                          {intl.formatMessage(\n                            messages.editJobScheduleSelectorDays,\n                            {\n                              jobScheduleDays: v,\n                            }\n                          )}\n                        </option>\n                      ))}\n                    </select>\n                  ) : (\n                    <select\n                      name=\"jobScheduleHours\"\n                      className=\"inline\"\n                      value={jobModalState.scheduleHours}\n                      onChange={(e) =>\n                        dispatch({\n                          type: 'set',\n                          hours: Number(e.target.value),\n                        })\n                      }\n                    >\n                      {[1, 2, 3, 4, 6, 8, 12, 24, 48, 72].map((v) => (\n                        <option value={v} key={`jobScheduleHours-${v}`}>\n                          {intl.formatMessage(\n                            messages.editJobScheduleSelectorHours,\n                            {\n                              jobScheduleHours: v,\n                            }\n                          )}\n                        </option>\n                      ))}\n                    </select>\n                  )}\n                </div>\n              </div>\n            </form>\n          </div>\n        </Modal>\n      </Transition>\n\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">{intl.formatMessage(messages.jobs)}</h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.jobsDescription)}\n        </p>\n      </div>\n      <div className=\"section\">\n        <Table>\n          <thead>\n            <tr>\n              <Table.TH>{intl.formatMessage(messages.jobname)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.jobtype)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.nextexecution)}</Table.TH>\n              <Table.TH />\n            </tr>\n          </thead>\n          <Table.TBody>\n            {data?.map((job) => (\n              <tr key={`job-list-${job.id}`}>\n                <Table.TD>\n                  <div className=\"flex items-center text-sm leading-5 text-white\">\n                    <span>\n                      {intl.formatMessage(\n                        messages[job.id] ?? messages.unknownJob\n                      )}\n                    </span>\n                    {job.running && <Spinner className=\"ml-2 h-5 w-5\" />}\n                  </div>\n                </Table.TD>\n                <Table.TD>\n                  <Badge\n                    badgeType={job.type === 'process' ? 'primary' : 'warning'}\n                    className=\"uppercase\"\n                  >\n                    {job.type === 'process'\n                      ? intl.formatMessage(messages.process)\n                      : intl.formatMessage(messages.command)}\n                  </Badge>\n                </Table.TD>\n                <Table.TD>\n                  <div className=\"text-sm leading-5 text-white\">\n                    <FormattedRelativeTime\n                      value={Math.floor(\n                        (new Date(job.nextExecutionTime).getTime() -\n                          Date.now()) /\n                          1000\n                      )}\n                      updateIntervalInSeconds={1}\n                      numeric=\"auto\"\n                    />\n                  </div>\n                </Table.TD>\n                <Table.TD alignText=\"right\">\n                  {job.interval !== 'fixed' && (\n                    <Button\n                      className=\"mr-2\"\n                      buttonType=\"warning\"\n                      onClick={() => dispatch({ type: 'open', job })}\n                    >\n                      <PencilIcon />\n                      <span>{intl.formatMessage(globalMessages.edit)}</span>\n                    </Button>\n                  )}\n                  {job.running ? (\n                    <Button buttonType=\"danger\" onClick={() => cancelJob(job)}>\n                      <StopIcon />\n                      <span>{intl.formatMessage(messages.canceljob)}</span>\n                    </Button>\n                  ) : (\n                    <Button buttonType=\"primary\" onClick={() => runJob(job)}>\n                      <PlayIcon />\n                      <span>{intl.formatMessage(messages.runnow)}</span>\n                    </Button>\n                  )}\n                </Table.TD>\n              </tr>\n            ))}\n          </Table.TBody>\n        </Table>\n      </div>\n      <div>\n        <h3 className=\"heading\">{intl.formatMessage(messages.cache)}</h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.cacheDescription)}\n        </p>\n      </div>\n      <div className=\"section\">\n        <Table>\n          <thead>\n            <tr>\n              <Table.TH>{intl.formatMessage(messages.cachename)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.cachehits)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.cachemisses)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.cachekeys)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.cacheksize)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.cachevsize)}</Table.TH>\n              <Table.TH />\n            </tr>\n          </thead>\n          <Table.TBody>\n            {cacheData?.apiCaches\n              ?.filter(\n                (cache) =>\n                  !(\n                    settings.currentSettings.mediaServerType !==\n                      MediaServerType.PLEX && cache.id === 'plexguid'\n                  )\n              )\n              .map((cache) => (\n                <tr key={`cache-list-${cache.id}`}>\n                  <Table.TD>{cache.name}</Table.TD>\n                  <Table.TD>{intl.formatNumber(cache.stats.hits)}</Table.TD>\n                  <Table.TD>{intl.formatNumber(cache.stats.misses)}</Table.TD>\n                  <Table.TD>{intl.formatNumber(cache.stats.keys)}</Table.TD>\n                  <Table.TD>{formatBytes(cache.stats.ksize)}</Table.TD>\n                  <Table.TD>{formatBytes(cache.stats.vsize)}</Table.TD>\n                  <Table.TD alignText=\"right\">\n                    <Button\n                      buttonType=\"danger\"\n                      onClick={() => flushCache(cache)}\n                    >\n                      <TrashIcon />\n                      <span>{intl.formatMessage(messages.flushcache)}</span>\n                    </Button>\n                  </Table.TD>\n                </tr>\n              ))}\n          </Table.TBody>\n        </Table>\n      </div>\n      {cacheData?.dnsCache != null && (\n        <>\n          <div>\n            <h3 className=\"heading\">{intl.formatMessage(messages.dnsCache)}</h3>\n            <p className=\"description\">\n              {intl.formatMessage(messages.dnsCacheDescription)}\n            </p>\n          </div>\n          <div className=\"section\">\n            <Table>\n              <thead>\n                <tr>\n                  <Table.TH>\n                    {intl.formatMessage(messages.dnscachename)}\n                  </Table.TH>\n                  <Table.TH>\n                    {intl.formatMessage(messages.dnscacheactiveaddress)}\n                  </Table.TH>\n                  <Table.TH>\n                    {intl.formatMessage(messages.dnscachehits)}\n                  </Table.TH>\n                  <Table.TH>\n                    {intl.formatMessage(messages.dnscachemisses)}\n                  </Table.TH>\n                  <Table.TH>\n                    {intl.formatMessage(messages.dnscacheage)}\n                  </Table.TH>\n                  <Table.TH />\n                </tr>\n              </thead>\n              <Table.TBody>\n                {(() => {\n                  if (!cacheData) {\n                    return (\n                      <tr>\n                        <Table.TD colSpan={6} alignText=\"center\">\n                          <LoadingSpinner />\n                        </Table.TD>\n                      </tr>\n                    );\n                  }\n\n                  const entries = Object.entries(\n                    cacheData.dnsCache?.entries ?? {}\n                  );\n\n                  if (entries.length === 0) {\n                    return (\n                      <tr>\n                        <Table.TD colSpan={6} alignText=\"center\">\n                          {intl.formatMessage(messages.dnsNoCacheEntries)}\n                        </Table.TD>\n                      </tr>\n                    );\n                  }\n\n                  return entries.map(([hostname, data]) => (\n                    <tr key={`cache-list-${hostname}`}>\n                      <Table.TD>{hostname}</Table.TD>\n                      <Table.TD>{data.activeAddress}</Table.TD>\n                      <Table.TD>{intl.formatNumber(data.hits)}</Table.TD>\n                      <Table.TD>{intl.formatNumber(data.misses)}</Table.TD>\n                      <Table.TD>{formatAge(data.age)}</Table.TD>\n                      <Table.TD alignText=\"right\">\n                        <Button\n                          buttonType=\"danger\"\n                          onClick={() => flushDnsCache(hostname)}\n                        >\n                          <TrashIcon />\n                          <span>\n                            {intl.formatMessage(messages.flushdnscache)}\n                          </span>\n                        </Button>\n                      </Table.TD>\n                    </tr>\n                  ));\n                })()}\n              </Table.TBody>\n            </Table>\n          </div>\n          <div>\n            <h3 className=\"heading\">\n              {intl.formatMessage(messages.dnsCacheGlobalStats)}\n            </h3>\n            <p className=\"description\">\n              {intl.formatMessage(messages.dnsCacheGlobalStatsDescription)}\n            </p>\n          </div>\n          <div className=\"section\">\n            {!cacheData ? (\n              <LoadingSpinner />\n            ) : (\n              <Table>\n                <thead>\n                  <tr>\n                    {Object.entries(cacheData.dnsCache?.stats ?? {})\n                      .filter(([statName]) => statName !== 'maxSize')\n                      .map(([statName]) => (\n                        <Table.TH key={`dns-stat-header-${statName}`}>\n                          {messages[statName]\n                            ? intl.formatMessage(messages[statName])\n                            : statName}\n                        </Table.TH>\n                      ))}\n                  </tr>\n                </thead>\n                <Table.TBody>\n                  <tr>\n                    {Object.entries(cacheData.dnsCache?.stats ?? {})\n                      .filter(([statName]) => statName !== 'maxSize')\n                      .map(([statName, statValue]) => (\n                        <Table.TD key={`dns-stat-${statName}`}>\n                          {statName === 'hitRate'\n                            ? intl.formatNumber(statValue, {\n                                style: 'percent',\n                                maximumFractionDigits: 2,\n                              })\n                            : intl.formatNumber(statValue)}\n                        </Table.TD>\n                      ))}\n                  </tr>\n                </Table.TBody>\n              </Table>\n            )}\n          </div>\n        </>\n      )}\n      <div className=\"break-words\">\n        <h3 className=\"heading\">{intl.formatMessage(messages.imagecache)}</h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.imagecacheDescription, {\n            code: (msg: React.ReactNode) => (\n              <code className=\"bg-gray-800/50\">{msg}</code>\n            ),\n            appDataPath: appData ? appData.appDataPath : '/app/config',\n          })}\n        </p>\n      </div>\n      <div className=\"section\">\n        <Table>\n          <thead>\n            <tr>\n              <Table.TH>{intl.formatMessage(messages.cachename)}</Table.TH>\n              <Table.TH>\n                {intl.formatMessage(messages.imagecachecount)}\n              </Table.TH>\n              <Table.TH>{intl.formatMessage(messages.imagecachesize)}</Table.TH>\n            </tr>\n          </thead>\n          <Table.TBody>\n            <tr>\n              <Table.TD>The Movie Database (tmdb)</Table.TD>\n              <Table.TD>\n                {intl.formatNumber(cacheData?.imageCache.tmdb.imageCount ?? 0)}\n              </Table.TD>\n              <Table.TD>\n                {formatBytes(cacheData?.imageCache.tmdb.size ?? 0)}\n              </Table.TD>\n            </tr>\n            <tr>\n              <Table.TD>\n                {intl.formatMessage(messages.usersavatars)} (avatar)\n              </Table.TD>\n              <Table.TD>\n                {intl.formatNumber(\n                  cacheData?.imageCache.avatar.imageCount ?? 0\n                )}\n              </Table.TD>\n              <Table.TD>\n                {formatBytes(cacheData?.imageCache.avatar.size ?? 0)}\n              </Table.TD>\n            </tr>\n          </Table.TBody>\n        </Table>\n      </div>\n    </>\n  );\n};\n\nexport default SettingsJobs;\n"
  },
  {
    "path": "src/components/Settings/SettingsLayout.tsx",
    "content": "import PageTitle from '@app/components/Common/PageTitle';\nimport type { SettingsRoute } from '@app/components/Common/SettingsTabs';\nimport SettingsTabs from '@app/components/Common/SettingsTabs';\nimport useSettings from '@app/hooks/useSettings';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { MediaServerType } from '@server/constants/server';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Settings', {\n  menuGeneralSettings: 'General',\n  menuUsers: 'Users',\n  menuPlexSettings: 'Plex',\n  menuJellyfinSettings: '{mediaServerName}',\n  menuServices: 'Services',\n  menuNetwork: 'Network',\n  menuNotifications: 'Notifications',\n  menuLogs: 'Logs',\n  menuJobs: 'Jobs & Cache',\n  menuAbout: 'About',\n  menuMetadataProviders: 'Metadata Providers',\n});\n\ntype SettingsLayoutProps = {\n  children: React.ReactNode;\n};\n\nconst SettingsLayout = ({ children }: SettingsLayoutProps) => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const settingsRoutes: SettingsRoute[] = [\n    {\n      text: intl.formatMessage(messages.menuGeneralSettings),\n      route: '/settings/main',\n      regex: /^\\/settings(\\/main)?$/,\n    },\n    {\n      text: intl.formatMessage(messages.menuUsers),\n      route: '/settings/users',\n      regex: /^\\/settings\\/users/,\n    },\n    settings.currentSettings.mediaServerType === MediaServerType.PLEX\n      ? {\n          text: intl.formatMessage(messages.menuPlexSettings),\n          route: '/settings/plex',\n          regex: /^\\/settings\\/plex/,\n        }\n      : {\n          text: getAvailableMediaServerName(),\n          route: '/settings/jellyfin',\n          regex: /^\\/settings\\/jellyfin/,\n        },\n    {\n      text: intl.formatMessage(messages.menuServices),\n      route: '/settings/services',\n      regex: /^\\/settings\\/services/,\n    },\n    {\n      text: intl.formatMessage(messages.menuNetwork),\n      route: '/settings/network',\n      regex: /^\\/settings\\/network/,\n    },\n    {\n      text: intl.formatMessage(messages.menuMetadataProviders),\n      route: '/settings/metadata',\n      regex: /^\\/settings\\/metadata/,\n    },\n    {\n      text: intl.formatMessage(messages.menuNotifications),\n      route: '/settings/notifications/email',\n      regex: /^\\/settings\\/notifications/,\n    },\n    {\n      text: intl.formatMessage(messages.menuLogs),\n      route: '/settings/logs',\n      regex: /^\\/settings\\/logs/,\n    },\n    {\n      text: intl.formatMessage(messages.menuJobs),\n      route: '/settings/jobs',\n      regex: /^\\/settings\\/jobs/,\n    },\n    {\n      text: intl.formatMessage(messages.menuAbout),\n      route: '/settings/about',\n      regex: /^\\/settings\\/about/,\n    },\n  ];\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(globalMessages.settings)} />\n      <div className=\"mt-6\">\n        <SettingsTabs settingsRoutes={settingsRoutes} />\n      </div>\n      <div className=\"mt-10 text-white\">{children}</div>\n    </>\n  );\n  function getAvailableMediaServerName() {\n    return intl.formatMessage(messages.menuJellyfinSettings, {\n      mediaServerName:\n        settings.currentSettings.mediaServerType === MediaServerType.JELLYFIN\n          ? 'Jellyfin'\n          : settings.currentSettings.mediaServerType === MediaServerType.EMBY\n            ? 'Emby'\n            : undefined,\n    });\n  }\n};\n\nexport default SettingsLayout;\n"
  },
  {
    "path": "src/components/Settings/SettingsLogs/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport Modal from '@app/components/Common/Modal';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport Table from '@app/components/Common/Table';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport useDebouncedState from '@app/hooks/useDebouncedState';\nimport { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport {\n  ChevronLeftIcon,\n  ChevronRightIcon,\n  ClipboardDocumentIcon,\n  DocumentMagnifyingGlassIcon,\n  FunnelIcon,\n  MagnifyingGlassIcon,\n  PauseIcon,\n  PlayIcon,\n} from '@heroicons/react/24/solid';\nimport type {\n  LogMessage,\n  LogsResultsResponse,\n} from '@server/interfaces/api/settingsInterfaces';\nimport copy from 'copy-to-clipboard';\nimport { useRouter } from 'next/router';\nimport { Fragment, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Settings.SettingsLogs', {\n  logs: 'Logs',\n  logsDescription:\n    'You can also view these logs directly via <code>stdout</code>, or in <code>{appDataPath}/logs/seerr.log</code>.',\n  time: 'Timestamp',\n  level: 'Severity',\n  label: 'Label',\n  message: 'Message',\n  filterDebug: 'Debug',\n  filterInfo: 'Info',\n  filterWarn: 'Warning',\n  filterError: 'Error',\n  showall: 'Show All Logs',\n  pauseLogs: 'Pause',\n  resumeLogs: 'Resume',\n  copyToClipboard: 'Copy to Clipboard',\n  logDetails: 'Log Details',\n  extraData: 'Additional Data',\n  copiedLogMessage: 'Copied log message to clipboard.',\n  viewdetails: 'View Details',\n});\n\ntype Filter = 'debug' | 'info' | 'warn' | 'error';\n\nconst SettingsLogs = () => {\n  const router = useRouter();\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const [currentFilter, setCurrentFilter] = useState<Filter>('debug');\n  const [currentPageSize, setCurrentPageSize] = useState(25);\n  const [searchFilter, debouncedSearchFilter, setSearchFilter] =\n    useDebouncedState('');\n  const [refreshInterval, setRefreshInterval] = useState(5000);\n  const [activeLog, setActiveLog] = useState<{\n    isOpen: boolean;\n    log?: LogMessage;\n  }>({ isOpen: false });\n\n  const page = router.query.page ? Number(router.query.page) : 1;\n  const pageIndex = page - 1;\n  const updateQueryParams = useUpdateQueryParams({ page: page.toString() });\n\n  const toggleLogs = () => {\n    setRefreshInterval(refreshInterval === 5000 ? 0 : 5000);\n  };\n\n  const { data, error } = useSWR<LogsResultsResponse>(\n    `/api/v1/settings/logs?take=${currentPageSize}&skip=${\n      pageIndex * currentPageSize\n    }&filter=${currentFilter}${\n      debouncedSearchFilter ? `&search=${debouncedSearchFilter}` : ''\n    }`,\n    {\n      refreshInterval: refreshInterval,\n      revalidateOnFocus: false,\n    }\n  );\n\n  const { data: appData } = useSWR('/api/v1/status/appdata');\n\n  useEffect(() => {\n    const filterString = window.localStorage.getItem('logs-display-settings');\n\n    if (filterString) {\n      const filterSettings = JSON.parse(filterString);\n\n      setCurrentFilter(filterSettings.currentFilter);\n      setCurrentPageSize(filterSettings.currentPageSize);\n    }\n  }, []);\n\n  useEffect(() => {\n    window.localStorage.setItem(\n      'logs-display-settings',\n      JSON.stringify({\n        currentFilter,\n        currentPageSize,\n      })\n    );\n  }, [currentFilter, currentPageSize]);\n\n  const copyLogString = (log: LogMessage): void => {\n    copy(\n      `${log.timestamp} [${log.level}]${log.label ? `[${log.label}]` : ''}: ${\n        log.message\n      }${log.data ? `${JSON.stringify(log.data)}` : ''}`\n    );\n    addToast(intl.formatMessage(messages.copiedLogMessage), {\n      appearance: 'success',\n      autoDismiss: true,\n    });\n  };\n\n  // check if there's no data and no errors in the table\n  // so as to show a spinner inside the table and not refresh the whole component\n  if (!data && error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const hasNextPage = data?.pageInfo.pages ?? 0 > pageIndex + 1;\n  const hasPrevPage = pageIndex > 0;\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.logs),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n      <Transition\n        as={Fragment}\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        appear\n        show={activeLog.isOpen}\n      >\n        <Modal\n          title={intl.formatMessage(messages.logDetails)}\n          onCancel={() => setActiveLog({ log: activeLog.log, isOpen: false })}\n          cancelText={intl.formatMessage(globalMessages.close)}\n          onOk={() =>\n            activeLog.log ? copyLogString(activeLog.log) : undefined\n          }\n          okText={intl.formatMessage(messages.copyToClipboard)}\n          okButtonType=\"primary\"\n        >\n          {activeLog && (\n            <>\n              <div className=\"form-row\">\n                <div className=\"text-label\">\n                  {intl.formatMessage(messages.time)}\n                </div>\n                <div className=\"mb-1 text-sm font-medium leading-5 text-gray-400 sm:mt-2\">\n                  <div className=\"flex max-w-lg items-center\">\n                    {intl.formatDate(activeLog.log?.timestamp, {\n                      year: 'numeric',\n                      month: 'short',\n                      day: '2-digit',\n                      hour: 'numeric',\n                      minute: 'numeric',\n                      second: 'numeric',\n                    })}\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <div className=\"text-label\">\n                  {intl.formatMessage(messages.level)}\n                </div>\n                <div className=\"mb-1 text-sm font-medium leading-5 text-gray-400 sm:mt-2\">\n                  <div className=\"flex max-w-lg items-center\">\n                    <Badge\n                      badgeType={\n                        activeLog.log?.level === 'error'\n                          ? 'danger'\n                          : activeLog.log?.level === 'warn'\n                            ? 'warning'\n                            : activeLog.log?.level === 'info'\n                              ? 'success'\n                              : 'default'\n                      }\n                    >\n                      {activeLog.log?.level.toUpperCase()}\n                    </Badge>\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <div className=\"text-label\">\n                  {intl.formatMessage(messages.label)}\n                </div>\n                <div className=\"mb-1 text-sm font-medium leading-5 text-gray-400 sm:mt-2\">\n                  <div className=\"flex max-w-lg items-center\">\n                    {activeLog.log?.label}\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <div className=\"text-label\">\n                  {intl.formatMessage(messages.message)}\n                </div>\n                <div className=\"col-span-2 mb-1 text-sm font-medium leading-5 text-gray-400 sm:mt-2\">\n                  <div className=\"flex max-w-lg items-center\">\n                    {activeLog.log?.message}\n                  </div>\n                </div>\n              </div>\n              {activeLog.log?.data && (\n                <div className=\"form-row\">\n                  <div className=\"text-label\">\n                    {intl.formatMessage(messages.extraData)}\n                  </div>\n                  <div className=\"col-span-2 mb-1 text-sm font-medium leading-5 text-gray-400 sm:mt-2\">\n                    <code className=\"block max-h-64 w-full overflow-auto whitespace-pre bg-gray-800 px-6 py-4 ring-1 ring-gray-700\">\n                      {JSON.stringify(activeLog.log?.data, null, ' ')}\n                    </code>\n                  </div>\n                </div>\n              )}\n            </>\n          )}\n        </Modal>\n      </Transition>\n      <div className=\"mb-2\">\n        <h3 className=\"heading\">{intl.formatMessage(messages.logs)}</h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.logsDescription, {\n            code: (msg: React.ReactNode) => (\n              <code className=\"whitespace-normal break-words bg-gray-800/50\">\n                {msg}\n              </code>\n            ),\n            appDataPath: appData ? appData.appDataPath : '/app/config',\n          })}\n        </p>\n        <div className=\"mt-2 flex flex-grow flex-col sm:flex-grow-0 sm:flex-row sm:justify-end\">\n          <div className=\"mb-2 flex flex-grow sm:mb-0 sm:mr-2 md:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n              <MagnifyingGlassIcon className=\"h-6 w-6\" />\n            </span>\n            <input\n              type=\"text\"\n              className=\"rounded-r-only\"\n              value={searchFilter}\n              onChange={(e) => setSearchFilter(e.target.value as string)}\n            />\n          </div>\n          <div className=\"mb-2 flex flex-1 flex-row justify-between sm:mb-0 sm:flex-none\">\n            <Button\n              className=\"mr-2 flex flex-grow\"\n              buttonType={refreshInterval ? 'default' : 'primary'}\n              onClick={() => toggleLogs()}\n            >\n              {refreshInterval ? <PauseIcon /> : <PlayIcon />}\n              <span>\n                {intl.formatMessage(\n                  refreshInterval ? messages.pauseLogs : messages.resumeLogs\n                )}\n              </span>\n            </Button>\n            <div className=\"flex flex-grow\">\n              <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n                <FunnelIcon className=\"h-6 w-6\" />\n              </span>\n              <select\n                id=\"filter\"\n                name=\"filter\"\n                onChange={(e) => {\n                  setCurrentFilter(e.target.value as Filter);\n                  router.push(router.pathname);\n                }}\n                value={currentFilter}\n                className=\"rounded-r-only\"\n              >\n                <option value=\"debug\">\n                  {intl.formatMessage(messages.filterDebug)}\n                </option>\n                <option value=\"info\">\n                  {intl.formatMessage(messages.filterInfo)}\n                </option>\n                <option value=\"warn\">\n                  {intl.formatMessage(messages.filterWarn)}\n                </option>\n                <option value=\"error\">\n                  {intl.formatMessage(messages.filterError)}\n                </option>\n              </select>\n            </div>\n          </div>\n        </div>\n        <Table>\n          <thead>\n            <tr>\n              <Table.TH>{intl.formatMessage(messages.time)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.level)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.label)}</Table.TH>\n              <Table.TH>{intl.formatMessage(messages.message)}</Table.TH>\n              <Table.TH />\n            </tr>\n          </thead>\n          <Table.TBody>\n            {!data ? (\n              <tr>\n                <Table.TD colSpan={5} noPadding>\n                  <LoadingSpinner />\n                </Table.TD>\n              </tr>\n            ) : (\n              data.results.map((row: LogMessage, index: number) => {\n                return (\n                  <tr key={`log-list-${index}`}>\n                    <Table.TD className=\"text-gray-300\">\n                      {intl.formatDate(row.timestamp, {\n                        year: 'numeric',\n                        month: 'short',\n                        day: '2-digit',\n                        hour: 'numeric',\n                        minute: 'numeric',\n                        second: 'numeric',\n                      })}\n                    </Table.TD>\n                    <Table.TD className=\"text-gray-300\">\n                      <Badge\n                        badgeType={\n                          row.level === 'error'\n                            ? 'danger'\n                            : row.level === 'warn'\n                              ? 'warning'\n                              : row.level === 'info'\n                                ? 'success'\n                                : 'default'\n                        }\n                      >\n                        {row.level.toUpperCase()}\n                      </Badge>\n                    </Table.TD>\n                    <Table.TD className=\"text-gray-300\">\n                      {row.label ?? ''}\n                    </Table.TD>\n                    <Table.TD className=\"text-gray-300\">{row.message}</Table.TD>\n                    <Table.TD className=\"-m-1 flex flex-wrap items-center justify-end\">\n                      {row.data && (\n                        <Tooltip\n                          content={intl.formatMessage(messages.viewdetails)}\n                        >\n                          <Button\n                            buttonSize=\"sm\"\n                            buttonType=\"primary\"\n                            onClick={() =>\n                              setActiveLog({ log: row, isOpen: true })\n                            }\n                            className=\"m-1\"\n                          >\n                            <DocumentMagnifyingGlassIcon className=\"icon-md\" />\n                          </Button>\n                        </Tooltip>\n                      )}\n                      <Tooltip\n                        content={intl.formatMessage(messages.copyToClipboard)}\n                      >\n                        <Button\n                          buttonType=\"primary\"\n                          buttonSize=\"sm\"\n                          onClick={() => copyLogString(row)}\n                          className=\"m-1\"\n                        >\n                          <ClipboardDocumentIcon className=\"icon-md\" />\n                        </Button>\n                      </Tooltip>\n                    </Table.TD>\n                  </tr>\n                );\n              })\n            )}\n\n            {data?.results.length === 0 && (\n              <tr className=\"relative h-24 p-2 text-white\">\n                <Table.TD colSpan={5} noPadding>\n                  <div className=\"flex w-screen flex-col items-center justify-center p-6 md:w-full\">\n                    <span className=\"text-base\">\n                      {intl.formatMessage(globalMessages.noresults)}\n                    </span>\n                    {currentFilter !== 'debug' && (\n                      <div className=\"mt-4\">\n                        <Button\n                          buttonSize=\"sm\"\n                          buttonType=\"primary\"\n                          onClick={() => setCurrentFilter('debug')}\n                        >\n                          {intl.formatMessage(messages.showall)}\n                        </Button>\n                      </div>\n                    )}\n                  </div>\n                </Table.TD>\n              </tr>\n            )}\n            <tr className=\"bg-gray-700\">\n              <Table.TD colSpan={5} noPadding>\n                <nav\n                  className=\"flex w-screen flex-col items-center space-x-4 space-y-3 px-6 py-3 sm:flex-row sm:space-y-0 md:w-full\"\n                  aria-label=\"Pagination\"\n                >\n                  <div className=\"hidden lg:flex lg:flex-1\">\n                    <p className=\"text-sm\">\n                      {(data?.results.length ?? 0) > 0 &&\n                        intl.formatMessage(globalMessages.showingresults, {\n                          from: pageIndex * currentPageSize + 1,\n                          to:\n                            (data?.results.length ?? 0 < currentPageSize)\n                              ? pageIndex * currentPageSize +\n                                (data?.results.length ?? 0)\n                              : (pageIndex + 1) * currentPageSize,\n                          total: data?.pageInfo.results ?? 0,\n                          strong: (msg: React.ReactNode) => (\n                            <span className=\"font-medium\">{msg}</span>\n                          ),\n                        })}\n                    </p>\n                  </div>\n                  <div className=\"flex justify-center sm:flex-1 sm:justify-start md:justify-center\">\n                    <span className=\"-mt-3 items-center text-sm sm:-ml-4 sm:mt-0 md:ml-0\">\n                      {intl.formatMessage(globalMessages.resultsperpage, {\n                        pageSize: (\n                          <select\n                            id=\"pageSize\"\n                            name=\"pageSize\"\n                            onChange={(e) => {\n                              setCurrentPageSize(Number(e.target.value));\n                              router\n                                .push(router.pathname)\n                                .then(() => window.scrollTo(0, 0));\n                            }}\n                            value={currentPageSize}\n                            className=\"short inline\"\n                          >\n                            <option value=\"10\">10</option>\n                            <option value=\"25\">25</option>\n                            <option value=\"50\">50</option>\n                            <option value=\"100\">100</option>\n                          </select>\n                        ),\n                      })}\n                    </span>\n                  </div>\n                  <div className=\"flex flex-auto justify-center space-x-2 sm:flex-1 sm:justify-end\">\n                    <Button\n                      disabled={!hasPrevPage}\n                      onClick={() =>\n                        updateQueryParams('page', (page - 1).toString())\n                      }\n                    >\n                      <ChevronLeftIcon />\n                      <span>{intl.formatMessage(globalMessages.previous)}</span>\n                    </Button>\n                    <Button\n                      disabled={!hasNextPage}\n                      onClick={() =>\n                        updateQueryParams('page', (page + 1).toString())\n                      }\n                    >\n                      <span>{intl.formatMessage(globalMessages.next)}</span>\n                      <ChevronRightIcon />\n                    </Button>\n                  </div>\n                </nav>\n              </Table.TD>\n            </tr>\n          </Table.TBody>\n        </Table>\n      </div>\n    </>\n  );\n};\n\nexport default SettingsLogs;\n"
  },
  {
    "path": "src/components/Settings/SettingsMain/index.tsx",
    "content": "import BlocklistedTagsSelector from '@app/components/BlocklistedTagsSelector';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport LanguageSelector from '@app/components/LanguageSelector';\nimport RegionSelector from '@app/components/RegionSelector';\nimport CopyButton from '@app/components/Settings/CopyButton';\nimport SettingsBadge from '@app/components/Settings/SettingsBadge';\nimport { availableLanguages } from '@app/context/LanguageContext';\nimport useLocale from '@app/hooks/useLocale';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { isValidURL } from '@app/utils/urlValidationHelper';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport { ArrowPathIcon } from '@heroicons/react/24/solid';\nimport type { UserSettingsGeneralResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport type { MainSettings } from '@server/lib/settings';\nimport type { AvailableLocale } from '@server/types/languages';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Settings.SettingsMain', {\n  general: 'General',\n  generalsettings: 'General Settings',\n  generalsettingsDescription:\n    'Configure global and default settings for Seerr.',\n  apikey: 'API Key',\n  apikeyCopied: 'Copied API key to clipboard.',\n  applicationTitle: 'Application Title',\n  applicationurl: 'Application URL',\n  discoverRegion: 'Discover Region',\n  discoverRegionTip: 'Filter content by regional availability',\n  originallanguage: 'Discover Language',\n  originallanguageTip: 'Filter content by original language',\n  blocklistedTags: 'Blocklist Content with Tags',\n  blocklistedTagsTip:\n    'Automatically add content with tags to the blocklist using the \"Process Blocklisted Tags\" job',\n  blocklistedTagsLimit: 'Limit Content Blocklisted per Tag',\n  blocklistedTagsLimitTip:\n    'The \"Process Blocklisted Tags\" job will blocklist this many pages into each sort. Larger numbers will create a more accurate blocklist, but use more space.',\n  streamingRegion: 'Streaming Region',\n  streamingRegionTip: 'Show streaming sites by regional availability',\n  hideBlocklisted: 'Hide Blocklisted Items',\n  hideBlocklistedTip:\n    'Hide blocklisted items from discover pages for all users with the \"Manage Blocklist\" permission',\n  toastApiKeySuccess: 'New API key generated successfully!',\n  toastApiKeyFailure: 'Something went wrong while generating a new API key.',\n  toastSettingsSuccess: 'Settings saved successfully!',\n  toastSettingsFailure: 'Something went wrong while saving settings.',\n  hideAvailable: 'Hide Available Media',\n  hideAvailableTip:\n    'Hide available media from the discover pages but not search results',\n  cacheImages: 'Enable Image Caching',\n  cacheImagesTip:\n    'Cache externally sourced images (requires a significant amount of disk space)',\n  validationApplicationTitle: 'You must provide an application title',\n  validationApplicationUrl: 'You must provide a valid URL',\n  validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',\n  partialRequestsEnabled: 'Allow Partial Series Requests',\n  enableSpecialEpisodes: 'Allow Special Episodes Requests',\n  locale: 'Display Language',\n  youtubeUrl: 'YouTube URL',\n  youtubeUrlTip:\n    'Base URL for YouTube videos if a self-hosted YouTube instance is used.',\n  validationUrl: 'You must provide a valid URL',\n  validationUrlTrailingSlash: 'URL must not end in a trailing slash',\n});\n\nconst SettingsMain = () => {\n  const { addToast } = useToasts();\n  const { user: currentUser, hasPermission: userHasPermission } = useUser();\n  const intl = useIntl();\n  const { setLocale } = useLocale();\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<MainSettings>('/api/v1/settings/main');\n  const { data: userData } = useSWR<UserSettingsGeneralResponse>(\n    currentUser ? `/api/v1/user/${currentUser.id}/settings/main` : null\n  );\n\n  const MainSettingsSchema = Yup.object().shape({\n    applicationTitle: Yup.string().required(\n      intl.formatMessage(messages.validationApplicationTitle)\n    ),\n    applicationUrl: Yup.string()\n      .test(\n        'valid-url',\n        intl.formatMessage(messages.validationApplicationUrl),\n        isValidURL\n      )\n      .test(\n        'no-trailing-slash',\n        intl.formatMessage(messages.validationApplicationUrlTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n    blocklistedTagsLimit: Yup.number()\n      .test(\n        'positive',\n        'Number must be greater than 0.',\n        (value) => (value ?? 0) >= 0\n      )\n      .test(\n        'lte-250',\n        'Number must be less than or equal to 250.',\n        (value) => (value ?? 0) <= 250\n      ),\n    youtubeUrl: Yup.string()\n      .url(intl.formatMessage(messages.validationUrl))\n      .test(\n        'no-trailing-slash',\n        intl.formatMessage(messages.validationUrlTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n  });\n\n  const regenerate = async () => {\n    try {\n      await axios.post('/api/v1/settings/main/regenerate');\n\n      revalidate();\n      addToast(intl.formatMessage(messages.toastApiKeySuccess), {\n        autoDismiss: true,\n        appearance: 'success',\n      });\n    } catch {\n      addToast(intl.formatMessage(messages.toastApiKeyFailure), {\n        autoDismiss: true,\n        appearance: 'error',\n      });\n    }\n  };\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.general),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.generalsettings)}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.generalsettingsDescription)}\n        </p>\n      </div>\n      <div className=\"section\">\n        <Formik\n          initialValues={{\n            applicationTitle: data?.applicationTitle,\n            applicationUrl: data?.applicationUrl,\n            hideAvailable: data?.hideAvailable,\n            hideBlocklisted: data?.hideBlocklisted,\n            locale: data?.locale ?? 'en',\n            discoverRegion: data?.discoverRegion,\n            originalLanguage: data?.originalLanguage,\n            streamingRegion: data?.streamingRegion || 'US',\n            blocklistedTags: data?.blocklistedTags,\n            blocklistedTagsLimit: data?.blocklistedTagsLimit || 50,\n            partialRequestsEnabled: data?.partialRequestsEnabled,\n            enableSpecialEpisodes: data?.enableSpecialEpisodes,\n            cacheImages: data?.cacheImages,\n            youtubeUrl: data?.youtubeUrl,\n          }}\n          enableReinitialize\n          validationSchema={MainSettingsSchema}\n          onSubmit={async (values) => {\n            try {\n              await axios.post('/api/v1/settings/main', {\n                applicationTitle: values.applicationTitle,\n                applicationUrl: values.applicationUrl,\n                hideAvailable: values.hideAvailable,\n                hideBlocklisted: values.hideBlocklisted,\n                locale: values.locale,\n                discoverRegion: values.discoverRegion,\n                streamingRegion: values.streamingRegion,\n                originalLanguage: values.originalLanguage,\n                blocklistedTags: values.blocklistedTags,\n                blocklistedTagsLimit: values.blocklistedTagsLimit,\n                partialRequestsEnabled: values.partialRequestsEnabled,\n                enableSpecialEpisodes: values.enableSpecialEpisodes,\n                cacheImages: values.cacheImages,\n                youtubeUrl: values.youtubeUrl,\n              });\n              mutate('/api/v1/settings/public');\n              mutate('/api/v1/status');\n\n              if (setLocale) {\n                setLocale(\n                  (userData?.locale\n                    ? userData.locale\n                    : values.locale) as AvailableLocale\n                );\n              }\n\n              addToast(intl.formatMessage(messages.toastSettingsSuccess), {\n                autoDismiss: true,\n                appearance: 'success',\n              });\n            } catch {\n              addToast(intl.formatMessage(messages.toastSettingsFailure), {\n                autoDismiss: true,\n                appearance: 'error',\n              });\n            } finally {\n              revalidate();\n            }\n          }}\n        >\n          {({\n            errors,\n            touched,\n            isSubmitting,\n            isValid,\n            values,\n            setFieldValue,\n          }) => {\n            return (\n              <Form className=\"section\" data-testid=\"settings-main-form\">\n                {userHasPermission(Permission.ADMIN) && (\n                  <div className=\"form-row\">\n                    <label htmlFor=\"apiKey\" className=\"text-label\">\n                      {intl.formatMessage(messages.apikey)}\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <SensitiveInput\n                          type=\"text\"\n                          id=\"apiKey\"\n                          className=\"rounded-l-only\"\n                          value={data?.apiKey}\n                          readOnly\n                        />\n                        <CopyButton\n                          textToCopy={data?.apiKey ?? ''}\n                          toastMessage={intl.formatMessage(\n                            messages.apikeyCopied\n                          )}\n                          key={data?.apiKey}\n                        />\n                        <button\n                          onClick={(e) => {\n                            e.preventDefault();\n                            regenerate();\n                          }}\n                          className=\"input-action\"\n                          type=\"button\"\n                        >\n                          <ArrowPathIcon />\n                        </button>\n                      </div>\n                    </div>\n                  </div>\n                )}\n                <div className=\"form-row\">\n                  <label htmlFor=\"applicationTitle\" className=\"text-label\">\n                    {intl.formatMessage(messages.applicationTitle)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"applicationTitle\"\n                        name=\"applicationTitle\"\n                        type=\"text\"\n                      />\n                    </div>\n                    {errors.applicationTitle &&\n                      touched.applicationTitle &&\n                      typeof errors.applicationTitle === 'string' && (\n                        <div className=\"error\">{errors.applicationTitle}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"applicationUrl\" className=\"text-label\">\n                    {intl.formatMessage(messages.applicationurl)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"applicationUrl\"\n                        name=\"applicationUrl\"\n                        type=\"text\"\n                        inputMode=\"url\"\n                      />\n                    </div>\n                    {errors.applicationUrl &&\n                      touched.applicationUrl &&\n                      typeof errors.applicationUrl === 'string' && (\n                        <div className=\"error\">{errors.applicationUrl}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"cacheImages\" className=\"checkbox-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.cacheImages)}\n                    </span>\n                    <SettingsBadge badgeType=\"experimental\" />\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.cacheImagesTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"cacheImages\"\n                      name=\"cacheImages\"\n                      onChange={() => {\n                        setFieldValue('cacheImages', !values.cacheImages);\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"locale\" className=\"text-label\">\n                    {intl.formatMessage(messages.locale)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field as=\"select\" id=\"locale\" name=\"locale\">\n                        {(\n                          Object.keys(\n                            availableLanguages\n                          ) as (keyof typeof availableLanguages)[]\n                        ).map((key) => (\n                          <option\n                            key={key}\n                            value={availableLanguages[key].code}\n                            lang={availableLanguages[key].code}\n                          >\n                            {availableLanguages[key].display}\n                          </option>\n                        ))}\n                      </Field>\n                    </div>\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"discoverRegion\" className=\"text-label\">\n                    <span>{intl.formatMessage(messages.discoverRegion)}</span>\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.discoverRegionTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <RegionSelector\n                        value={values.discoverRegion ?? ''}\n                        name=\"discoverRegion\"\n                        onChange={setFieldValue}\n                      />\n                    </div>\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"originalLanguage\" className=\"text-label\">\n                    <span>{intl.formatMessage(messages.originallanguage)}</span>\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.originallanguageTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field relative z-30\">\n                      <LanguageSelector\n                        setFieldValue={setFieldValue}\n                        value={values.originalLanguage}\n                      />\n                    </div>\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"streamingRegion\" className=\"text-label\">\n                    <span>{intl.formatMessage(messages.streamingRegion)}</span>\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.streamingRegionTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field relative z-20\">\n                      <RegionSelector\n                        value={values.streamingRegion}\n                        name=\"streamingRegion\"\n                        onChange={setFieldValue}\n                        regionType=\"streaming\"\n                        disableAll\n                      />\n                    </div>\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"blocklistedTags\" className=\"text-label\">\n                    <span>{intl.formatMessage(messages.blocklistedTags)}</span>\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.blocklistedTagsTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field relative z-10\">\n                      <BlocklistedTagsSelector\n                        defaultValue={values.blocklistedTags}\n                      />\n                    </div>\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"blocklistedTagsLimit\" className=\"text-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.blocklistedTagsLimit)}\n                    </span>\n                    <SettingsBadge badgeType=\"advanced\" />\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.blocklistedTagsLimitTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      id=\"blocklistedTagsLimit\"\n                      name=\"blocklistedTagsLimit\"\n                      type=\"text\"\n                      inputMode=\"numeric\"\n                      className=\"short\"\n                      placeholder={50}\n                    />\n                    {errors.blocklistedTagsLimit &&\n                      touched.blocklistedTagsLimit &&\n                      typeof errors.blocklistedTagsLimit === 'string' && (\n                        <div className=\"error\">\n                          {errors.blocklistedTagsLimit}\n                        </div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"hideAvailable\" className=\"checkbox-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.hideAvailable)}\n                    </span>\n                    <SettingsBadge badgeType=\"experimental\" />\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.hideAvailableTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"hideAvailable\"\n                      name=\"hideAvailable\"\n                      onChange={() => {\n                        setFieldValue('hideAvailable', !values.hideAvailable);\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"hideBlocklisted\" className=\"checkbox-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.hideBlocklisted)}\n                    </span>\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.hideBlocklistedTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"hideBlocklisted\"\n                      name=\"hideBlocklisted\"\n                      onChange={() => {\n                        setFieldValue(\n                          'hideBlocklisted',\n                          !values.hideBlocklisted\n                        );\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label\n                    htmlFor=\"partialRequestsEnabled\"\n                    className=\"checkbox-label\"\n                  >\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.partialRequestsEnabled)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"partialRequestsEnabled\"\n                      name=\"partialRequestsEnabled\"\n                      onChange={() => {\n                        setFieldValue(\n                          'partialRequestsEnabled',\n                          !values.partialRequestsEnabled\n                        );\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label\n                    htmlFor=\"enableSpecialEpisodes\"\n                    className=\"checkbox-label\"\n                  >\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.enableSpecialEpisodes)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"enableSpecialEpisodes\"\n                      name=\"enableSpecialEpisodes\"\n                      onChange={() => {\n                        setFieldValue(\n                          'enableSpecialEpisodes',\n                          !values.enableSpecialEpisodes\n                        );\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"youtubeUrl\" className=\"text-label\">\n                    {intl.formatMessage(messages.youtubeUrl)}\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.youtubeUrlTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"youtubeUrl\"\n                        name=\"youtubeUrl\"\n                        type=\"text\"\n                        inputMode=\"url\"\n                      />\n                    </div>\n                    {errors.youtubeUrl &&\n                      touched.youtubeUrl &&\n                      typeof errors.youtubeUrl === 'string' && (\n                        <div className=\"error\">{errors.youtubeUrl}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"actions\">\n                  <div className=\"flex justify-end\">\n                    <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                      <Button\n                        buttonType=\"primary\"\n                        type=\"submit\"\n                        disabled={isSubmitting || !isValid}\n                      >\n                        <ArrowDownOnSquareIcon />\n                        <span>\n                          {isSubmitting\n                            ? intl.formatMessage(globalMessages.saving)\n                            : intl.formatMessage(globalMessages.save)}\n                        </span>\n                      </Button>\n                    </span>\n                  </div>\n                </div>\n              </Form>\n            );\n          }}\n        </Formik>\n      </div>\n    </>\n  );\n};\n\nexport default SettingsMain;\n"
  },
  {
    "path": "src/components/Settings/SettingsMetadata.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport MetadataSelector, {\n  MetadataProviderType,\n} from '@app/components/MetadataSelector';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.Settings', {\n  metadataProviderSettings: 'Metadata Providers',\n  general: 'General',\n  settings: 'Settings',\n  seriesMetadataProvider: 'Series metadata provider',\n  animeMetadataProvider: 'Anime metadata provider',\n  metadataSettings: 'Settings for metadata provider',\n  clickTest:\n    'Click on the \"Test\" button to check connectivity with metadata providers',\n  notTested: 'Not Tested',\n  failed: 'Does not work',\n  operational: 'Operational',\n  providerStatus: 'Metadata Provider Status',\n  chooseProvider: 'Choose metadata providers for different content types',\n  metadataProviderSelection: 'Metadata Provider Selection',\n  tmdbProviderDoesnotWork:\n    'TMDB provider does not work, please select another metadata provider',\n  tvdbProviderDoesnotWork:\n    'TVDB provider does not work, please select another metadata provider',\n  allChosenProvidersAreOperational:\n    'All chosen metadata providers are operational',\n  connectionTestFailed: 'Connection test failed',\n  failedToSaveMetadataSettings: 'Failed to save metadata provider settings',\n  metadataSettingsSaved: 'Metadata provider settings saved',\n});\n\ntype ProviderStatus = 'ok' | 'not tested' | 'failed';\n\ninterface ProviderResponse {\n  tvdb: ProviderStatus;\n  tmdb: ProviderStatus;\n}\n\ninterface MetadataValues {\n  tv: MetadataProviderType;\n  anime: MetadataProviderType;\n}\n\ninterface MetadataSettings {\n  metadata: MetadataValues;\n}\n\nconst SettingsMetadata = () => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const [isTesting, setIsTesting] = useState(false);\n  const defaultStatus: ProviderResponse = {\n    tmdb: 'not tested',\n    tvdb: 'not tested',\n  };\n\n  const [providerStatus, setProviderStatus] =\n    useState<ProviderResponse>(defaultStatus);\n\n  const { data, error } = useSWR<MetadataSettings>(\n    '/api/v1/settings/metadatas',\n    async (url: string) => {\n      const response = await axios.get<{\n        tv: MetadataProviderType;\n        anime: MetadataProviderType;\n      }>(url);\n\n      return {\n        metadata: {\n          tv: response.data.tv,\n          anime: response.data.anime,\n        },\n      };\n    }\n  );\n\n  const testConnection = async (\n    values: MetadataValues\n  ): Promise<ProviderResponse> => {\n    const useTmdb =\n      values.tv === MetadataProviderType.TMDB ||\n      values.anime === MetadataProviderType.TMDB;\n    const useTvdb =\n      values.tv === MetadataProviderType.TVDB ||\n      values.anime === MetadataProviderType.TVDB;\n\n    const testData = {\n      tmdb: useTmdb,\n      tvdb: useTvdb,\n    };\n\n    try {\n      const response = await axios.post<{\n        success: boolean;\n        tests: ProviderResponse;\n      }>('/api/v1/settings/metadatas/test', testData);\n\n      const newStatus: ProviderResponse = {\n        tmdb: useTmdb ? response.data.tests.tmdb : 'not tested',\n        tvdb: useTvdb ? response.data.tests.tvdb : 'not tested',\n      };\n\n      setProviderStatus(newStatus);\n      return newStatus;\n    } catch (error) {\n      if (axios.isAxiosError(error) && error.response) {\n        // If we receive an error response with a valid format\n        const errorData = error.response.data as {\n          success: boolean;\n          tests: ProviderResponse;\n        };\n\n        if (errorData.tests) {\n          const newStatus: ProviderResponse = {\n            tmdb: useTmdb ? errorData.tests.tmdb : 'not tested',\n            tvdb: useTvdb ? errorData.tests.tvdb : 'not tested',\n          };\n\n          setProviderStatus(newStatus);\n          return newStatus;\n        }\n      }\n\n      // In case of error without usable data\n      throw new Error('Failed to test connection', { cause: error });\n    }\n  };\n\n  const saveSettings = async (\n    values: MetadataValues\n  ): Promise<MetadataSettings> => {\n    try {\n      const response = await axios.put<{\n        success: boolean;\n        tv: MetadataProviderType;\n        anime: MetadataProviderType;\n        tests?: {\n          tvdb: ProviderStatus;\n          tmdb: ProviderStatus;\n        };\n      }>('/api/v1/settings/metadatas', {\n        tv: values.tv,\n        anime: values.anime,\n      });\n\n      // Update metadata provider status if available\n      if (response.data.tests) {\n        const mapStatusValue = (status: string): ProviderStatus => {\n          if (status === 'ok') return 'ok';\n          if (status === 'failed') return 'failed';\n          return 'not tested';\n        };\n\n        setProviderStatus({\n          tmdb: mapStatusValue(response.data.tests.tmdb),\n          tvdb: mapStatusValue(response.data.tests.tvdb),\n        });\n      }\n\n      // Adapt the response to the format expected by the component\n      return {\n        metadata: {\n          tv: response.data.tv,\n          anime: response.data.anime,\n        },\n      };\n    } catch (error) {\n      // Retrieve test data in case of error\n      if (axios.isAxiosError(error) && error.response?.data) {\n        const errorData = error.response.data as {\n          success: boolean;\n          tests?: {\n            tvdb: string;\n            tmdb: string;\n          };\n        };\n\n        // If test data is available in the error response\n        if (errorData.tests) {\n          const mapStatusValue = (status: string): ProviderStatus => {\n            if (status === 'ok') return 'ok';\n            if (status === 'failed') return 'failed';\n            return 'not tested';\n          };\n\n          // Update metadata provider status with error data\n          setProviderStatus({\n            tmdb: mapStatusValue(errorData.tests.tmdb),\n            tvdb: mapStatusValue(errorData.tests.tvdb),\n          });\n        }\n      }\n\n      throw new Error('Failed to save Metadata settings', { cause: error });\n    }\n  };\n\n  const getStatusClass = (status: ProviderStatus): string => {\n    switch (status) {\n      case 'ok':\n        return 'text-green-500';\n      case 'not tested':\n        return 'text-yellow-500';\n      case 'failed':\n        return 'text-red-500';\n    }\n  };\n\n  const getStatusMessage = (status: ProviderStatus): string => {\n    switch (status) {\n      case 'ok':\n        return intl.formatMessage(messages.operational);\n      case 'not tested':\n        return intl.formatMessage(messages.notTested);\n      case 'failed':\n        return intl.formatMessage(messages.failed);\n    }\n  };\n\n  const getBadgeType = (\n    status: ProviderStatus\n  ):\n    | 'default'\n    | 'primary'\n    | 'danger'\n    | 'warning'\n    | 'success'\n    | 'dark'\n    | 'light'\n    | undefined => {\n    switch (status) {\n      case 'ok':\n        return 'success';\n      case 'not tested':\n        return 'warning';\n      case 'failed':\n        return 'danger';\n    }\n  };\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  const initialValues: MetadataValues = data?.metadata || {\n    tv: MetadataProviderType.TMDB,\n    anime: MetadataProviderType.TMDB,\n  };\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.general),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.metadataProviderSettings)}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.metadataSettings)}\n        </p>\n      </div>\n\n      <div className=\"mb-6 rounded-lg bg-gray-800 p-4\">\n        <h4 className=\"mb-3 text-lg font-medium\">\n          {intl.formatMessage(messages.providerStatus)}\n        </h4>\n        <div className=\"flex flex-col space-y-3\">\n          <div className=\"flex items-center\">\n            <span className=\"mr-2 w-24\">TheMovieDB:</span>\n            <span\n              className={`text-sm ${getStatusClass(providerStatus.tmdb)}`}\n              data-testid=\"tmdb-status-container\"\n            >\n              <Badge badgeType={getBadgeType(providerStatus.tmdb)}>\n                {getStatusMessage(providerStatus.tmdb)}\n              </Badge>\n            </span>\n          </div>\n          <div className=\"flex items-center\">\n            <span className=\"mr-2 w-24\">TheTVDB:</span>\n            <span\n              className={`text-sm ${getStatusClass(providerStatus.tvdb)}`}\n              data-testid=\"tvdb-status\"\n            >\n              <Badge badgeType={getBadgeType(providerStatus.tvdb)}>\n                {getStatusMessage(providerStatus.tvdb)}\n              </Badge>\n            </span>\n          </div>\n        </div>\n      </div>\n\n      <div className=\"section\">\n        <Formik\n          initialValues={{ metadata: initialValues }}\n          onSubmit={async (values) => {\n            try {\n              const result = await saveSettings(values.metadata);\n\n              if (data) {\n                data.metadata = result.metadata;\n              }\n\n              addToast(intl.formatMessage(messages.metadataSettingsSaved), {\n                appearance: 'success',\n                autoDismiss: true,\n              });\n            } catch {\n              addToast(\n                intl.formatMessage(messages.failedToSaveMetadataSettings),\n                {\n                  appearance: 'error',\n                  autoDismiss: true,\n                }\n              );\n            }\n          }}\n        >\n          {({ isSubmitting, isValid, values, setFieldValue }) => {\n            return (\n              <Form className=\"section\" data-testid=\"settings-main-form\">\n                <div className=\"mb-6\">\n                  <h2 className=\"heading\">\n                    {intl.formatMessage(messages.metadataProviderSelection)}\n                  </h2>\n                  <p className=\"description\">\n                    {intl.formatMessage(messages.chooseProvider)}\n                  </p>\n                </div>\n\n                <div className=\"form-row\">\n                  <label\n                    htmlFor=\"tv-metadata-provider\"\n                    className=\"checkbox-label\"\n                  >\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.seriesMetadataProvider)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <MetadataSelector\n                      testId=\"tv-metadata-provider-selector\"\n                      value={values.metadata.tv}\n                      onChange={(value) => setFieldValue('metadata.tv', value)}\n                      isDisabled={isSubmitting}\n                    />\n                  </div>\n                </div>\n\n                <div className=\"form-row\">\n                  <label\n                    htmlFor=\"anime-metadata-provider\"\n                    className=\"checkbox-label\"\n                  >\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.animeMetadataProvider)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <MetadataSelector\n                      testId=\"anime-metadata-provider-selector\"\n                      value={values.metadata.anime}\n                      onChange={(value) =>\n                        setFieldValue('metadata.anime', value)\n                      }\n                      isDisabled={isSubmitting}\n                    />\n                  </div>\n                </div>\n\n                <div className=\"actions\">\n                  <div className=\"flex justify-end\">\n                    <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                      <Button\n                        buttonType=\"warning\"\n                        type=\"button\"\n                        disabled={isSubmitting || !isValid}\n                        onClick={async () => {\n                          setIsTesting(true);\n                          try {\n                            const resp = await testConnection(values.metadata);\n\n                            if (resp.tvdb === 'failed') {\n                              addToast(\n                                intl.formatMessage(\n                                  messages.tvdbProviderDoesnotWork\n                                ),\n                                {\n                                  appearance: 'error',\n                                  autoDismiss: true,\n                                }\n                              );\n                            } else if (resp.tmdb === 'failed') {\n                              addToast(\n                                intl.formatMessage(\n                                  messages.tmdbProviderDoesnotWork\n                                ),\n                                {\n                                  appearance: 'error',\n                                  autoDismiss: true,\n                                }\n                              );\n                            } else {\n                              addToast(\n                                intl.formatMessage(\n                                  messages.allChosenProvidersAreOperational\n                                ),\n                                {\n                                  appearance: 'success',\n                                  autoDismiss: true,\n                                }\n                              );\n                            }\n                          } catch {\n                            addToast(\n                              intl.formatMessage(messages.connectionTestFailed),\n                              {\n                                appearance: 'error',\n                                autoDismiss: true,\n                              }\n                            );\n                          } finally {\n                            setIsTesting(false);\n                          }\n                        }}\n                      >\n                        <BeakerIcon />\n                        <span>\n                          {isTesting\n                            ? intl.formatMessage(globalMessages.testing)\n                            : intl.formatMessage(globalMessages.test)}\n                        </span>\n                      </Button>\n                    </span>\n\n                    <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                      <Button\n                        data-testid=\"metadata-save-button\"\n                        buttonType=\"primary\"\n                        type=\"submit\"\n                        disabled={isSubmitting || !isValid || isTesting}\n                      >\n                        <ArrowDownOnSquareIcon />\n                        <span>\n                          {isSubmitting\n                            ? intl.formatMessage(globalMessages.saving)\n                            : intl.formatMessage(globalMessages.save)}\n                        </span>\n                      </Button>\n                    </span>\n                  </div>\n                </div>\n              </Form>\n            );\n          }}\n        </Formik>\n      </div>\n    </>\n  );\n};\n\nexport default SettingsMetadata;\n"
  },
  {
    "path": "src/components/Settings/SettingsNetwork/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport SettingsBadge from '@app/components/Settings/SettingsBadge';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport type { NetworkSettings } from '@server/lib/settings';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Settings.SettingsNetwork', {\n  toastSettingsSuccess: 'Settings saved successfully!',\n  toastSettingsFailure: 'Something went wrong while saving settings.',\n  network: 'Network',\n  networksettings: 'Network Settings',\n  networksettingsDescription:\n    'Configure network settings for your Seerr instance.',\n  csrfProtection: 'Enable CSRF Protection',\n  csrfProtectionTip: 'Set external API access to read-only (requires HTTPS)',\n  csrfProtectionHoverTip:\n    'Do NOT enable this setting unless you understand what you are doing!',\n  trustProxy: 'Enable Proxy Support',\n  trustProxyTip:\n    'Allow Seerr to correctly register client IP addresses behind a proxy',\n  proxyEnabled: 'HTTP(S) Proxy',\n  proxyEnabledTip:\n    'Send ALL outgoing HTTP/HTTPS requests through a proxy server (host/port). Does NOT enable HTTPS, SSL, or certificate configuration.',\n  proxyHostname: 'Proxy Hostname',\n  proxyPort: 'Proxy Port',\n  proxySsl: 'Use SSL For Proxy',\n  proxyUser: 'Proxy Username',\n  proxyPassword: 'Proxy Password',\n  proxyBypassFilter: 'Proxy Ignored Addresses',\n  proxyBypassFilterTip:\n    \"Use ',' as a separator, and '*.' as a wildcard for subdomains\",\n  proxyBypassLocalAddresses: 'Bypass Proxy for Local Addresses',\n  validationDnsCacheMinTtl: 'You must provide a valid minimum TTL',\n  validationDnsCacheMaxTtl: 'You must provide a valid maximum TTL',\n  validationProxyPort: 'You must provide a valid port',\n  networkDisclaimer:\n    'Network parameters from your container/system should be used instead of these settings. See the {docs} for more information.',\n  docs: 'documentation',\n  forceIpv4First: 'Force IPv4 Resolution First',\n  forceIpv4FirstTip:\n    'Force Seerr to resolve IPv4 addresses first instead of IPv6',\n  dnsCache: 'DNS Cache',\n  dnsCacheTip:\n    'Enable caching of DNS lookups to optimize performance and avoid making unnecessary API calls',\n  dnsCacheHoverTip:\n    'Do NOT enable this if you are experiencing issues with DNS lookups',\n  dnsCacheForceMinTtl: 'DNS Cache Minimum TTL',\n  dnsCacheForceMaxTtl: 'DNS Cache Maximum TTL',\n  apiRequestTimeout: 'API Request Timeout',\n  apiRequestTimeoutTip:\n    'Maximum time (in seconds) to wait for responses from external services like Radarr/Sonarr. Set to 0 for no timeout.',\n  validationApiRequestTimeout: 'You must provide a valid timeout value',\n});\n\nconst SettingsNetwork = () => {\n  const { addToast } = useToasts();\n  const intl = useIntl();\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<NetworkSettings>('/api/v1/settings/network');\n\n  const NetworkSettingsSchema = Yup.object().shape({\n    dnsCacheForceMinTtl: Yup.number().when('dnsCacheEnabled', {\n      is: true,\n      then: Yup.number()\n        .typeError(intl.formatMessage(messages.validationDnsCacheMinTtl))\n        .required(intl.formatMessage(messages.validationDnsCacheMinTtl))\n        .min(0),\n    }),\n    dnsCacheForceMaxTtl: Yup.number().when('dnsCacheEnabled', {\n      is: true,\n      then: Yup.number()\n        .typeError(intl.formatMessage(messages.validationDnsCacheMaxTtl))\n        .required(intl.formatMessage(messages.validationDnsCacheMaxTtl))\n        .min(-1),\n    }),\n    proxyPort: Yup.number().when('proxyEnabled', {\n      is: (proxyEnabled: boolean) => proxyEnabled,\n      then: Yup.number()\n        .typeError(intl.formatMessage(messages.validationProxyPort))\n        .integer(intl.formatMessage(messages.validationProxyPort))\n        .min(1, intl.formatMessage(messages.validationProxyPort))\n        .max(65535, intl.formatMessage(messages.validationProxyPort))\n        .required(intl.formatMessage(messages.validationProxyPort)),\n    }),\n    apiRequestTimeout: Yup.number()\n      .typeError(intl.formatMessage(messages.validationApiRequestTimeout))\n      .required(intl.formatMessage(messages.validationApiRequestTimeout))\n      .min(0, intl.formatMessage(messages.validationApiRequestTimeout)),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.network),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.networksettings)}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.networksettingsDescription)}\n        </p>\n      </div>\n      <div className=\"section\">\n        <Formik\n          initialValues={{\n            csrfProtection: data?.csrfProtection,\n            forceIpv4First: data?.forceIpv4First,\n            dnsCacheEnabled: data?.dnsCache.enabled,\n            dnsCacheForceMinTtl: data?.dnsCache.forceMinTtl,\n            dnsCacheForceMaxTtl: data?.dnsCache.forceMaxTtl,\n            trustProxy: data?.trustProxy,\n            proxyEnabled: data?.proxy?.enabled,\n            proxyHostname: data?.proxy?.hostname,\n            proxyPort: data?.proxy?.port,\n            proxySsl: data?.proxy?.useSsl,\n            proxyUser: data?.proxy?.user,\n            proxyPassword: data?.proxy?.password,\n            proxyBypassFilter: data?.proxy?.bypassFilter,\n            proxyBypassLocalAddresses: data?.proxy?.bypassLocalAddresses,\n            apiRequestTimeout:\n              data?.apiRequestTimeout !== undefined\n                ? data.apiRequestTimeout / 1000\n                : 10,\n          }}\n          enableReinitialize\n          validationSchema={NetworkSettingsSchema}\n          onSubmit={async (values) => {\n            try {\n              await axios.post('/api/v1/settings/network', {\n                csrfProtection: values.csrfProtection,\n                forceIpv4First: values.forceIpv4First,\n                trustProxy: values.trustProxy,\n                dnsCache: {\n                  enabled: values.dnsCacheEnabled,\n                  forceMinTtl: Number(values.dnsCacheForceMinTtl),\n                  forceMaxTtl: Number(values.dnsCacheForceMaxTtl),\n                },\n                proxy: {\n                  enabled: values.proxyEnabled,\n                  hostname: values.proxyHostname,\n                  port: Number(values.proxyPort),\n                  useSsl: values.proxySsl,\n                  user: values.proxyUser,\n                  password: values.proxyPassword,\n                  bypassFilter: values.proxyBypassFilter,\n                  bypassLocalAddresses: values.proxyBypassLocalAddresses,\n                },\n                apiRequestTimeout: Number(values.apiRequestTimeout) * 1000,\n              });\n              mutate('/api/v1/settings/public');\n              mutate('/api/v1/status');\n\n              addToast(intl.formatMessage(messages.toastSettingsSuccess), {\n                autoDismiss: true,\n                appearance: 'success',\n              });\n            } catch {\n              addToast(intl.formatMessage(messages.toastSettingsFailure), {\n                autoDismiss: true,\n                appearance: 'error',\n              });\n            } finally {\n              revalidate();\n            }\n          }}\n        >\n          {({\n            errors,\n            touched,\n            isSubmitting,\n            isValid,\n            values,\n            setFieldValue,\n          }) => {\n            return (\n              <Form className=\"section\" data-testid=\"settings-network-form\">\n                <div className=\"form-row\">\n                  <label htmlFor=\"trustProxy\" className=\"checkbox-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.trustProxy)}\n                    </span>\n                    <SettingsBadge badgeType=\"restartRequired\" />\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.trustProxyTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"trustProxy\"\n                      name=\"trustProxy\"\n                      onChange={() => {\n                        setFieldValue('trustProxy', !values.trustProxy);\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"csrfProtection\" className=\"checkbox-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.csrfProtection)}\n                    </span>\n                    <SettingsBadge badgeType=\"advanced\" className=\"mr-2\" />\n                    <SettingsBadge badgeType=\"restartRequired\" />\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.csrfProtectionTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Tooltip\n                      content={intl.formatMessage(\n                        messages.csrfProtectionHoverTip\n                      )}\n                    >\n                      <Field\n                        type=\"checkbox\"\n                        id=\"csrfProtection\"\n                        name=\"csrfProtection\"\n                        onChange={() => {\n                          setFieldValue(\n                            'csrfProtection',\n                            !values.csrfProtection\n                          );\n                        }}\n                      />\n                    </Tooltip>\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"forceIpv4First\" className=\"checkbox-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.forceIpv4First)}\n                    </span>\n                    <SettingsBadge badgeType=\"advanced\" className=\"mr-2\" />\n                    <SettingsBadge badgeType=\"restartRequired\" />\n                    <SettingsBadge badgeType=\"experimental\" />\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.forceIpv4FirstTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"forceIpv4First\"\n                      name=\"forceIpv4First\"\n                      onChange={() => {\n                        setFieldValue('forceIpv4First', !values.forceIpv4First);\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"dnsCacheEnabled\" className=\"checkbox-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.dnsCache)}\n                    </span>\n                    <SettingsBadge badgeType=\"advanced\" className=\"mr-2\" />\n                    <SettingsBadge badgeType=\"restartRequired\" />\n                    <SettingsBadge badgeType=\"experimental\" className=\"mr-2\" />\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.dnsCacheTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Tooltip\n                      content={intl.formatMessage(messages.dnsCacheHoverTip)}\n                    >\n                      <Field\n                        type=\"checkbox\"\n                        id=\"dnsCacheEnabled\"\n                        name=\"dnsCacheEnabled\"\n                        onChange={() => {\n                          setFieldValue(\n                            'dnsCacheEnabled',\n                            !values.dnsCacheEnabled\n                          );\n                        }}\n                      />\n                    </Tooltip>\n                  </div>\n                </div>\n                {values.dnsCacheEnabled && (\n                  <>\n                    <div className=\"ml-4 mr-2\">\n                      <div className=\"form-row\">\n                        <label\n                          htmlFor=\"dnsCacheForceMinTtl\"\n                          className=\"text-label\"\n                        >\n                          {intl.formatMessage(messages.dnsCacheForceMinTtl)}\n                        </label>\n                        <div className=\"form-input-area\">\n                          <Field\n                            id=\"dnsCacheForceMinTtl\"\n                            name=\"dnsCacheForceMinTtl\"\n                            type=\"text\"\n                            inputMode=\"numeric\"\n                            className=\"short\"\n                          />\n                        </div>\n                        {errors.dnsCacheForceMinTtl &&\n                          touched.dnsCacheForceMinTtl &&\n                          typeof errors.dnsCacheForceMinTtl === 'string' && (\n                            <div className=\"error\">\n                              {errors.dnsCacheForceMinTtl}\n                            </div>\n                          )}\n                      </div>\n                      <div className=\"form-row\">\n                        <label\n                          htmlFor=\"dnsCacheForceMaxTtl\"\n                          className=\"text-label\"\n                        >\n                          {intl.formatMessage(messages.dnsCacheForceMaxTtl)}\n                        </label>\n                        <div className=\"form-input-area\">\n                          <Field\n                            id=\"dnsCacheForceMaxTtl\"\n                            name=\"dnsCacheForceMaxTtl\"\n                            type=\"text\"\n                            inputMode=\"text\"\n                            className=\"short\"\n                          />\n                        </div>\n                        {errors.dnsCacheForceMaxTtl &&\n                          touched.dnsCacheForceMaxTtl &&\n                          typeof errors.dnsCacheForceMaxTtl === 'string' && (\n                            <div className=\"error\">\n                              {errors.dnsCacheForceMaxTtl}\n                            </div>\n                          )}\n                      </div>\n                    </div>\n                  </>\n                )}\n                <div className=\"form-row\">\n                  <label htmlFor=\"apiRequestTimeout\" className=\"text-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.apiRequestTimeout)}\n                    </span>\n                    <SettingsBadge badgeType=\"restartRequired\" />\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.apiRequestTimeoutTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      id=\"apiRequestTimeout\"\n                      name=\"apiRequestTimeout\"\n                      type=\"text\"\n                      inputMode=\"numeric\"\n                      className=\"short\"\n                    />\n                  </div>\n                  {errors.apiRequestTimeout &&\n                    touched.apiRequestTimeout &&\n                    typeof errors.apiRequestTimeout === 'string' && (\n                      <div className=\"error\">{errors.apiRequestTimeout}</div>\n                    )}\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"proxyEnabled\" className=\"checkbox-label\">\n                    <span className=\"mr-2\">\n                      {intl.formatMessage(messages.proxyEnabled)}\n                    </span>\n                    <SettingsBadge badgeType=\"advanced\" className=\"mr-2\" />\n                    <SettingsBadge badgeType=\"restartRequired\" />\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.proxyEnabledTip)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"proxyEnabled\"\n                      name=\"proxyEnabled\"\n                      onChange={() => {\n                        setFieldValue('proxyEnabled', !values.proxyEnabled);\n                      }}\n                    />\n                  </div>\n                </div>\n                {values.proxyEnabled && (\n                  <>\n                    <div className=\"ml-4 mr-2\">\n                      <div className=\"form-row\">\n                        <label\n                          htmlFor=\"proxyHostname\"\n                          className=\"checkbox-label\"\n                        >\n                          {intl.formatMessage(messages.proxyHostname)}\n                        </label>\n                        <div className=\"form-input-area\">\n                          <div className=\"form-input-field\">\n                            <Field\n                              id=\"proxyHostname\"\n                              name=\"proxyHostname\"\n                              type=\"text\"\n                            />\n                          </div>\n                          {errors.proxyHostname &&\n                            touched.proxyHostname &&\n                            typeof errors.proxyHostname === 'string' && (\n                              <div className=\"error\">\n                                {errors.proxyHostname}\n                              </div>\n                            )}\n                        </div>\n                      </div>\n                      <div className=\"form-row\">\n                        <label htmlFor=\"proxyPort\" className=\"checkbox-label\">\n                          {intl.formatMessage(messages.proxyPort)}\n                        </label>\n                        <div className=\"form-input-area\">\n                          <Field\n                            id=\"proxyPort\"\n                            name=\"proxyPort\"\n                            type=\"text\"\n                            inputMode=\"numeric\"\n                            className=\"short\"\n                          />\n                          {errors.proxyPort &&\n                            touched.proxyPort &&\n                            typeof errors.proxyPort === 'string' && (\n                              <div className=\"error\">{errors.proxyPort}</div>\n                            )}\n                        </div>\n                      </div>\n                      <div className=\"form-row\">\n                        <label htmlFor=\"proxySsl\" className=\"checkbox-label\">\n                          {intl.formatMessage(messages.proxySsl)}\n                        </label>\n                        <div className=\"form-input-area\">\n                          <Field\n                            type=\"checkbox\"\n                            id=\"proxySsl\"\n                            name=\"proxySsl\"\n                            onChange={() => {\n                              setFieldValue('proxySsl', !values.proxySsl);\n                            }}\n                          />\n                        </div>\n                      </div>\n                      <div className=\"form-row\">\n                        <label htmlFor=\"proxyUser\" className=\"checkbox-label\">\n                          {intl.formatMessage(messages.proxyUser)}\n                        </label>\n                        <div className=\"form-input-area\">\n                          <div className=\"form-input-field\">\n                            <Field\n                              id=\"proxyUser\"\n                              name=\"proxyUser\"\n                              type=\"text\"\n                            />\n                          </div>\n                          {errors.proxyUser &&\n                            touched.proxyUser &&\n                            typeof errors.proxyUser === 'string' && (\n                              <div className=\"error\">{errors.proxyUser}</div>\n                            )}\n                        </div>\n                      </div>\n                      <div className=\"form-row\">\n                        <label\n                          htmlFor=\"proxyPassword\"\n                          className=\"checkbox-label\"\n                        >\n                          {intl.formatMessage(messages.proxyPassword)}\n                        </label>\n                        <div className=\"form-input-area\">\n                          <div className=\"form-input-field\">\n                            <Field\n                              id=\"proxyPassword\"\n                              name=\"proxyPassword\"\n                              type=\"password\"\n                            />\n                          </div>\n                          {errors.proxyPassword &&\n                            touched.proxyPassword &&\n                            typeof errors.proxyPassword === 'string' && (\n                              <div className=\"error\">\n                                {errors.proxyPassword}\n                              </div>\n                            )}\n                        </div>\n                      </div>\n                      <div className=\"form-row\">\n                        <label\n                          htmlFor=\"proxyBypassFilter\"\n                          className=\"checkbox-label\"\n                        >\n                          {intl.formatMessage(messages.proxyBypassFilter)}\n                          <span className=\"label-tip\">\n                            {intl.formatMessage(messages.proxyBypassFilterTip)}\n                          </span>\n                        </label>\n                        <div className=\"form-input-area\">\n                          <div className=\"form-input-field\">\n                            <Field\n                              id=\"proxyBypassFilter\"\n                              name=\"proxyBypassFilter\"\n                              type=\"text\"\n                            />\n                          </div>\n                          {errors.proxyBypassFilter &&\n                            touched.proxyBypassFilter &&\n                            typeof errors.proxyBypassFilter === 'string' && (\n                              <div className=\"error\">\n                                {errors.proxyBypassFilter}\n                              </div>\n                            )}\n                        </div>\n                      </div>\n                      <div className=\"form-row\">\n                        <label\n                          htmlFor=\"proxyBypassLocalAddresses\"\n                          className=\"checkbox-label\"\n                        >\n                          {intl.formatMessage(\n                            messages.proxyBypassLocalAddresses\n                          )}\n                        </label>\n                        <div className=\"form-input-area\">\n                          <Field\n                            type=\"checkbox\"\n                            id=\"proxyBypassLocalAddresses\"\n                            name=\"proxyBypassLocalAddresses\"\n                            onChange={() => {\n                              setFieldValue(\n                                'proxyBypassLocalAddresses',\n                                !values.proxyBypassLocalAddresses\n                              );\n                            }}\n                          />\n                        </div>\n                      </div>\n                    </div>\n                  </>\n                )}\n                <div className=\"actions\">\n                  <div className=\"flex justify-end\">\n                    <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                      <Button\n                        buttonType=\"primary\"\n                        type=\"submit\"\n                        disabled={isSubmitting || !isValid}\n                      >\n                        <ArrowDownOnSquareIcon />\n                        <span>\n                          {isSubmitting\n                            ? intl.formatMessage(globalMessages.saving)\n                            : intl.formatMessage(globalMessages.save)}\n                        </span>\n                      </Button>\n                    </span>\n                  </div>\n                </div>\n              </Form>\n            );\n          }}\n        </Formik>\n      </div>\n    </>\n  );\n};\n\nexport default SettingsNetwork;\n"
  },
  {
    "path": "src/components/Settings/SettingsNotifications.tsx",
    "content": "import DiscordLogo from '@app/assets/extlogos/discord.svg';\nimport GotifyLogo from '@app/assets/extlogos/gotify.svg';\nimport NtfyLogo from '@app/assets/extlogos/ntfy.svg';\nimport PushbulletLogo from '@app/assets/extlogos/pushbullet.svg';\nimport PushoverLogo from '@app/assets/extlogos/pushover.svg';\nimport SlackLogo from '@app/assets/extlogos/slack.svg';\nimport TelegramLogo from '@app/assets/extlogos/telegram.svg';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport type { SettingsRoute } from '@app/components/Common/SettingsTabs';\nimport SettingsTabs from '@app/components/Common/SettingsTabs';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { BoltIcon, CloudIcon, EnvelopeIcon } from '@heroicons/react/24/solid';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Settings', {\n  notifications: 'Notifications',\n  notificationsettings: 'Notification Settings',\n  notificationAgentSettingsDescription:\n    'Configure and enable notification agents.',\n  email: 'Email',\n  webhook: 'Webhook',\n  webpush: 'Web Push',\n});\n\ntype SettingsNotificationsProps = {\n  children: React.ReactNode;\n};\n\nconst SettingsNotifications = ({ children }: SettingsNotificationsProps) => {\n  const intl = useIntl();\n\n  const settingsRoutes: SettingsRoute[] = [\n    {\n      text: intl.formatMessage(messages.email),\n      content: (\n        <span className=\"flex items-center\">\n          <EnvelopeIcon className=\"mr-2 h-4\" />\n          {intl.formatMessage(messages.email)}\n        </span>\n      ),\n      route: '/settings/notifications/email',\n      regex: /^\\/settings\\/notifications\\/email/,\n    },\n    {\n      text: intl.formatMessage(messages.webpush),\n      content: (\n        <span className=\"flex items-center\">\n          <CloudIcon className=\"mr-2 h-4\" />\n          {intl.formatMessage(messages.webpush)}\n        </span>\n      ),\n      route: '/settings/notifications/webpush',\n      regex: /^\\/settings\\/notifications\\/webpush/,\n    },\n    {\n      text: 'Discord',\n      content: (\n        <span className=\"flex items-center\">\n          <DiscordLogo className=\"mr-2 h-4\" />\n          Discord\n        </span>\n      ),\n      route: '/settings/notifications/discord',\n      regex: /^\\/settings\\/notifications\\/discord/,\n    },\n    {\n      text: 'Gotify',\n      content: (\n        <span className=\"flex items-center\">\n          <GotifyLogo className=\"mr-2 h-4\" />\n          Gotify\n        </span>\n      ),\n      route: '/settings/notifications/gotify',\n      regex: /^\\/settings\\/notifications\\/gotify/,\n    },\n    {\n      text: 'ntfy.sh',\n      content: (\n        <span className=\"flex items-center\">\n          <NtfyLogo className=\"mr-2 h-4\" />\n          ntfy.sh\n        </span>\n      ),\n      route: '/settings/notifications/ntfy',\n      regex: /^\\/settings\\/notifications\\/ntfy/,\n    },\n    {\n      text: 'Pushbullet',\n      content: (\n        <span className=\"flex items-center\">\n          <PushbulletLogo className=\"mr-2 h-4\" />\n          Pushbullet\n        </span>\n      ),\n      route: '/settings/notifications/pushbullet',\n      regex: /^\\/settings\\/notifications\\/pushbullet/,\n    },\n    {\n      text: 'Pushover',\n      content: (\n        <span className=\"flex items-center\">\n          <PushoverLogo className=\"mr-2 h-4\" />\n          Pushover\n        </span>\n      ),\n      route: '/settings/notifications/pushover',\n      regex: /^\\/settings\\/notifications\\/pushover/,\n    },\n    {\n      text: 'Slack',\n      content: (\n        <span className=\"flex items-center\">\n          <SlackLogo className=\"mr-2 h-4\" />\n          Slack\n        </span>\n      ),\n      route: '/settings/notifications/slack',\n      regex: /^\\/settings\\/notifications\\/slack/,\n    },\n    {\n      text: 'Telegram',\n      content: (\n        <span className=\"flex items-center\">\n          <TelegramLogo className=\"mr-2 h-4\" />\n          Telegram\n        </span>\n      ),\n      route: '/settings/notifications/telegram',\n      regex: /^\\/settings\\/notifications\\/telegram/,\n    },\n    {\n      text: intl.formatMessage(messages.webhook),\n      content: (\n        <span className=\"flex items-center\">\n          <BoltIcon className=\"mr-2 h-4\" />\n          {intl.formatMessage(messages.webhook)}\n        </span>\n      ),\n      route: '/settings/notifications/webhook',\n      regex: /^\\/settings\\/notifications\\/webhook/,\n    },\n  ];\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.notifications),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.notificationsettings)}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.notificationAgentSettingsDescription)}\n        </p>\n      </div>\n      <SettingsTabs tabType=\"button\" settingsRoutes={settingsRoutes} />\n      <div className=\"section\">{children}</div>\n    </>\n  );\n};\n\nexport default SettingsNotifications;\n"
  },
  {
    "path": "src/components/Settings/SettingsPlex.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport LibraryItem from '@app/components/Settings/LibraryItem';\nimport SettingsBadge from '@app/components/Settings/SettingsBadge';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { isValidURL } from '@app/utils/urlValidationHelper';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport {\n  ArrowPathIcon,\n  MagnifyingGlassIcon,\n  XMarkIcon,\n} from '@heroicons/react/24/solid';\nimport type { PlexDevice } from '@server/interfaces/api/plexInterfaces';\nimport type { PlexSettings, TautulliSettings } from '@server/lib/settings';\nimport axios from 'axios';\nimport { Field, Formik } from 'formik';\nimport { orderBy } from 'lodash';\nimport { useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Settings', {\n  plex: 'Plex',\n  plexsettings: 'Plex Settings',\n  plexsettingsDescription:\n    'Configure the settings for your Plex server. Seerr scans your Plex libraries to determine content availability.',\n  serverpreset: 'Server',\n  serverLocal: 'local',\n  serverRemote: 'remote',\n  serverSecure: 'secure',\n  serverpresetManualMessage: 'Manual configuration',\n  serverpresetRefreshing: 'Retrieving servers…',\n  serverpresetLoad: 'Press the button to load available servers',\n  toastPlexRefresh: 'Retrieving server list from Plex…',\n  toastPlexRefreshSuccess: 'Plex server list retrieved successfully!',\n  toastPlexRefreshFailure: 'Failed to retrieve Plex server list.',\n  toastPlexConnecting: 'Attempting to connect to Plex…',\n  toastPlexConnectingSuccess: 'Plex connection established successfully!',\n  toastPlexConnectingFailure: 'Failed to connect to Plex.',\n  settingUpPlexDescription:\n    'To set up Plex, you can either enter the details manually or select a server retrieved from <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Press the button to the right of the dropdown to fetch the list of available servers.',\n  hostname: 'Hostname or IP Address',\n  port: 'Port',\n  enablessl: 'Use SSL',\n  plexlibraries: 'Plex Libraries',\n  plexlibrariesDescription:\n    'The libraries Seerr scans for titles. Set up and save your Plex connection settings, then click the button below if no libraries are listed.',\n  scanning: 'Syncing…',\n  scan: 'Sync Libraries',\n  manualscan: 'Manual Library Scan',\n  manualscanDescription:\n    \"Normally, this will only be run once every 24 hours. Seerr 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!\",\n  notrunning: 'Not Running',\n  currentlibrary: 'Current Library: {name}',\n  librariesRemaining: 'Libraries Remaining: {count}',\n  startscan: 'Start Scan',\n  cancelscan: 'Cancel Scan',\n  validationHostnameRequired: 'You must provide a valid hostname or IP address',\n  validationPortRequired: 'You must provide a valid port number',\n  webAppUrl: '<WebAppLink>Web App</WebAppLink> URL',\n  webAppUrlTip:\n    'Optionally direct users to the web app on your server instead of the \"hosted\" web app',\n  tautulliSettings: 'Tautulli Settings',\n  tautulliSettingsDescription:\n    'Optionally configure the settings for your Tautulli server. Seerr fetches watch history data for your Plex media from Tautulli.',\n  urlBase: 'URL Base',\n  tautulliApiKey: 'API Key',\n  externalUrl: 'External URL',\n  validationApiKey: 'You must provide an API key',\n  validationUrl: 'You must provide a valid URL',\n  validationUrlTrailingSlash: 'URL must not end in a trailing slash',\n  validationUrlBaseLeadingSlash: 'URL base must have a leading slash',\n  validationUrlBaseTrailingSlash: 'URL base must not end in a trailing slash',\n  toastTautulliSettingsSuccess: 'Tautulli settings saved successfully!',\n  toastTautulliSettingsFailure:\n    'Something went wrong while saving Tautulli settings.',\n});\n\ninterface Library {\n  id: string;\n  name: string;\n  enabled: boolean;\n}\n\ninterface SyncStatus {\n  running: boolean;\n  progress: number;\n  total: number;\n  currentLibrary?: Library;\n  libraries: Library[];\n}\n\ninterface PresetServerDisplay {\n  name: string;\n  ssl: boolean;\n  uri: string;\n  address: string;\n  port: number;\n  local: boolean;\n  status?: boolean;\n  message?: string;\n}\ninterface SettingsPlexProps {\n  onComplete?: () => void;\n}\n\nconst SettingsPlex = ({ onComplete }: SettingsPlexProps) => {\n  const [isSyncing, setIsSyncing] = useState(false);\n  const [isRefreshingPresets, setIsRefreshingPresets] = useState(false);\n  const [availableServers, setAvailableServers] = useState<PlexDevice[] | null>(\n    null\n  );\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<PlexSettings>('/api/v1/settings/plex');\n  const { data: dataTautulli, mutate: revalidateTautulli } =\n    useSWR<TautulliSettings>('/api/v1/settings/tautulli');\n  const { data: dataSync, mutate: revalidateSync } = useSWR<SyncStatus>(\n    '/api/v1/settings/plex/sync',\n    {\n      refreshInterval: 1000,\n    }\n  );\n  const intl = useIntl();\n  const { addToast, removeToast } = useToasts();\n\n  const PlexSettingsSchema = Yup.object().shape({\n    hostname: Yup.string()\n      .nullable()\n      .required(intl.formatMessage(messages.validationHostnameRequired)),\n    port: Yup.number()\n      .nullable()\n      .required(intl.formatMessage(messages.validationPortRequired)),\n    webAppUrl: Yup.string()\n      .nullable()\n      .url(intl.formatMessage(messages.validationUrl)),\n  });\n\n  const TautulliSettingsSchema = Yup.object().shape(\n    {\n      tautulliHostname: Yup.string()\n        .when(['tautulliPort', 'tautulliApiKey'], {\n          is: (value: unknown) => !!value,\n          then: Yup.string()\n            .nullable()\n            .required(intl.formatMessage(messages.validationHostnameRequired)),\n          otherwise: Yup.string().nullable(),\n        })\n        .matches(\n          /^(([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,\n          intl.formatMessage(messages.validationHostnameRequired)\n        ),\n      tautulliPort: Yup.number().when(['tautulliHostname', 'tautulliApiKey'], {\n        is: (value: unknown) => !!value,\n        then: Yup.number()\n          .typeError(intl.formatMessage(messages.validationPortRequired))\n          .nullable()\n          .required(intl.formatMessage(messages.validationPortRequired)),\n        otherwise: Yup.number()\n          .typeError(intl.formatMessage(messages.validationPortRequired))\n          .nullable(),\n      }),\n      tautulliUrlBase: Yup.string()\n        .test(\n          'leading-slash',\n          intl.formatMessage(messages.validationUrlBaseLeadingSlash),\n          (value) => !value || value.startsWith('/')\n        )\n        .test(\n          'no-trailing-slash',\n          intl.formatMessage(messages.validationUrlBaseTrailingSlash),\n          (value) => !value || !value.endsWith('/')\n        ),\n      tautulliApiKey: Yup.string().when(['tautulliHostname', 'tautulliPort'], {\n        is: (value: unknown) => !!value,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationApiKey)),\n        otherwise: Yup.string().nullable(),\n      }),\n      tautulliExternalUrl: Yup.string()\n        .test(\n          'valid-url',\n          intl.formatMessage(messages.validationUrl),\n          isValidURL\n        )\n        .test(\n          'no-trailing-slash',\n          intl.formatMessage(messages.validationUrlTrailingSlash),\n          (value) => !value || !value.endsWith('/')\n        ),\n    },\n    [\n      ['tautulliHostname', 'tautulliPort'],\n      ['tautulliHostname', 'tautulliApiKey'],\n      ['tautulliPort', 'tautulliApiKey'],\n    ]\n  );\n\n  const activeLibraries =\n    data?.libraries\n      .filter((library) => library.enabled)\n      .map((library) => library.id) ?? [];\n\n  const availablePresets = useMemo(() => {\n    const finalPresets: PresetServerDisplay[] = [];\n    availableServers?.forEach((dev) => {\n      dev.connection.forEach((conn) =>\n        finalPresets.push({\n          name: dev.name,\n          ssl: conn.protocol === 'https',\n          uri: conn.uri,\n          address: conn.address,\n          port: conn.port,\n          local: conn.local,\n          status: conn.status === 200,\n          message: conn.message,\n        })\n      );\n    });\n\n    return orderBy(finalPresets, ['status', 'ssl'], ['desc', 'desc']);\n  }, [availableServers]);\n\n  const syncLibraries = async () => {\n    setIsSyncing(true);\n\n    const params: { sync: boolean; enable?: string } = {\n      sync: true,\n    };\n\n    if (activeLibraries.length > 0) {\n      params.enable = activeLibraries.join(',');\n    }\n\n    await axios.get('/api/v1/settings/plex/library', {\n      params,\n    });\n    setIsSyncing(false);\n    revalidate();\n  };\n\n  const refreshPresetServers = async () => {\n    setIsRefreshingPresets(true);\n    let toastId: string | undefined;\n    try {\n      addToast(\n        intl.formatMessage(messages.toastPlexRefresh),\n        {\n          autoDismiss: false,\n          appearance: 'info',\n        },\n        (id) => {\n          toastId = id;\n        }\n      );\n      const response = await axios.get<PlexDevice[]>(\n        '/api/v1/settings/plex/devices/servers'\n      );\n      if (response.data) {\n        setAvailableServers(response.data);\n      }\n      if (toastId) {\n        removeToast(toastId);\n      }\n      addToast(intl.formatMessage(messages.toastPlexRefreshSuccess), {\n        autoDismiss: true,\n        appearance: 'success',\n      });\n    } catch {\n      if (toastId) {\n        removeToast(toastId);\n      }\n      addToast(intl.formatMessage(messages.toastPlexRefreshFailure), {\n        autoDismiss: true,\n        appearance: 'error',\n      });\n    } finally {\n      setIsRefreshingPresets(false);\n    }\n  };\n\n  const startScan = async () => {\n    await axios.post('/api/v1/settings/plex/sync', {\n      start: true,\n    });\n    revalidateSync();\n  };\n\n  const cancelScan = async () => {\n    await axios.post('/api/v1/settings/plex/sync', {\n      cancel: true,\n    });\n    revalidateSync();\n  };\n\n  const toggleLibrary = async (libraryId: string) => {\n    setIsSyncing(true);\n    if (activeLibraries.includes(libraryId)) {\n      const params: { enable?: string } = {};\n\n      if (activeLibraries.length > 1) {\n        params.enable = activeLibraries\n          .filter((id) => id !== libraryId)\n          .join(',');\n      }\n\n      await axios.get('/api/v1/settings/plex/library', {\n        params,\n      });\n    } else {\n      await axios.get('/api/v1/settings/plex/library', {\n        params: {\n          enable: [...activeLibraries, libraryId].join(','),\n        },\n      });\n    }\n\n    if (onComplete) {\n      onComplete();\n    }\n    setIsSyncing(false);\n    revalidate();\n  };\n\n  if ((!data || !dataTautulli) && !error) {\n    return <LoadingSpinner />;\n  }\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.plex),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">{intl.formatMessage(messages.plexsettings)}</h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.plexsettingsDescription)}\n        </p>\n        {!!onComplete && (\n          <div className=\"section\">\n            <Alert\n              title={intl.formatMessage(messages.settingUpPlexDescription, {\n                RegisterPlexTVLink: (msg: React.ReactNode) => (\n                  <a\n                    href=\"https://plex.tv\"\n                    className=\"text-white transition duration-300 hover:underline\"\n                    target=\"_blank\"\n                    rel=\"noreferrer\"\n                  >\n                    {msg}\n                  </a>\n                ),\n              })}\n              type=\"info\"\n            />\n          </div>\n        )}\n      </div>\n      <Formik\n        initialValues={{\n          hostname: data?.ip,\n          port: data?.port ?? 32400,\n          useSsl: data?.useSsl,\n          selectedPreset: undefined,\n          webAppUrl: data?.webAppUrl,\n        }}\n        validationSchema={PlexSettingsSchema}\n        validateOnMount={true}\n        onSubmit={async (values) => {\n          let toastId: string | null = null;\n          try {\n            addToast(\n              intl.formatMessage(messages.toastPlexConnecting),\n              {\n                autoDismiss: false,\n                appearance: 'info',\n              },\n              (id) => {\n                toastId = id;\n              }\n            );\n            await axios.post('/api/v1/settings/plex', {\n              ip: values.hostname,\n              port: Number(values.port),\n              useSsl: values.useSsl,\n              webAppUrl: values.webAppUrl,\n            } as PlexSettings);\n\n            syncLibraries();\n\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastPlexConnectingSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            if (toastId) {\n              removeToast(toastId);\n            }\n            addToast(intl.formatMessage(messages.toastPlexConnectingFailure), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          }\n        }}\n      >\n        {({\n          errors,\n          touched,\n          values,\n          handleSubmit,\n          setFieldValue,\n          setValues,\n          isSubmitting,\n          isValid,\n        }) => {\n          return (\n            <form className=\"section\" onSubmit={handleSubmit}>\n              <div className=\"form-row\">\n                <label htmlFor=\"preset\" className=\"text-label\">\n                  {intl.formatMessage(messages.serverpreset)}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <select\n                      id=\"preset\"\n                      name=\"preset\"\n                      value={values.selectedPreset}\n                      disabled={!availableServers || isRefreshingPresets}\n                      className=\"rounded-l-only\"\n                      onChange={async (e) => {\n                        const targPreset =\n                          availablePresets[Number(e.target.value)];\n\n                        if (targPreset) {\n                          setValues({\n                            ...values,\n                            hostname: targPreset.address,\n                            port: targPreset.port,\n                            useSsl: targPreset.ssl,\n                          });\n                        }\n                      }}\n                    >\n                      <option value=\"manual\">\n                        {availableServers || isRefreshingPresets\n                          ? isRefreshingPresets\n                            ? intl.formatMessage(\n                                messages.serverpresetRefreshing\n                              )\n                            : intl.formatMessage(\n                                messages.serverpresetManualMessage\n                              )\n                          : intl.formatMessage(messages.serverpresetLoad)}\n                      </option>\n                      {availablePresets.map((server, index) => (\n                        <option\n                          key={`preset-server-${index}`}\n                          value={index}\n                          disabled={!server.status}\n                        >\n                          {`\n                            ${server.name} (${server.address})\n                            [${\n                              server.local\n                                ? intl.formatMessage(messages.serverLocal)\n                                : intl.formatMessage(messages.serverRemote)\n                            }]${\n                              server.ssl\n                                ? ` [${intl.formatMessage(\n                                    messages.serverSecure\n                                  )}]`\n                                : ''\n                            }\n                            ${server.status ? '' : '(' + server.message + ')'}\n                          `}\n                        </option>\n                      ))}\n                    </select>\n                    <button\n                      onClick={(e) => {\n                        e.preventDefault();\n                        refreshPresetServers();\n                      }}\n                      className=\"input-action\"\n                    >\n                      <ArrowPathIcon\n                        className={isRefreshingPresets ? 'animate-spin' : ''}\n                        style={{ animationDirection: 'reverse' }}\n                      />\n                    </button>\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"hostname\" className=\"text-label\">\n                  {intl.formatMessage(messages.hostname)}\n                  <span className=\"label-required\">*</span>\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-gray-100 sm:text-sm\">\n                      {values.useSsl ? 'https://' : 'http://'}\n                    </span>\n                    <Field\n                      type=\"text\"\n                      inputMode=\"url\"\n                      id=\"hostname\"\n                      name=\"hostname\"\n                      className=\"rounded-r-only\"\n                    />\n                  </div>\n                  {errors.hostname &&\n                    touched.hostname &&\n                    typeof errors.hostname === 'string' && (\n                      <div className=\"error\">{errors.hostname}</div>\n                    )}\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"port\" className=\"text-label\">\n                  {intl.formatMessage(messages.port)}\n                  <span className=\"label-required\">*</span>\n                </label>\n                <div className=\"form-input-area\">\n                  <Field\n                    type=\"text\"\n                    inputMode=\"numeric\"\n                    id=\"port\"\n                    name=\"port\"\n                    className=\"short\"\n                  />\n                  {errors.port &&\n                    touched.port &&\n                    typeof errors.port === 'string' && (\n                      <div className=\"error\">{errors.port}</div>\n                    )}\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"ssl\" className=\"checkbox-label\">\n                  {intl.formatMessage(messages.enablessl)}\n                </label>\n                <div className=\"form-input-area\">\n                  <Field\n                    type=\"checkbox\"\n                    id=\"useSsl\"\n                    name=\"useSsl\"\n                    onChange={() => {\n                      setFieldValue('useSsl', !values.useSsl);\n                    }}\n                  />\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"webAppUrl\" className=\"text-label\">\n                  {intl.formatMessage(messages.webAppUrl, {\n                    WebAppLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://support.plex.tv/articles/200288666-opening-plex-web-app/\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                  })}\n                  <SettingsBadge badgeType=\"advanced\" className=\"ml-2\" />\n                  <span className=\"label-tip\">\n                    {intl.formatMessage(messages.webAppUrlTip)}\n                  </span>\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <Field\n                      type=\"text\"\n                      inputMode=\"url\"\n                      id=\"webAppUrl\"\n                      name=\"webAppUrl\"\n                      placeholder=\"https://app.plex.tv/desktop\"\n                    />\n                  </div>\n                  {errors.webAppUrl &&\n                    touched.webAppUrl &&\n                    typeof errors.webAppUrl === 'string' && (\n                      <div className=\"error\">{errors.webAppUrl}</div>\n                    )}\n                </div>\n              </div>\n              <div className=\"actions\">\n                <div className=\"flex justify-end\">\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"primary\"\n                      type=\"submit\"\n                      disabled={isSubmitting || !isValid}\n                    >\n                      <ArrowDownOnSquareIcon />\n                      <span>\n                        {isSubmitting\n                          ? intl.formatMessage(globalMessages.saving)\n                          : intl.formatMessage(globalMessages.save)}\n                      </span>\n                    </Button>\n                  </span>\n                </div>\n              </div>\n            </form>\n          );\n        }}\n      </Formik>\n      <div className=\"mb-6 mt-10\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.plexlibraries)}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.plexlibrariesDescription)}\n        </p>\n      </div>\n      <div className=\"section\">\n        <Button\n          onClick={() => syncLibraries()}\n          disabled={isSyncing || !data?.ip || !data?.port}\n        >\n          <ArrowPathIcon\n            className={isSyncing ? 'animate-spin' : ''}\n            style={{ animationDirection: 'reverse' }}\n          />\n          <span>\n            {isSyncing\n              ? intl.formatMessage(messages.scanning)\n              : intl.formatMessage(messages.scan)}\n          </span>\n        </Button>\n        <ul className=\"mt-6 grid grid-cols-1 gap-5 sm:grid-cols-2 sm:gap-6 lg:grid-cols-4\">\n          {data?.libraries.map((library) => (\n            <LibraryItem\n              name={library.name}\n              isEnabled={library.enabled}\n              key={`setting-library-${library.id}`}\n              onToggle={() => toggleLibrary(library.id)}\n            />\n          ))}\n        </ul>\n      </div>\n      <div className=\"mb-6 mt-10\">\n        <h3 className=\"heading\">{intl.formatMessage(messages.manualscan)}</h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.manualscanDescription)}\n        </p>\n      </div>\n      <div className=\"section\">\n        <div className=\"rounded-md bg-gray-800 p-4\">\n          <div className=\"relative mb-6 h-8 w-full overflow-hidden rounded-full bg-gray-600\">\n            {dataSync?.running && (\n              <div\n                className=\"h-8 bg-indigo-600 transition-all duration-200 ease-in-out\"\n                style={{\n                  width: `${Math.round(\n                    (dataSync.progress / dataSync.total) * 100\n                  )}%`,\n                }}\n              />\n            )}\n            <div className=\"absolute inset-0 flex h-8 w-full items-center justify-center text-sm\">\n              <span>\n                {dataSync?.running\n                  ? `${dataSync.progress} of ${dataSync.total}`\n                  : 'Not running'}\n              </span>\n            </div>\n          </div>\n          <div className=\"flex w-full flex-col sm:flex-row\">\n            {dataSync?.running && (\n              <>\n                {dataSync.currentLibrary && (\n                  <div className=\"mb-2 mr-0 flex items-center sm:mb-0 sm:mr-2\">\n                    <Badge>\n                      {intl.formatMessage(messages.currentlibrary, {\n                        name: dataSync.currentLibrary.name,\n                      })}\n                    </Badge>\n                  </div>\n                )}\n                <div className=\"flex items-center\">\n                  <Badge badgeType=\"warning\">\n                    {intl.formatMessage(messages.librariesRemaining, {\n                      count: dataSync.currentLibrary\n                        ? dataSync.libraries.slice(\n                            dataSync.libraries.findIndex(\n                              (library) =>\n                                library.id === dataSync.currentLibrary?.id\n                            ) + 1\n                          ).length\n                        : 0,\n                    })}\n                  </Badge>\n                </div>\n              </>\n            )}\n            <div className=\"flex-1 text-right\">\n              {!dataSync?.running ? (\n                <Button\n                  buttonType=\"warning\"\n                  onClick={() => startScan()}\n                  disabled={isSyncing || !activeLibraries.length}\n                >\n                  <MagnifyingGlassIcon />\n                  <span>{intl.formatMessage(messages.startscan)}</span>\n                </Button>\n              ) : (\n                <Button buttonType=\"danger\" onClick={() => cancelScan()}>\n                  <XMarkIcon />\n                  <span>{intl.formatMessage(messages.cancelscan)}</span>\n                </Button>\n              )}\n            </div>\n          </div>\n        </div>\n      </div>\n      {!onComplete && (\n        <>\n          <div className=\"mb-6 mt-10\">\n            <h3 className=\"heading\">\n              {intl.formatMessage(messages.tautulliSettings)}\n            </h3>\n            <p className=\"description\">\n              {intl.formatMessage(messages.tautulliSettingsDescription)}\n            </p>\n          </div>\n          <Formik\n            initialValues={{\n              tautulliHostname: dataTautulli?.hostname,\n              tautulliPort: dataTautulli?.port ?? 8181,\n              tautulliUseSsl: dataTautulli?.useSsl,\n              tautulliUrlBase: dataTautulli?.urlBase,\n              tautulliApiKey: dataTautulli?.apiKey,\n              tautulliExternalUrl: dataTautulli?.externalUrl,\n            }}\n            validationSchema={TautulliSettingsSchema}\n            onSubmit={async (values) => {\n              try {\n                await axios.post('/api/v1/settings/tautulli', {\n                  hostname: values.tautulliHostname,\n                  port: Number(values.tautulliPort),\n                  useSsl: values.tautulliUseSsl,\n                  urlBase: values.tautulliUrlBase,\n                  apiKey: values.tautulliApiKey,\n                  externalUrl: values.tautulliExternalUrl,\n                } as TautulliSettings);\n\n                addToast(\n                  intl.formatMessage(messages.toastTautulliSettingsSuccess),\n                  {\n                    autoDismiss: true,\n                    appearance: 'success',\n                  }\n                );\n              } catch {\n                addToast(\n                  intl.formatMessage(messages.toastTautulliSettingsFailure),\n                  {\n                    autoDismiss: true,\n                    appearance: 'error',\n                  }\n                );\n              } finally {\n                revalidateTautulli();\n              }\n            }}\n          >\n            {({\n              errors,\n              touched,\n              values,\n              handleSubmit,\n              setFieldValue,\n              isSubmitting,\n              isValid,\n            }) => {\n              return (\n                <form className=\"section\" onSubmit={handleSubmit}>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"tautulliHostname\" className=\"text-label\">\n                      {intl.formatMessage(messages.hostname)}\n                      <span className=\"label-required\">*</span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-gray-100 sm:text-sm\">\n                          {values.tautulliUseSsl ? 'https://' : 'http://'}\n                        </span>\n                        <Field\n                          type=\"text\"\n                          inputMode=\"url\"\n                          id=\"tautulliHostname\"\n                          name=\"tautulliHostname\"\n                          className=\"rounded-r-only\"\n                        />\n                      </div>\n                      {errors.tautulliHostname &&\n                        touched.tautulliHostname &&\n                        typeof errors.tautulliHostname === 'string' && (\n                          <div className=\"error\">{errors.tautulliHostname}</div>\n                        )}\n                    </div>\n                  </div>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"tautulliPort\" className=\"text-label\">\n                      {intl.formatMessage(messages.port)}\n                      <span className=\"label-required\">*</span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <Field\n                        type=\"text\"\n                        inputMode=\"numeric\"\n                        id=\"tautulliPort\"\n                        name=\"tautulliPort\"\n                        className=\"short\"\n                        autoComplete=\"off\"\n                        data-form-type=\"other\"\n                        data-1pignore=\"true\"\n                        data-lpignore=\"true\"\n                        data-bwignore=\"true\"\n                      />\n                      {errors.tautulliPort &&\n                        touched.tautulliPort &&\n                        typeof errors.tautulliPort === 'string' && (\n                          <div className=\"error\">{errors.tautulliPort}</div>\n                        )}\n                    </div>\n                  </div>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"tautulliUseSsl\" className=\"checkbox-label\">\n                      {intl.formatMessage(messages.enablessl)}\n                    </label>\n                    <div className=\"form-input-area\">\n                      <Field\n                        type=\"checkbox\"\n                        id=\"tautulliUseSsl\"\n                        name=\"tautulliUseSsl\"\n                        onChange={() => {\n                          setFieldValue(\n                            'tautulliUseSsl',\n                            !values.tautulliUseSsl\n                          );\n                        }}\n                      />\n                    </div>\n                  </div>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"tautulliUrlBase\" className=\"text-label\">\n                      {intl.formatMessage(messages.urlBase)}\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <Field\n                          type=\"text\"\n                          inputMode=\"url\"\n                          id=\"tautulliUrlBase\"\n                          name=\"tautulliUrlBase\"\n                          autoComplete=\"off\"\n                          data-form-type=\"other\"\n                          data-1pignore=\"true\"\n                          data-lpignore=\"true\"\n                          data-bwignore=\"true\"\n                        />\n                      </div>\n                      {errors.tautulliUrlBase &&\n                        touched.tautulliUrlBase &&\n                        typeof errors.tautulliUrlBase === 'string' && (\n                          <div className=\"error\">{errors.tautulliUrlBase}</div>\n                        )}\n                    </div>\n                  </div>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"tautulliApiKey\" className=\"text-label\">\n                      {intl.formatMessage(messages.tautulliApiKey)}\n                      <span className=\"label-required\">*</span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <SensitiveInput\n                          as=\"field\"\n                          id=\"tautulliApiKey\"\n                          name=\"tautulliApiKey\"\n                        />\n                      </div>\n                      {errors.tautulliApiKey &&\n                        touched.tautulliApiKey &&\n                        typeof errors.tautulliApiKey === 'string' && (\n                          <div className=\"error\">{errors.tautulliApiKey}</div>\n                        )}\n                    </div>\n                  </div>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"tautulliExternalUrl\" className=\"text-label\">\n                      {intl.formatMessage(messages.externalUrl)}\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <Field\n                          type=\"text\"\n                          inputMode=\"url\"\n                          id=\"tautulliExternalUrl\"\n                          name=\"tautulliExternalUrl\"\n                          autoComplete=\"off\"\n                          data-form-type=\"other\"\n                          data-1pignore=\"true\"\n                          data-lpignore=\"true\"\n                          data-bwignore=\"true\"\n                        />\n                      </div>\n                      {errors.tautulliExternalUrl &&\n                        touched.tautulliExternalUrl && (\n                          <div className=\"error\">\n                            {errors.tautulliExternalUrl}\n                          </div>\n                        )}\n                    </div>\n                  </div>\n                  <div className=\"actions\">\n                    <div className=\"flex justify-end\">\n                      <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                        <Button\n                          buttonType=\"primary\"\n                          type=\"submit\"\n                          disabled={isSubmitting || !isValid}\n                        >\n                          <ArrowDownOnSquareIcon />\n                          <span>\n                            {isSubmitting\n                              ? intl.formatMessage(globalMessages.saving)\n                              : intl.formatMessage(globalMessages.save)}\n                          </span>\n                        </Button>\n                      </span>\n                    </div>\n                  </div>\n                </form>\n              );\n            }}\n          </Formik>\n        </>\n      )}\n    </>\n  );\n};\n\nexport default SettingsPlex;\n"
  },
  {
    "path": "src/components/Settings/SettingsServices.tsx",
    "content": "import RadarrLogo from '@app/assets/services/radarr.svg';\nimport SonarrLogo from '@app/assets/services/sonarr.svg';\nimport Alert from '@app/components/Common/Alert';\nimport Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport Modal from '@app/components/Common/Modal';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport OverrideRuleModal from '@app/components/Settings/OverrideRule/OverrideRuleModal';\nimport OverrideRuleTiles from '@app/components/Settings/OverrideRule/OverrideRuleTiles';\nimport RadarrModal from '@app/components/Settings/RadarrModal';\nimport SonarrModal from '@app/components/Settings/SonarrModal';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport { PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/solid';\nimport type OverrideRule from '@server/entity/OverrideRule';\nimport type { OverrideRuleResultsResponse } from '@server/interfaces/api/overrideRuleInterfaces';\nimport type { RadarrSettings, SonarrSettings } from '@server/lib/settings';\nimport axios from 'axios';\nimport { Fragment, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR, { mutate } from 'swr';\n\nconst messages = defineMessages('components.Settings', {\n  services: 'Services',\n  radarrsettings: 'Radarr Settings',\n  sonarrsettings: 'Sonarr Settings',\n  serviceSettingsDescription:\n    '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.',\n  deleteserverconfirm: 'Are you sure you want to delete this server?',\n  ssl: 'SSL',\n  default: 'Default',\n  default4k: 'Default 4K',\n  is4k: '4K',\n  address: 'Address',\n  activeProfile: 'Active Profile',\n  addradarr: 'Add Radarr Server',\n  addsonarr: 'Add Sonarr Server',\n  noDefaultServer:\n    'At least one {serverType} server must be marked as default in order for {mediaType} requests to be processed.',\n  noDefaultNon4kServer:\n    '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 <strong>NOT</strong> be designated as a 4K server.',\n  noDefault4kServer:\n    'A 4K {serverType} server must be marked as default in order to enable users to submit 4K {mediaType} requests.',\n  mediaTypeMovie: 'movie',\n  mediaTypeSeries: 'series',\n  deleteServer: 'Delete {serverType} Server',\n  overrideRules: 'Override Rules',\n  overrideRulesDescription:\n    'Override rules allow you to specify properties that will be replaced if a request matches the rule.',\n  addrule: 'New Override Rule',\n});\n\ninterface ServerInstanceProps {\n  name: string;\n  isDefault?: boolean;\n  is4k?: boolean;\n  hostname: string;\n  port: number;\n  isSSL?: boolean;\n  externalUrl?: string;\n  profileName: string;\n  isSonarr?: boolean;\n  onEdit: () => void;\n  onDelete: () => void;\n}\n\nexport interface DVRTestResponse {\n  profiles: {\n    id: number;\n    name: string;\n  }[];\n  rootFolders: {\n    id: number;\n    path: string;\n  }[];\n  tags: {\n    id: number;\n    label: string;\n  }[];\n  urlBase?: string;\n}\n\nexport type RadarrTestResponse = DVRTestResponse;\n\nexport type SonarrTestResponse = DVRTestResponse & {\n  languageProfiles:\n    | {\n        id: number;\n        name: string;\n      }[]\n    | null;\n};\n\nconst ServerInstance = ({\n  name,\n  hostname,\n  port,\n  profileName,\n  is4k = false,\n  isDefault = false,\n  isSSL = false,\n  isSonarr = false,\n  externalUrl,\n  onEdit,\n  onDelete,\n}: ServerInstanceProps) => {\n  const intl = useIntl();\n\n  const internalUrl =\n    (isSSL ? 'https://' : 'http://') + hostname + ':' + String(port);\n  const serviceUrl = externalUrl ?? internalUrl;\n\n  return (\n    <li className=\"col-span-1 rounded-lg bg-gray-800 shadow ring-1 ring-gray-500\">\n      <div className=\"flex w-full items-center justify-between space-x-6 p-6\">\n        <div className=\"flex-1 truncate\">\n          <div className=\"mb-2 flex items-center space-x-2\">\n            <h3 className=\"truncate font-medium leading-5 text-white\">\n              <a\n                href={serviceUrl}\n                target=\"_blank\"\n                rel=\"noopener noreferrer\"\n                className=\"transition duration-300 hover:text-white hover:underline\"\n              >\n                {name}\n              </a>\n            </h3>\n            {isDefault && !is4k && (\n              <Badge>{intl.formatMessage(messages.default)}</Badge>\n            )}\n            {isDefault && is4k && (\n              <Badge>{intl.formatMessage(messages.default4k)}</Badge>\n            )}\n            {!isDefault && is4k && (\n              <Badge badgeType=\"warning\">\n                {intl.formatMessage(messages.is4k)}\n              </Badge>\n            )}\n            {isSSL && (\n              <Badge badgeType=\"success\">\n                {intl.formatMessage(messages.ssl)}\n              </Badge>\n            )}\n          </div>\n          <p className=\"mt-1 truncate text-sm leading-5 text-gray-300\">\n            <span className=\"mr-2 font-bold\">\n              {intl.formatMessage(messages.address)}\n            </span>\n            <a\n              href={internalUrl}\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"transition duration-300 hover:text-white hover:underline\"\n            >\n              {internalUrl}\n            </a>\n          </p>\n          <p className=\"mt-1 truncate text-sm leading-5 text-gray-300\">\n            <span className=\"mr-2 font-bold\">\n              {intl.formatMessage(messages.activeProfile)}\n            </span>\n            {profileName}\n          </p>\n        </div>\n        <a\n          href={serviceUrl}\n          target=\"_blank\"\n          rel=\"noopener noreferrer\"\n          className=\"opacity-50 hover:opacity-100\"\n        >\n          {isSonarr ? (\n            <SonarrLogo className=\"h-10 w-10 flex-shrink-0\" />\n          ) : (\n            <RadarrLogo className=\"h-10 w-10 flex-shrink-0\" />\n          )}\n        </a>\n      </div>\n      <div className=\"border-t border-gray-500\">\n        <div className=\"-mt-px flex\">\n          <div className=\"flex w-0 flex-1 border-r border-gray-500\">\n            <button\n              onClick={() => onEdit()}\n              className=\"focus:ring-blue relative -mr-px inline-flex w-0 flex-1 items-center justify-center rounded-bl-lg border border-transparent py-4 text-sm font-medium leading-5 text-gray-200 transition duration-150 ease-in-out hover:text-white focus:z-10 focus:border-gray-500 focus:outline-none\"\n            >\n              <PencilIcon className=\"mr-2 h-5 w-5\" />\n              <span>{intl.formatMessage(globalMessages.edit)}</span>\n            </button>\n          </div>\n          <div className=\"-ml-px flex w-0 flex-1\">\n            <button\n              onClick={() => onDelete()}\n              className=\"focus:ring-blue relative inline-flex w-0 flex-1 items-center justify-center rounded-br-lg border border-transparent py-4 text-sm font-medium leading-5 text-gray-200 transition duration-150 ease-in-out hover:text-white focus:z-10 focus:border-gray-500 focus:outline-none\"\n            >\n              <TrashIcon className=\"mr-2 h-5 w-5\" />\n              <span>{intl.formatMessage(globalMessages.delete)}</span>\n            </button>\n          </div>\n        </div>\n      </div>\n    </li>\n  );\n};\n\nconst SettingsServices = () => {\n  const intl = useIntl();\n  const {\n    data: radarrData,\n    error: radarrError,\n    mutate: revalidateRadarr,\n  } = useSWR<RadarrSettings[]>('/api/v1/settings/radarr');\n  const {\n    data: sonarrData,\n    error: sonarrError,\n    mutate: revalidateSonarr,\n  } = useSWR<SonarrSettings[]>('/api/v1/settings/sonarr');\n  const { data: rules, mutate: revalidate } =\n    useSWR<OverrideRuleResultsResponse>('/api/v1/overrideRule');\n  const [editRadarrModal, setEditRadarrModal] = useState<{\n    open: boolean;\n    radarr: RadarrSettings | null;\n  }>({\n    open: false,\n    radarr: null,\n  });\n  const [editSonarrModal, setEditSonarrModal] = useState<{\n    open: boolean;\n    sonarr: SonarrSettings | null;\n  }>({\n    open: false,\n    sonarr: null,\n  });\n  const [deleteServerModal, setDeleteServerModal] = useState<{\n    open: boolean;\n    type: 'radarr' | 'sonarr';\n    serverId: number | null;\n  }>({\n    open: false,\n    type: 'radarr',\n    serverId: null,\n  });\n  const [overrideRuleModal, setOverrideRuleModal] = useState<{\n    open: boolean;\n    rule: OverrideRule | null;\n  }>({\n    open: false,\n    rule: null,\n  });\n\n  const deleteServer = async () => {\n    await axios.delete(\n      `/api/v1/settings/${deleteServerModal.type}/${deleteServerModal.serverId}`\n    );\n    setDeleteServerModal({ open: false, serverId: null, type: 'radarr' });\n    revalidateRadarr();\n    revalidateSonarr();\n    mutate('/api/v1/settings/public');\n  };\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.services),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.radarrsettings)}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.serviceSettingsDescription, {\n            serverType: 'Radarr',\n          })}\n        </p>\n      </div>\n      {editRadarrModal.open && (\n        <RadarrModal\n          radarr={editRadarrModal.radarr}\n          onClose={() => {\n            if (!overrideRuleModal.open)\n              setEditRadarrModal({ open: false, radarr: null });\n          }}\n          onSave={() => {\n            revalidateRadarr();\n            mutate('/api/v1/settings/public');\n            setEditRadarrModal({ open: false, radarr: null });\n          }}\n        />\n      )}\n      {editSonarrModal.open && (\n        <SonarrModal\n          sonarr={editSonarrModal.sonarr}\n          onClose={() => {\n            if (!overrideRuleModal.open)\n              setEditSonarrModal({ open: false, sonarr: null });\n          }}\n          onSave={() => {\n            revalidateSonarr();\n            mutate('/api/v1/settings/public');\n            setEditSonarrModal({ open: false, sonarr: null });\n          }}\n        />\n      )}\n      <Transition\n        as={Fragment}\n        show={deleteServerModal.open}\n        enter=\"transition-opacity ease-in-out duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity ease-in-out duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n      >\n        <Modal\n          okText={intl.formatMessage(globalMessages.delete)}\n          okButtonType=\"danger\"\n          onOk={() => deleteServer()}\n          onCancel={() =>\n            setDeleteServerModal({\n              open: false,\n              serverId: null,\n              type: 'radarr',\n            })\n          }\n          title={intl.formatMessage(messages.deleteServer, {\n            serverType:\n              deleteServerModal.type === 'radarr' ? 'Radarr' : 'Sonarr',\n          })}\n        >\n          {intl.formatMessage(messages.deleteserverconfirm)}\n        </Modal>\n      </Transition>\n      <div className=\"section\">\n        {!radarrData && !radarrError && <LoadingSpinner />}\n        {radarrData && !radarrError && (\n          <>\n            {radarrData.length > 0 &&\n              (!radarrData.some((radarr) => radarr.isDefault) ? (\n                <Alert\n                  title={intl.formatMessage(messages.noDefaultServer, {\n                    serverType: 'Radarr',\n                    mediaType: intl.formatMessage(messages.mediaTypeMovie),\n                  })}\n                />\n              ) : !radarrData.some(\n                  (radarr) => radarr.isDefault && !radarr.is4k\n                ) ? (\n                <Alert\n                  title={intl.formatMessage(messages.noDefaultNon4kServer, {\n                    serverType: 'Radarr',\n                    strong: (msg: React.ReactNode) => (\n                      <strong className=\"font-semibold text-white\">\n                        {msg}\n                      </strong>\n                    ),\n                  })}\n                />\n              ) : (\n                radarrData.some((radarr) => radarr.is4k) &&\n                !radarrData.some(\n                  (radarr) => radarr.isDefault && radarr.is4k\n                ) && (\n                  <Alert\n                    title={intl.formatMessage(messages.noDefault4kServer, {\n                      serverType: 'Radarr',\n                      mediaType: intl.formatMessage(messages.mediaTypeMovie),\n                    })}\n                  />\n                )\n              ))}\n            <ul className=\"grid max-w-6xl grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3\">\n              {radarrData.map((radarr) => (\n                <ServerInstance\n                  key={`radarr-config-${radarr.id}`}\n                  name={radarr.name}\n                  hostname={radarr.hostname}\n                  port={radarr.port}\n                  profileName={radarr.activeProfileName}\n                  isSSL={radarr.useSsl}\n                  isDefault={radarr.isDefault}\n                  is4k={radarr.is4k}\n                  externalUrl={radarr.externalUrl}\n                  onEdit={() => setEditRadarrModal({ open: true, radarr })}\n                  onDelete={() =>\n                    setDeleteServerModal({\n                      open: true,\n                      serverId: radarr.id,\n                      type: 'radarr',\n                    })\n                  }\n                />\n              ))}\n              <li className=\"col-span-1 h-32 rounded-lg border-2 border-dashed border-gray-400 shadow sm:h-44\">\n                <div className=\"flex h-full w-full items-center justify-center\">\n                  <Button\n                    buttonType=\"ghost\"\n                    className=\"mb-3 mt-3\"\n                    onClick={() =>\n                      setEditRadarrModal({ open: true, radarr: null })\n                    }\n                  >\n                    <PlusIcon />\n                    <span>{intl.formatMessage(messages.addradarr)}</span>\n                  </Button>\n                </div>\n              </li>\n            </ul>\n          </>\n        )}\n      </div>\n      <div className=\"mb-6 mt-10\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.sonarrsettings)}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.serviceSettingsDescription, {\n            serverType: 'Sonarr',\n          })}\n        </p>\n      </div>\n      <div className=\"section\">\n        {!sonarrData && !sonarrError && <LoadingSpinner />}\n        {sonarrData && !sonarrError && (\n          <>\n            {sonarrData.length > 0 &&\n              (!sonarrData.some((sonarr) => sonarr.isDefault) ? (\n                <Alert\n                  title={intl.formatMessage(messages.noDefaultServer, {\n                    serverType: 'Sonarr',\n                    mediaType: intl.formatMessage(messages.mediaTypeSeries),\n                  })}\n                />\n              ) : !sonarrData.some(\n                  (sonarr) => sonarr.isDefault && !sonarr.is4k\n                ) ? (\n                <Alert\n                  title={intl.formatMessage(messages.noDefaultNon4kServer, {\n                    serverType: 'Sonarr',\n                    strong: (msg: React.ReactNode) => (\n                      <strong className=\"font-semibold text-white\">\n                        {msg}\n                      </strong>\n                    ),\n                  })}\n                />\n              ) : (\n                sonarrData.some((sonarr) => sonarr.is4k) &&\n                !sonarrData.some(\n                  (sonarr) => sonarr.isDefault && sonarr.is4k\n                ) && (\n                  <Alert\n                    title={intl.formatMessage(messages.noDefault4kServer, {\n                      serverType: 'Sonarr',\n                      mediaType: intl.formatMessage(messages.mediaTypeSeries),\n                    })}\n                  />\n                )\n              ))}\n            <ul className=\"grid max-w-6xl grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3\">\n              {sonarrData.map((sonarr) => (\n                <ServerInstance\n                  key={`sonarr-config-${sonarr.id}`}\n                  name={sonarr.name}\n                  hostname={sonarr.hostname}\n                  port={sonarr.port}\n                  profileName={sonarr.activeProfileName}\n                  isSSL={sonarr.useSsl}\n                  isSonarr\n                  isDefault={sonarr.isDefault}\n                  is4k={sonarr.is4k}\n                  externalUrl={sonarr.externalUrl}\n                  onEdit={() => setEditSonarrModal({ open: true, sonarr })}\n                  onDelete={() =>\n                    setDeleteServerModal({\n                      open: true,\n                      serverId: sonarr.id,\n                      type: 'sonarr',\n                    })\n                  }\n                />\n              ))}\n              <li className=\"col-span-1 h-32 rounded-lg border-2 border-dashed border-gray-400 shadow sm:h-44\">\n                <div className=\"flex h-full w-full items-center justify-center\">\n                  <Button\n                    buttonType=\"ghost\"\n                    onClick={() =>\n                      setEditSonarrModal({ open: true, sonarr: null })\n                    }\n                  >\n                    <PlusIcon />\n                    <span>{intl.formatMessage(messages.addsonarr)}</span>\n                  </Button>\n                </div>\n              </li>\n            </ul>\n          </>\n        )}\n      </div>\n      <div className=\"mb-6 mt-10\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.overrideRules)}\n        </h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.overrideRulesDescription, {\n            serverType: 'Sonarr',\n          })}\n        </p>\n      </div>\n      <div className=\"section\">\n        <ul className=\"grid max-w-6xl grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3\">\n          {rules && radarrData && sonarrData && (\n            <OverrideRuleTiles\n              rules={rules}\n              radarrServices={radarrData}\n              sonarrServices={sonarrData}\n              setOverrideRuleModal={setOverrideRuleModal}\n              revalidate={revalidate}\n            />\n          )}\n          <li className=\"min-h-[8rem] rounded-lg border-2 border-dashed border-gray-400 shadow sm:min-h-[11rem]\">\n            <div className=\"flex h-full w-full items-center justify-center\">\n              <Button\n                buttonType=\"ghost\"\n                disabled={!radarrData?.length && !sonarrData?.length}\n                onClick={() =>\n                  setOverrideRuleModal({\n                    open: true,\n                    rule: null,\n                  })\n                }\n              >\n                <PlusIcon />\n                <span>{intl.formatMessage(messages.addrule)}</span>\n              </Button>\n            </div>\n          </li>\n        </ul>\n      </div>\n      {overrideRuleModal.open && radarrData && sonarrData && (\n        <OverrideRuleModal\n          rule={overrideRuleModal.rule}\n          onClose={() => {\n            setOverrideRuleModal({\n              open: false,\n              rule: null,\n            });\n            revalidate();\n          }}\n          radarrServices={radarrData}\n          sonarrServices={sonarrData}\n        />\n      )}\n    </>\n  );\n};\n\nexport default SettingsServices;\n"
  },
  {
    "path": "src/components/Settings/SettingsUsers/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LabeledCheckbox from '@app/components/Common/LabeledCheckbox';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport PermissionEdit from '@app/components/PermissionEdit';\nimport QuotaSelector from '@app/components/QuotaSelector';\nimport useSettings from '@app/hooks/useSettings';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport { MediaServerType } from '@server/constants/server';\nimport type { MainSettings } from '@server/lib/settings';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\nimport * as yup from 'yup';\n\nconst messages = defineMessages('components.Settings.SettingsUsers', {\n  users: 'Users',\n  userSettings: 'User Settings',\n  userSettingsDescription: 'Configure global and default user settings.',\n  toastSettingsSuccess: 'User settings saved successfully!',\n  toastSettingsFailure: 'Something went wrong while saving settings.',\n  loginMethods: 'Login Methods',\n  loginMethodsTip: 'Configure login methods for users.',\n  localLogin: 'Enable Local Sign-In',\n  localLoginTip:\n    'Allow users to sign in using their email address and password',\n  mediaServerLogin: 'Enable {mediaServerName} Sign-In',\n  mediaServerLoginTip:\n    'Allow users to sign in using their {mediaServerName} account',\n  atLeastOneAuth: 'At least one authentication method must be selected.',\n  newPlexLogin: 'Enable New {mediaServerName} Sign-In',\n  newPlexLoginTip:\n    'Allow {mediaServerName} users to sign in without first being imported',\n  movieRequestLimitLabel: 'Global Movie Request Limit',\n  tvRequestLimitLabel: 'Global Series Request Limit',\n  defaultPermissions: 'Default Permissions',\n  defaultPermissionsTip: 'Initial permissions assigned to new users',\n});\n\nconst SettingsUsers = () => {\n  const { addToast } = useToasts();\n  const intl = useIntl();\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<MainSettings>('/api/v1/settings/main');\n  const settings = useSettings();\n\n  const schema = yup\n    .object()\n    .shape({\n      localLogin: yup.boolean(),\n      mediaServerLogin: yup.boolean(),\n    })\n    .test({\n      name: 'atLeastOneAuth',\n      test: function (values) {\n        const isValid = ['localLogin', 'mediaServerLogin'].some(\n          (field) => !!values[field]\n        );\n\n        if (isValid) return true;\n        return this.createError({\n          path: 'localLogin | mediaServerLogin',\n          message: intl.formatMessage(messages.atLeastOneAuth),\n        });\n      },\n    });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  const mediaServerFormatValues = {\n    mediaServerName:\n      settings.currentSettings.mediaServerType === MediaServerType.JELLYFIN\n        ? 'Jellyfin'\n        : settings.currentSettings.mediaServerType === MediaServerType.EMBY\n          ? 'Emby'\n          : settings.currentSettings.mediaServerType === MediaServerType.PLEX\n            ? 'Plex'\n            : undefined,\n  };\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.users),\n          intl.formatMessage(globalMessages.settings),\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">{intl.formatMessage(messages.userSettings)}</h3>\n        <p className=\"description\">\n          {intl.formatMessage(messages.userSettingsDescription)}\n        </p>\n      </div>\n      <div className=\"section\">\n        <Formik\n          initialValues={{\n            localLogin: data?.localLogin,\n            mediaServerLogin: data?.mediaServerLogin,\n            newPlexLogin: data?.newPlexLogin,\n            movieQuotaLimit: data?.defaultQuotas.movie.quotaLimit ?? 0,\n            movieQuotaDays: data?.defaultQuotas.movie.quotaDays ?? 7,\n            tvQuotaLimit: data?.defaultQuotas.tv.quotaLimit ?? 0,\n            tvQuotaDays: data?.defaultQuotas.tv.quotaDays ?? 7,\n            defaultPermissions: data?.defaultPermissions ?? 0,\n          }}\n          validationSchema={schema}\n          enableReinitialize\n          onSubmit={async (values) => {\n            try {\n              await axios.post('/api/v1/settings/main', {\n                localLogin: values.localLogin,\n                mediaServerLogin: values.mediaServerLogin,\n                newPlexLogin: values.newPlexLogin,\n                defaultQuotas: {\n                  movie: {\n                    quotaLimit: values.movieQuotaLimit,\n                    quotaDays: values.movieQuotaDays,\n                  },\n                  tv: {\n                    quotaLimit: values.tvQuotaLimit,\n                    quotaDays: values.tvQuotaDays,\n                  },\n                },\n                defaultPermissions: values.defaultPermissions,\n              });\n              mutate('/api/v1/settings/public');\n\n              addToast(intl.formatMessage(messages.toastSettingsSuccess), {\n                autoDismiss: true,\n                appearance: 'success',\n              });\n            } catch {\n              addToast(intl.formatMessage(messages.toastSettingsFailure), {\n                autoDismiss: true,\n                appearance: 'error',\n              });\n            } finally {\n              revalidate();\n            }\n          }}\n        >\n          {({ isSubmitting, isValid, values, errors, setFieldValue }) => {\n            return (\n              <Form className=\"section\">\n                <div\n                  role=\"group\"\n                  aria-labelledby=\"group-label\"\n                  className=\"form-group\"\n                >\n                  <div className=\"form-row\">\n                    <span id=\"group-label\" className=\"group-label\">\n                      {intl.formatMessage(messages.loginMethods)}\n                      <span className=\"label-tip\">\n                        {intl.formatMessage(messages.loginMethodsTip)}\n                      </span>\n                      {'localLogin | mediaServerLogin' in errors && (\n                        <span className=\"error\">\n                          {errors['localLogin | mediaServerLogin'] as string}\n                        </span>\n                      )}\n                    </span>\n\n                    <div className=\"form-input-area max-w-lg\">\n                      <LabeledCheckbox\n                        id=\"localLogin\"\n                        label={intl.formatMessage(messages.localLogin)}\n                        description={intl.formatMessage(\n                          messages.localLoginTip,\n                          mediaServerFormatValues\n                        )}\n                        onChange={() =>\n                          setFieldValue('localLogin', !values.localLogin)\n                        }\n                      />\n                      <LabeledCheckbox\n                        id=\"mediaServerLogin\"\n                        className=\"mt-4\"\n                        label={intl.formatMessage(\n                          messages.mediaServerLogin,\n                          mediaServerFormatValues\n                        )}\n                        description={intl.formatMessage(\n                          messages.mediaServerLoginTip,\n                          mediaServerFormatValues\n                        )}\n                        onChange={() =>\n                          setFieldValue(\n                            'mediaServerLogin',\n                            !values.mediaServerLogin\n                          )\n                        }\n                      />\n                    </div>\n                  </div>\n                </div>\n\n                <div className=\"form-row\">\n                  <label htmlFor=\"newPlexLogin\" className=\"checkbox-label\">\n                    {intl.formatMessage(\n                      messages.newPlexLogin,\n                      mediaServerFormatValues\n                    )}\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(\n                        messages.newPlexLoginTip,\n                        mediaServerFormatValues\n                      )}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"newPlexLogin\"\n                      name=\"newPlexLogin\"\n                      onChange={() => {\n                        setFieldValue('newPlexLogin', !values.newPlexLogin);\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"applicationTitle\" className=\"text-label\">\n                    {intl.formatMessage(messages.movieRequestLimitLabel)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <QuotaSelector\n                      onChange={setFieldValue}\n                      dayFieldName=\"movieQuotaDays\"\n                      limitFieldName=\"movieQuotaLimit\"\n                      mediaType=\"movie\"\n                      defaultDays={values.movieQuotaDays}\n                      defaultLimit={values.movieQuotaLimit}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"applicationTitle\" className=\"text-label\">\n                    {intl.formatMessage(messages.tvRequestLimitLabel)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <QuotaSelector\n                      onChange={setFieldValue}\n                      dayFieldName=\"tvQuotaDays\"\n                      limitFieldName=\"tvQuotaLimit\"\n                      mediaType=\"tv\"\n                      defaultDays={values.tvQuotaDays}\n                      defaultLimit={values.tvQuotaLimit}\n                    />\n                  </div>\n                </div>\n                <div\n                  role=\"group\"\n                  aria-labelledby=\"group-label\"\n                  className=\"form-group\"\n                >\n                  <div className=\"form-row\">\n                    <span id=\"group-label\" className=\"group-label\">\n                      {intl.formatMessage(messages.defaultPermissions)}\n                      <span className=\"label-tip\">\n                        {intl.formatMessage(messages.defaultPermissionsTip)}\n                      </span>\n                    </span>\n                    <div className=\"form-input-area\">\n                      <div className=\"max-w-lg\">\n                        <PermissionEdit\n                          currentPermission={values.defaultPermissions}\n                          onUpdate={(newPermissions) =>\n                            setFieldValue('defaultPermissions', newPermissions)\n                          }\n                        />\n                      </div>\n                    </div>\n                  </div>\n                </div>\n                <div className=\"actions\">\n                  <div className=\"flex justify-end\">\n                    <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                      <Button\n                        buttonType=\"primary\"\n                        type=\"submit\"\n                        disabled={isSubmitting || !isValid}\n                      >\n                        <ArrowDownOnSquareIcon />\n                        <span>\n                          {isSubmitting\n                            ? intl.formatMessage(globalMessages.saving)\n                            : intl.formatMessage(globalMessages.save)}\n                        </span>\n                      </Button>\n                    </span>\n                  </div>\n                </div>\n              </Form>\n            );\n          }}\n        </Formik>\n      </div>\n    </>\n  );\n};\n\nexport default SettingsUsers;\n"
  },
  {
    "path": "src/components/Settings/SonarrModal/index.tsx",
    "content": "import Modal from '@app/components/Common/Modal';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport type { SonarrTestResponse } from '@app/components/Settings/SettingsServices';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { isValidURL } from '@app/utils/urlValidationHelper';\nimport { Transition } from '@headlessui/react';\nimport type { SonarrSettings } from '@server/lib/settings';\nimport axios from 'axios';\nimport { Field, Formik } from 'formik';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport type { OnChangeValue } from 'react-select';\nimport Select from 'react-select';\nimport { useToasts } from 'react-toast-notifications';\nimport * as Yup from 'yup';\n\ntype OptionType = {\n  value: number;\n  label: string;\n};\n\nconst messages = defineMessages('components.Settings.SonarrModal', {\n  createsonarr: 'Add New Sonarr Server',\n  create4ksonarr: 'Add New 4K Sonarr Server',\n  editsonarr: 'Edit Sonarr Server',\n  edit4ksonarr: 'Edit 4K Sonarr Server',\n  validationNameRequired: 'You must provide a server name',\n  validationHostnameRequired: 'You must provide a valid hostname or IP address',\n  validationPortRequired: 'You must provide a valid port number',\n  validationApiKeyRequired: 'You must provide an API key',\n  validationRootFolderRequired: 'You must select a root folder',\n  validationProfileRequired: 'You must select a quality profile',\n  validationLanguageProfileRequired: 'You must select a language profile',\n  toastSonarrTestSuccess: 'Sonarr connection established successfully!',\n  toastSonarrTestFailure: 'Failed to connect to Sonarr.',\n  add: 'Add Server',\n  defaultserver: 'Default Server',\n  default4kserver: 'Default 4K Server',\n  servername: 'Server Name',\n  hostname: 'Hostname or IP Address',\n  port: 'Port',\n  ssl: 'Use SSL',\n  apiKey: 'API Key',\n  baseUrl: 'URL Base',\n  qualityprofile: 'Quality Profile',\n  languageprofile: 'Language Profile',\n  rootfolder: 'Root Folder',\n  seriesType: 'Series Type',\n  animeSeriesType: 'Anime Series Type',\n  animequalityprofile: 'Anime Quality Profile',\n  animelanguageprofile: 'Anime Language Profile',\n  animerootfolder: 'Anime Root Folder',\n  seasonfolders: 'Season Folders',\n  server4k: '4K Server',\n  selectQualityProfile: 'Select quality profile',\n  selectRootFolder: 'Select root folder',\n  selectLanguageProfile: 'Select language profile',\n  loadingprofiles: 'Loading quality profiles…',\n  testFirstQualityProfiles: 'Test connection to load quality profiles',\n  loadingrootfolders: 'Loading root folders…',\n  testFirstRootFolders: 'Test connection to load root folders',\n  loadinglanguageprofiles: 'Loading language profiles…',\n  testFirstLanguageProfiles: 'Test connection to load language profiles',\n  loadingTags: 'Loading tags…',\n  testFirstTags: 'Test connection to load tags',\n  syncEnabled: 'Enable Scan',\n  externalUrl: 'External URL',\n  enableSearch: 'Enable Automatic Search',\n  tagRequests: 'Tag Requests',\n  tagRequestsInfo:\n    \"Automatically add an additional tag with the requester's user ID & display name\",\n  validationApplicationUrl: 'You must provide a valid URL',\n  validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',\n  validationBaseUrlLeadingSlash: 'Base URL must have a leading slash',\n  validationBaseUrlTrailingSlash: 'Base URL must not end in a trailing slash',\n  tags: 'Tags',\n  animeTags: 'Anime Tags',\n  notagoptions: 'No tags.',\n  selecttags: 'Select tags',\n  monitorNewItems: 'Monitor New Seasons',\n});\n\ninterface SonarrModalProps {\n  sonarr: SonarrSettings | null;\n  onClose: () => void;\n  onSave: () => void;\n}\n\nconst SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {\n  const intl = useIntl();\n  const initialLoad = useRef(false);\n  const { addToast } = useToasts();\n  const [isValidated, setIsValidated] = useState(sonarr ? true : false);\n  const [isTesting, setIsTesting] = useState(false);\n  const [testResponse, setTestResponse] = useState<SonarrTestResponse>({\n    profiles: [],\n    rootFolders: [],\n    languageProfiles: null,\n    tags: [],\n  });\n\n  const SonarrSettingsSchema = Yup.object().shape({\n    name: Yup.string().required(\n      intl.formatMessage(messages.validationNameRequired)\n    ),\n    hostname: Yup.string().required(\n      intl.formatMessage(messages.validationHostnameRequired)\n    ),\n    port: Yup.number()\n      .nullable()\n      .required(intl.formatMessage(messages.validationPortRequired)),\n    apiKey: Yup.string().required(\n      intl.formatMessage(messages.validationApiKeyRequired)\n    ),\n    rootFolder: Yup.string().required(\n      intl.formatMessage(messages.validationRootFolderRequired)\n    ),\n    activeProfileId: Yup.string().required(\n      intl.formatMessage(messages.validationProfileRequired)\n    ),\n    activeLanguageProfileId: testResponse.languageProfiles\n      ? Yup.number().required(\n          intl.formatMessage(messages.validationLanguageProfileRequired)\n        )\n      : Yup.number(),\n    externalUrl: Yup.string()\n      .test(\n        'valid-url',\n        intl.formatMessage(messages.validationApplicationUrl),\n        isValidURL\n      )\n      .test(\n        'no-trailing-slash',\n        intl.formatMessage(messages.validationApplicationUrlTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n    baseUrl: Yup.string()\n      .test(\n        'leading-slash',\n        intl.formatMessage(messages.validationBaseUrlLeadingSlash),\n        (value) => !value || value.startsWith('/')\n      )\n      .test(\n        'no-trailing-slash',\n        intl.formatMessage(messages.validationBaseUrlTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n  });\n\n  const testConnection = useCallback(\n    async ({\n      hostname,\n      port,\n      apiKey,\n      baseUrl,\n      useSsl = false,\n    }: {\n      hostname: string;\n      port: number;\n      apiKey: string;\n      baseUrl?: string;\n      useSsl?: boolean;\n    }) => {\n      setIsTesting(true);\n      try {\n        const response = await axios.post<SonarrTestResponse>(\n          '/api/v1/settings/sonarr/test',\n          {\n            hostname,\n            apiKey,\n            port: Number(port),\n            baseUrl,\n            useSsl,\n          }\n        );\n\n        setIsValidated(true);\n        setTestResponse(response.data);\n        if (initialLoad.current) {\n          addToast(intl.formatMessage(messages.toastSonarrTestSuccess), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        }\n      } catch {\n        setIsValidated(false);\n        if (initialLoad.current) {\n          addToast(intl.formatMessage(messages.toastSonarrTestFailure), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        }\n      } finally {\n        setIsTesting(false);\n        initialLoad.current = true;\n      }\n    },\n    [addToast, intl]\n  );\n\n  useEffect(() => {\n    if (sonarr) {\n      testConnection({\n        apiKey: sonarr.apiKey,\n        hostname: sonarr.hostname,\n        port: sonarr.port,\n        baseUrl: sonarr.baseUrl,\n        useSsl: sonarr.useSsl,\n      });\n    }\n  }, [sonarr, testConnection]);\n\n  return (\n    <Transition\n      as=\"div\"\n      appear\n      show\n      enter=\"transition-opacity ease-in-out duration-300\"\n      enterFrom=\"opacity-0\"\n      enterTo=\"opacity-100\"\n      leave=\"transition-opacity ease-in-out duration-300\"\n      leaveFrom=\"opacity-100\"\n      leaveTo=\"opacity-0\"\n    >\n      <Formik\n        initialValues={{\n          name: sonarr?.name,\n          hostname: sonarr?.hostname,\n          port: sonarr?.port ?? 8989,\n          ssl: sonarr?.useSsl ?? false,\n          apiKey: sonarr?.apiKey,\n          baseUrl: sonarr?.baseUrl,\n          activeProfileId: sonarr?.activeProfileId,\n          activeLanguageProfileId: sonarr?.activeLanguageProfileId,\n          rootFolder: sonarr?.activeDirectory,\n          seriesType: sonarr?.seriesType,\n          animeSeriesType: sonarr?.animeSeriesType,\n          activeAnimeProfileId: sonarr?.activeAnimeProfileId,\n          activeAnimeLanguageProfileId: sonarr?.activeAnimeLanguageProfileId,\n          activeAnimeRootFolder: sonarr?.activeAnimeDirectory,\n          tags: sonarr?.tags ?? [],\n          animeTags: sonarr?.animeTags ?? [],\n          isDefault: sonarr?.isDefault ?? false,\n          is4k: sonarr?.is4k ?? false,\n          enableSeasonFolders: sonarr?.enableSeasonFolders ?? false,\n          externalUrl: sonarr?.externalUrl,\n          syncEnabled: sonarr?.syncEnabled ?? false,\n          enableSearch: !sonarr?.preventSearch,\n          tagRequests: sonarr?.tagRequests ?? false,\n          monitorNewItems: sonarr?.monitorNewItems ?? 'all',\n        }}\n        validationSchema={SonarrSettingsSchema}\n        onSubmit={async (values) => {\n          try {\n            const profileName = testResponse.profiles.find(\n              (profile) => profile.id === Number(values.activeProfileId)\n            )?.name;\n            const animeProfileName = testResponse.profiles.find(\n              (profile) => profile.id === Number(values.activeAnimeProfileId)\n            )?.name;\n\n            const submission = {\n              name: values.name,\n              hostname: values.hostname,\n              port: Number(values.port),\n              apiKey: values.apiKey,\n              useSsl: values.ssl,\n              baseUrl: values.baseUrl,\n              activeProfileId: Number(values.activeProfileId),\n              activeLanguageProfileId: values.activeLanguageProfileId\n                ? Number(values.activeLanguageProfileId)\n                : undefined,\n              activeProfileName: profileName,\n              activeDirectory: values.rootFolder,\n              seriesType: values.seriesType,\n              animeSeriesType: values.animeSeriesType,\n              activeAnimeProfileId: values.activeAnimeProfileId\n                ? Number(values.activeAnimeProfileId)\n                : undefined,\n              activeAnimeLanguageProfileId: values.activeAnimeLanguageProfileId\n                ? Number(values.activeAnimeLanguageProfileId)\n                : undefined,\n              activeAnimeProfileName: animeProfileName ?? undefined,\n              activeAnimeDirectory: values.activeAnimeRootFolder,\n              tags: values.tags,\n              animeTags: values.animeTags,\n              is4k: values.is4k,\n              isDefault: values.isDefault,\n              enableSeasonFolders: values.enableSeasonFolders,\n              externalUrl: values.externalUrl,\n              syncEnabled: values.syncEnabled,\n              preventSearch: !values.enableSearch,\n              tagRequests: values.tagRequests,\n              monitorNewItems: values.monitorNewItems,\n            };\n            if (!sonarr) {\n              await axios.post('/api/v1/settings/sonarr', submission);\n            } else {\n              await axios.put(\n                `/api/v1/settings/sonarr/${sonarr.id}`,\n                submission\n              );\n            }\n\n            onSave();\n          } catch {\n            // set error here\n          }\n        }}\n      >\n        {({\n          errors,\n          touched,\n          values,\n          handleSubmit,\n          setFieldValue,\n          isSubmitting,\n          isValid,\n        }) => {\n          return (\n            <Modal\n              onCancel={onClose}\n              okButtonType=\"primary\"\n              okText={\n                isSubmitting\n                  ? intl.formatMessage(globalMessages.saving)\n                  : sonarr\n                    ? intl.formatMessage(globalMessages.save)\n                    : intl.formatMessage(messages.add)\n              }\n              secondaryButtonType=\"warning\"\n              secondaryText={\n                isTesting\n                  ? intl.formatMessage(globalMessages.testing)\n                  : intl.formatMessage(globalMessages.test)\n              }\n              onSecondary={() => {\n                if (values.apiKey && values.hostname && values.port) {\n                  testConnection({\n                    apiKey: values.apiKey,\n                    baseUrl: values.baseUrl,\n                    hostname: values.hostname,\n                    port: values.port,\n                    useSsl: values.ssl,\n                  });\n                  if (!values.baseUrl || values.baseUrl === '/') {\n                    setFieldValue('baseUrl', testResponse.urlBase);\n                  }\n                }\n              }}\n              secondaryDisabled={\n                !values.apiKey ||\n                !values.hostname ||\n                !values.port ||\n                isTesting ||\n                isSubmitting\n              }\n              okDisabled={!isValidated || isSubmitting || isTesting || !isValid}\n              onOk={() => handleSubmit()}\n              title={\n                !sonarr\n                  ? intl.formatMessage(\n                      values.is4k\n                        ? messages.create4ksonarr\n                        : messages.createsonarr\n                    )\n                  : intl.formatMessage(\n                      values.is4k ? messages.edit4ksonarr : messages.editsonarr\n                    )\n              }\n            >\n              <div className=\"mb-6\">\n                <div className=\"form-row\">\n                  <label htmlFor=\"isDefault\" className=\"checkbox-label\">\n                    {intl.formatMessage(\n                      values.is4k\n                        ? messages.default4kserver\n                        : messages.defaultserver\n                    )}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field type=\"checkbox\" id=\"isDefault\" name=\"isDefault\" />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"is4k\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.server4k)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field type=\"checkbox\" id=\"is4k\" name=\"is4k\" />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"name\" className=\"text-label\">\n                    {intl.formatMessage(messages.servername)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"name\"\n                        name=\"name\"\n                        type=\"text\"\n                        autoComplete=\"off\"\n                        data-form-type=\"other\"\n                        data-1pignore=\"true\"\n                        data-lpignore=\"true\"\n                        data-bwignore=\"true\"\n                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                          setIsValidated(false);\n                          setFieldValue('name', e.target.value);\n                        }}\n                      />\n                    </div>\n                    {errors.name &&\n                      touched.name &&\n                      typeof errors.name === 'string' && (\n                        <div className=\"error\">{errors.name}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"hostname\" className=\"text-label\">\n                    {intl.formatMessage(messages.hostname)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <span className=\"protocol\">\n                        {values.ssl ? 'https://' : 'http://'}\n                      </span>\n                      <Field\n                        id=\"hostname\"\n                        name=\"hostname\"\n                        type=\"text\"\n                        inputMode=\"url\"\n                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                          setIsValidated(false);\n                          setFieldValue('hostname', e.target.value);\n                        }}\n                        className=\"rounded-r-only\"\n                      />\n                    </div>\n                    {errors.hostname &&\n                      touched.hostname &&\n                      typeof errors.hostname === 'string' && (\n                        <div className=\"error\">{errors.hostname}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"port\" className=\"text-label\">\n                    {intl.formatMessage(messages.port)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      id=\"port\"\n                      name=\"port\"\n                      type=\"text\"\n                      inputMode=\"numeric\"\n                      className=\"short\"\n                      onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                        setIsValidated(false);\n                        setFieldValue('port', e.target.value);\n                      }}\n                    />\n                    {errors.port &&\n                      touched.port &&\n                      typeof errors.port === 'string' && (\n                        <div className=\"error\">{errors.port}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"ssl\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.ssl)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"ssl\"\n                      name=\"ssl\"\n                      onChange={() => {\n                        setIsValidated(false);\n                        setFieldValue('ssl', !values.ssl);\n                      }}\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"apiKey\" className=\"text-label\">\n                    {intl.formatMessage(messages.apiKey)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <SensitiveInput\n                        as=\"field\"\n                        id=\"apiKey\"\n                        name=\"apiKey\"\n                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                          setIsValidated(false);\n                          setFieldValue('apiKey', e.target.value);\n                        }}\n                      />\n                    </div>\n                    {errors.apiKey &&\n                      touched.apiKey &&\n                      typeof errors.apiKey === 'string' && (\n                        <div className=\"error\">{errors.apiKey}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"baseUrl\" className=\"text-label\">\n                    {intl.formatMessage(messages.baseUrl)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"baseUrl\"\n                        name=\"baseUrl\"\n                        type=\"text\"\n                        inputMode=\"url\"\n                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n                          setIsValidated(false);\n                          setFieldValue('baseUrl', e.target.value);\n                        }}\n                      />\n                    </div>\n                    {errors.baseUrl &&\n                      touched.baseUrl &&\n                      typeof errors.baseUrl === 'string' && (\n                        <div className=\"error\">{errors.baseUrl}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"seriesType\" className=\"text-label\">\n                    {intl.formatMessage(messages.seriesType)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"seriesType\"\n                        name=\"seriesType\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"standard\">Standard</option>\n                        <option value=\"daily\">Daily</option>\n                      </Field>\n                    </div>\n                  </div>\n                  {errors.seriesType && touched.seriesType && (\n                    <div className=\"error\">{errors.seriesType}</div>\n                  )}\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"activeProfileId\" className=\"text-label\">\n                    {intl.formatMessage(messages.qualityprofile)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"activeProfileId\"\n                        name=\"activeProfileId\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"\">\n                          {isTesting\n                            ? intl.formatMessage(messages.loadingprofiles)\n                            : !isValidated\n                              ? intl.formatMessage(\n                                  messages.testFirstQualityProfiles\n                                )\n                              : intl.formatMessage(\n                                  messages.selectQualityProfile\n                                )}\n                        </option>\n                        {testResponse.profiles.length > 0 &&\n                          testResponse.profiles\n                            .toSorted((a, b) =>\n                              a.name.localeCompare(b.name, intl.locale, {\n                                numeric: true,\n                                sensitivity: 'base',\n                              })\n                            )\n                            .map((profile) => (\n                              <option\n                                key={`loaded-profile-${profile.id}`}\n                                value={profile.id}\n                              >\n                                {profile.name}\n                              </option>\n                            ))}\n                      </Field>\n                    </div>\n                    {errors.activeProfileId &&\n                      touched.activeProfileId &&\n                      typeof errors.activeProfileId === 'string' && (\n                        <div className=\"error\">{errors.activeProfileId}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"rootFolder\" className=\"text-label\">\n                    {intl.formatMessage(messages.rootfolder)}\n                    <span className=\"label-required\">*</span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"rootFolder\"\n                        name=\"rootFolder\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"\">\n                          {isTesting\n                            ? intl.formatMessage(messages.loadingrootfolders)\n                            : !isValidated\n                              ? intl.formatMessage(\n                                  messages.testFirstRootFolders\n                                )\n                              : intl.formatMessage(messages.selectRootFolder)}\n                        </option>\n                        {testResponse.rootFolders.length > 0 &&\n                          testResponse.rootFolders.map((folder) => (\n                            <option\n                              key={`loaded-profile-${folder.id}`}\n                              value={folder.path}\n                            >\n                              {folder.path}\n                            </option>\n                          ))}\n                      </Field>\n                    </div>\n                    {errors.rootFolder &&\n                      touched.rootFolder &&\n                      typeof errors.rootFolder === 'string' && (\n                        <div className=\"error\">{errors.rootFolder}</div>\n                      )}\n                  </div>\n                </div>\n                {testResponse.languageProfiles && (\n                  <div className=\"form-row\">\n                    <label\n                      htmlFor=\"activeLanguageProfileId\"\n                      className=\"text-label\"\n                    >\n                      {intl.formatMessage(messages.languageprofile)}\n                      <span className=\"label-required\">*</span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <Field\n                          as=\"select\"\n                          id=\"activeLanguageProfileId\"\n                          name=\"activeLanguageProfileId\"\n                          disabled={!isValidated || isTesting}\n                        >\n                          <option value=\"\">\n                            {isTesting\n                              ? intl.formatMessage(\n                                  messages.loadinglanguageprofiles\n                                )\n                              : !isValidated\n                                ? intl.formatMessage(\n                                    messages.testFirstLanguageProfiles\n                                  )\n                                : intl.formatMessage(\n                                    messages.selectLanguageProfile\n                                  )}\n                          </option>\n                          {testResponse.languageProfiles.length > 0 &&\n                            testResponse.languageProfiles.map((language) => (\n                              <option\n                                key={`loaded-profile-${language.id}`}\n                                value={language.id}\n                              >\n                                {language.name}\n                              </option>\n                            ))}\n                        </Field>\n                      </div>\n                      {errors.activeLanguageProfileId &&\n                        touched.activeLanguageProfileId && (\n                          <div className=\"error\">\n                            {errors.activeLanguageProfileId}\n                          </div>\n                        )}\n                    </div>\n                  </div>\n                )}\n                <div className=\"form-row\">\n                  <label htmlFor=\"tags\" className=\"text-label\">\n                    {intl.formatMessage(messages.tags)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Select<OptionType, true>\n                      options={\n                        isValidated\n                          ? testResponse.tags.map((tag) => ({\n                              label: tag.label,\n                              value: tag.id,\n                            }))\n                          : []\n                      }\n                      isMulti\n                      isDisabled={!isValidated || isTesting}\n                      placeholder={\n                        !isValidated\n                          ? intl.formatMessage(messages.testFirstTags)\n                          : isTesting\n                            ? intl.formatMessage(messages.loadingTags)\n                            : intl.formatMessage(messages.selecttags)\n                      }\n                      isLoading={isTesting}\n                      className=\"react-select-container\"\n                      classNamePrefix=\"react-select\"\n                      value={\n                        isTesting\n                          ? []\n                          : (values.tags\n                              .map((tagId) => {\n                                const foundTag = testResponse.tags.find(\n                                  (tag) => tag.id === tagId\n                                );\n\n                                if (!foundTag) {\n                                  return undefined;\n                                }\n\n                                return {\n                                  value: foundTag.id,\n                                  label: foundTag.label,\n                                };\n                              })\n                              .filter(\n                                (option) => option !== undefined\n                              ) as OptionType[])\n                      }\n                      onChange={(value: OnChangeValue<OptionType, true>) => {\n                        setFieldValue(\n                          'tags',\n                          value.map((option) => option.value)\n                        );\n                      }}\n                      noOptionsMessage={() =>\n                        intl.formatMessage(messages.notagoptions)\n                      }\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"animeSeriesType\" className=\"text-label\">\n                    {intl.formatMessage(messages.animeSeriesType)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"animeSeriesType\"\n                        name=\"animeSeriesType\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"standard\">Standard</option>\n                        <option value=\"anime\">Anime</option>\n                      </Field>\n                    </div>\n                  </div>\n                  {errors.animeSeriesType && touched.animeSeriesType && (\n                    <div className=\"error\">{errors.animeSeriesType}</div>\n                  )}\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"activeAnimeProfileId\" className=\"text-label\">\n                    {intl.formatMessage(messages.animequalityprofile)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"activeAnimeProfileId\"\n                        name=\"activeAnimeProfileId\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"\">\n                          {isTesting\n                            ? intl.formatMessage(messages.loadingprofiles)\n                            : !isValidated\n                              ? intl.formatMessage(\n                                  messages.testFirstQualityProfiles\n                                )\n                              : intl.formatMessage(\n                                  messages.selectQualityProfile\n                                )}\n                        </option>\n                        {testResponse.profiles.length > 0 &&\n                          testResponse.profiles\n                            .toSorted((a, b) =>\n                              a.name.localeCompare(b.name, intl.locale, {\n                                numeric: true,\n                                sensitivity: 'base',\n                              })\n                            )\n                            .map((profile) => (\n                              <option\n                                key={`loaded-profile-anime-${profile.id}`}\n                                value={profile.id}\n                              >\n                                {profile.name}\n                              </option>\n                            ))}\n                      </Field>\n                    </div>\n                    {errors.activeAnimeProfileId &&\n                      touched.activeAnimeProfileId && (\n                        <div className=\"error\">\n                          {errors.activeAnimeProfileId}\n                        </div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"activeAnimeRootFolder\" className=\"text-label\">\n                    {intl.formatMessage(messages.animerootfolder)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"activeAnimeRootFolder\"\n                        name=\"activeAnimeRootFolder\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"\">\n                          {isTesting\n                            ? intl.formatMessage(messages.loadingrootfolders)\n                            : !isValidated\n                              ? intl.formatMessage(\n                                  messages.testFirstRootFolders\n                                )\n                              : intl.formatMessage(messages.selectRootFolder)}\n                        </option>\n                        {testResponse.rootFolders.length > 0 &&\n                          testResponse.rootFolders.map((folder) => (\n                            <option\n                              key={`loaded-profile-${folder.id}`}\n                              value={folder.path}\n                            >\n                              {folder.path}\n                            </option>\n                          ))}\n                      </Field>\n                    </div>\n                    {errors.activeAnimeRootFolder &&\n                      touched.activeAnimeRootFolder && (\n                        <div className=\"error\">{errors.rootFolder}</div>\n                      )}\n                  </div>\n                </div>\n                {testResponse.languageProfiles && (\n                  <div className=\"form-row\">\n                    <label\n                      htmlFor=\"activeAnimeLanguageProfileId\"\n                      className=\"text-label\"\n                    >\n                      {intl.formatMessage(messages.animelanguageprofile)}\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <Field\n                          as=\"select\"\n                          id=\"activeAnimeLanguageProfileId\"\n                          name=\"activeAnimeLanguageProfileId\"\n                          disabled={!isValidated || isTesting}\n                        >\n                          <option value=\"\">\n                            {isTesting\n                              ? intl.formatMessage(\n                                  messages.loadinglanguageprofiles\n                                )\n                              : !isValidated\n                                ? intl.formatMessage(\n                                    messages.testFirstLanguageProfiles\n                                  )\n                                : intl.formatMessage(\n                                    messages.selectLanguageProfile\n                                  )}\n                          </option>\n                          {testResponse.languageProfiles.length > 0 &&\n                            testResponse.languageProfiles.map((language) => (\n                              <option\n                                key={`loaded-profile-${language.id}`}\n                                value={language.id}\n                              >\n                                {language.name}\n                              </option>\n                            ))}\n                        </Field>\n                      </div>\n                      {errors.activeAnimeLanguageProfileId &&\n                        touched.activeAnimeLanguageProfileId && (\n                          <div className=\"error\">\n                            {errors.activeAnimeLanguageProfileId}\n                          </div>\n                        )}\n                    </div>\n                  </div>\n                )}\n                <div className=\"form-row\">\n                  <label htmlFor=\"tags\" className=\"text-label\">\n                    {intl.formatMessage(messages.animeTags)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Select<OptionType, true>\n                      options={\n                        isValidated\n                          ? testResponse.tags.map((tag) => ({\n                              label: tag.label,\n                              value: tag.id,\n                            }))\n                          : []\n                      }\n                      isMulti\n                      isDisabled={!isValidated}\n                      placeholder={\n                        !isValidated\n                          ? intl.formatMessage(messages.testFirstTags)\n                          : isTesting\n                            ? intl.formatMessage(messages.loadingTags)\n                            : intl.formatMessage(messages.selecttags)\n                      }\n                      isLoading={isTesting}\n                      className=\"react-select-container\"\n                      classNamePrefix=\"react-select\"\n                      value={\n                        isTesting\n                          ? []\n                          : (values.animeTags\n                              .map((tagId) => {\n                                const foundTag = testResponse.tags.find(\n                                  (tag) => tag.id === tagId\n                                );\n\n                                if (!foundTag) {\n                                  return undefined;\n                                }\n\n                                return {\n                                  value: foundTag.id,\n                                  label: foundTag.label,\n                                };\n                              })\n                              .filter(\n                                (option) => option !== undefined\n                              ) as OptionType[])\n                      }\n                      onChange={(value) => {\n                        setFieldValue(\n                          'animeTags',\n                          value.map((option) => option.value)\n                        );\n                      }}\n                      noOptionsMessage={() =>\n                        intl.formatMessage(messages.notagoptions)\n                      }\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label\n                    htmlFor=\"enableSeasonFolders\"\n                    className=\"checkbox-label\"\n                  >\n                    {intl.formatMessage(messages.seasonfolders)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"enableSeasonFolders\"\n                      name=\"enableSeasonFolders\"\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"monitorNewItems\" className=\"text-label\">\n                    {intl.formatMessage(messages.monitorNewItems)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        as=\"select\"\n                        id=\"monitorNewItems\"\n                        name=\"monitorNewItems\"\n                        disabled={!isValidated || isTesting}\n                      >\n                        <option value=\"all\">All</option>\n                        <option value=\"none\">None</option>\n                      </Field>\n                    </div>\n                  </div>\n                  {errors.monitorNewItems && touched.monitorNewItems && (\n                    <div className=\"error\">{errors.monitorNewItems}</div>\n                  )}\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"externalUrl\" className=\"text-label\">\n                    {intl.formatMessage(messages.externalUrl)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <Field\n                        id=\"externalUrl\"\n                        name=\"externalUrl\"\n                        type=\"text\"\n                        inputMode=\"url\"\n                      />\n                    </div>\n                    {errors.externalUrl &&\n                      touched.externalUrl &&\n                      typeof errors.externalUrl === 'string' && (\n                        <div className=\"error\">{errors.externalUrl}</div>\n                      )}\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"syncEnabled\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.syncEnabled)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"syncEnabled\"\n                      name=\"syncEnabled\"\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"enableSearch\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.enableSearch)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"enableSearch\"\n                      name=\"enableSearch\"\n                    />\n                  </div>\n                </div>\n                <div className=\"form-row\">\n                  <label htmlFor=\"tagRequests\" className=\"checkbox-label\">\n                    {intl.formatMessage(messages.tagRequests)}\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.tagRequestsInfo)}\n                    </span>\n                  </label>\n                  <div className=\"form-input-area\">\n                    <Field\n                      type=\"checkbox\"\n                      id=\"tagRequests\"\n                      name=\"tagRequests\"\n                    />\n                  </div>\n                </div>\n              </div>\n            </Modal>\n          );\n        }}\n      </Formik>\n    </Transition>\n  );\n};\n\nexport default SonarrModal;\n"
  },
  {
    "path": "src/components/Setup/JellyfinSetup.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport defineMessages from '@app/utils/defineMessages';\nimport { InformationCircleIcon } from '@heroicons/react/24/solid';\nimport { ApiErrorCode } from '@server/constants/error';\nimport { MediaServerType, ServerType } from '@server/constants/server';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { FormattedMessage, useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport validator from 'validator';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages('components.Login', {\n  username: 'Username',\n  password: 'Password',\n  hostname: '{mediaServerName} URL',\n  port: 'Port',\n  enablessl: 'Use SSL',\n  urlBase: 'URL Base',\n  email: 'Email Address',\n  emailtooltip:\n    'Address does not need to be associated with your {mediaServerName} instance.',\n  validationhostrequired: '{mediaServerName} URL required',\n  validationhostformat: 'Valid URL required',\n  validationemailrequired: 'You must provide a valid email address',\n  validationemailformat: 'Valid email required',\n  validationusernamerequired: 'Username required',\n  validationpasswordrequired: 'You must provide a password',\n  validationservertyperequired: 'Please select a server type',\n  validationPortRequired: 'You must provide a valid port number',\n  validationUrlTrailingSlash: 'URL must not end in a trailing slash',\n  validationUrlBaseLeadingSlash: 'URL base must have a leading slash',\n  validationUrlBaseTrailingSlash: 'URL base must not end in a trailing slash',\n  loginerror: 'Something went wrong while trying to sign in.',\n  adminerror: 'You must use an admin account to sign in.',\n  noadminerror: 'No admin user found on the server.',\n  credentialerror: 'The username or password is incorrect.',\n  invalidurlerror: 'Unable to connect to {mediaServerName} server.',\n  signingin: 'Signing In…',\n  signin: 'Sign In',\n  initialsigningin: 'Connecting…',\n  initialsignin: 'Connect',\n  forgotpassword: 'Forgot Password?',\n  servertype: 'Server Type',\n  back: 'Go back',\n});\n\ninterface JellyfinSetupProps {\n  revalidate: () => void;\n  serverType?: MediaServerType;\n  onCancel?: () => void;\n}\n\nfunction JellyfinSetup({\n  revalidate,\n  serverType,\n  onCancel,\n}: JellyfinSetupProps) {\n  const toasts = useToasts();\n  const intl = useIntl();\n\n  const mediaServerFormatValues = {\n    mediaServerName:\n      serverType === MediaServerType.JELLYFIN\n        ? ServerType.JELLYFIN\n        : serverType === MediaServerType.EMBY\n          ? ServerType.EMBY\n          : 'Media Server',\n  };\n\n  const LoginSchema = Yup.object().shape({\n    hostname: Yup.string().required(\n      intl.formatMessage(\n        messages.validationhostrequired,\n        mediaServerFormatValues\n      )\n    ),\n    port: Yup.number().required(\n      intl.formatMessage(messages.validationPortRequired)\n    ),\n    urlBase: Yup.string()\n      .test(\n        'leading-slash',\n        intl.formatMessage(messages.validationUrlBaseLeadingSlash),\n        (value) => !value || value.startsWith('/')\n      )\n      .test(\n        'trailing-slash',\n        intl.formatMessage(messages.validationUrlBaseTrailingSlash),\n        (value) => !value || !value.endsWith('/')\n      ),\n    email: Yup.string()\n      .test(\n        'email',\n        intl.formatMessage(messages.validationemailformat),\n        (value) => !value || validator.isEmail(value, { require_tld: false })\n      )\n      .required(intl.formatMessage(messages.validationemailrequired)),\n    username: Yup.string().required(\n      intl.formatMessage(messages.validationusernamerequired)\n    ),\n    password: Yup.string(),\n  });\n\n  return (\n    <Formik\n      initialValues={{\n        username: '',\n        password: '',\n        hostname: '',\n        port: 8096,\n        useSsl: false,\n        urlBase: '',\n        email: '',\n      }}\n      validationSchema={LoginSchema}\n      onSubmit={async (values) => {\n        try {\n          await axios.post('/api/v1/auth/jellyfin', {\n            username: values.username,\n            password: values.password,\n            hostname: values.hostname,\n            port: values.port,\n            useSsl: values.useSsl,\n            urlBase: values.urlBase,\n            email: values.email,\n            serverType: serverType,\n          });\n        } catch (e) {\n          let errorMessage = messages.loginerror;\n          switch (e?.response?.data?.message) {\n            case ApiErrorCode.InvalidUrl:\n              errorMessage = messages.invalidurlerror;\n              break;\n            case ApiErrorCode.InvalidCredentials:\n              errorMessage = messages.credentialerror;\n              break;\n            case ApiErrorCode.NotAdmin:\n              errorMessage = messages.adminerror;\n              break;\n            case ApiErrorCode.NoAdminUser:\n              errorMessage = messages.noadminerror;\n              break;\n          }\n\n          toasts.addToast(\n            intl.formatMessage(errorMessage, mediaServerFormatValues),\n            {\n              autoDismiss: true,\n              appearance: 'error',\n            }\n          );\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({ errors, touched, values, setFieldValue, isSubmitting, isValid }) => (\n        <Form>\n          <div className=\"sm:border-t sm:border-gray-800\">\n            <div className=\"flex flex-col sm:flex-row sm:gap-4\">\n              <div className=\"w-full\">\n                <label htmlFor=\"hostname\" className=\"text-label\">\n                  {intl.formatMessage(\n                    messages.hostname,\n                    mediaServerFormatValues\n                  )}\n                </label>\n                <div className=\"mb-2 mt-1 sm:col-span-2 sm:mb-0 sm:mt-0\">\n                  <div className=\"flex rounded-md shadow-sm\">\n                    <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-gray-100 sm:text-sm\">\n                      {values.useSsl ? 'https://' : 'http://'}\n                    </span>\n                    <Field\n                      id=\"hostname\"\n                      name=\"hostname\"\n                      type=\"text\"\n                      className=\"rounded-r-only flex-1\"\n                      placeholder={intl.formatMessage(\n                        messages.hostname,\n                        mediaServerFormatValues\n                      )}\n                      autoComplete=\"off\"\n                      data-form-type=\"other\"\n                      data-1pignore=\"true\"\n                      data-lpignore=\"true\"\n                      data-bwignore=\"true\"\n                    />\n                  </div>\n                  {errors.hostname && touched.hostname && (\n                    <div className=\"error\">{errors.hostname}</div>\n                  )}\n                </div>\n              </div>\n              <div className=\"flex-1\">\n                <label htmlFor=\"port\" className=\"text-label\">\n                  {intl.formatMessage(messages.port)}\n                </label>\n                <div className=\"mt-1 sm:mt-0\">\n                  <Field\n                    id=\"port\"\n                    name=\"port\"\n                    inputMode=\"numeric\"\n                    type=\"text\"\n                    className=\"short flex-1\"\n                    placeholder={intl.formatMessage(messages.port)}\n                  />\n                  {errors.port && touched.port && (\n                    <div className=\"error\">{errors.port}</div>\n                  )}\n                </div>\n              </div>\n            </div>\n            <label htmlFor=\"useSsl\" className=\"text-label mt-2\">\n              {intl.formatMessage(messages.enablessl)}\n            </label>\n            <div className=\"mb-2 mt-1 sm:col-span-2\">\n              <div className=\"flex rounded-md shadow-sm\">\n                <Field\n                  id=\"useSsl\"\n                  name=\"useSsl\"\n                  type=\"checkbox\"\n                  onChange={() => {\n                    setFieldValue('useSsl', !values.useSsl);\n                    setFieldValue('port', values.useSsl ? 8096 : 443);\n                  }}\n                />\n              </div>\n            </div>\n            <label htmlFor=\"urlBase\" className=\"text-label mt-1\">\n              {intl.formatMessage(messages.urlBase)}\n            </label>\n            <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n              <div className=\"flex rounded-md shadow-sm\">\n                <Field\n                  type=\"text\"\n                  inputMode=\"url\"\n                  id=\"urlBase\"\n                  name=\"urlBase\"\n                  placeholder={intl.formatMessage(messages.urlBase)}\n                />\n              </div>\n              {errors.urlBase && touched.urlBase && (\n                <div className=\"error\">{errors.urlBase}</div>\n              )}\n            </div>\n            <label\n              htmlFor=\"email\"\n              className=\"text-label inline-flex gap-1 align-middle\"\n            >\n              {intl.formatMessage(messages.email)}\n              <span className=\"label-tip\">\n                <Tooltip\n                  content={intl.formatMessage(\n                    messages.emailtooltip,\n                    mediaServerFormatValues\n                  )}\n                >\n                  <span className=\"tooltip-trigger\">\n                    <InformationCircleIcon className=\"h-4 w-4\" />\n                  </span>\n                </Tooltip>\n              </span>\n            </label>\n            <div className=\"mt-1 sm:col-span-2 sm:mb-2 sm:mt-0\">\n              <div className=\"flex rounded-md shadow-sm\">\n                <Field\n                  id=\"email\"\n                  name=\"email\"\n                  type=\"text\"\n                  placeholder={intl.formatMessage(messages.email)}\n                  autoComplete=\"off\"\n                  data-form-type=\"other\"\n                  data-1pignore=\"true\"\n                  data-lpignore=\"true\"\n                  data-bwignore=\"true\"\n                />\n              </div>\n              {errors.email && touched.email && (\n                <div className=\"error\">{errors.email}</div>\n              )}\n            </div>\n            <label htmlFor=\"username\" className=\"text-label\">\n              {intl.formatMessage(messages.username)}\n            </label>\n            <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n              <div className=\"flex rounded-md shadow-sm\">\n                <Field\n                  id=\"username\"\n                  name=\"username\"\n                  type=\"text\"\n                  placeholder={intl.formatMessage(messages.username)}\n                  autoComplete=\"off\"\n                  data-form-type=\"other\"\n                  data-1pignore=\"true\"\n                  data-lpignore=\"true\"\n                  data-bwignore=\"true\"\n                />\n              </div>\n              {errors.username && touched.username && (\n                <div className=\"error\">{errors.username}</div>\n              )}\n            </div>\n            <label htmlFor=\"password\" className=\"text-label\">\n              {intl.formatMessage(messages.password)}\n            </label>\n            <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n              <div className=\"flexrounded-md shadow-sm\">\n                <Field\n                  id=\"password\"\n                  name=\"password\"\n                  type=\"password\"\n                  placeholder={intl.formatMessage(messages.password)}\n                  autoComplete=\"off\"\n                  data-form-type=\"other\"\n                  data-1pignore=\"true\"\n                  data-lpignore=\"true\"\n                  data-bwignore=\"true\"\n                />\n              </div>\n              {errors.password && touched.password && (\n                <div className=\"error\">{errors.password}</div>\n              )}\n            </div>\n          </div>\n          <div className=\"mt-8 border-t border-gray-700 pt-5\">\n            <div className=\"flex flex-row-reverse justify-between\">\n              <span className=\"inline-flex rounded-md shadow-sm\">\n                <Button\n                  buttonType=\"primary\"\n                  type=\"submit\"\n                  disabled={isSubmitting || !isValid}\n                >\n                  {isSubmitting\n                    ? intl.formatMessage(messages.signingin)\n                    : intl.formatMessage(messages.signin)}\n                </Button>\n              </span>\n              {onCancel && (\n                <span className=\"inline-flex rounded-md shadow-sm\">\n                  <Button buttonType=\"default\" onClick={() => onCancel()}>\n                    <FormattedMessage {...messages.back} />\n                  </Button>\n                </span>\n              )}\n            </div>\n          </div>\n        </Form>\n      )}\n    </Formik>\n  );\n}\n\nexport default JellyfinSetup;\n"
  },
  {
    "path": "src/components/Setup/LoginWithPlex.tsx",
    "content": "import PlexLoginButton from '@app/components/Login/PlexLoginButton';\nimport { useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport axios from 'axios';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.Setup', {\n  welcome: 'Welcome to Seerr',\n  signinMessage: 'Get started by signing in with your Plex account',\n});\n\ninterface LoginWithPlexProps {\n  onComplete: () => void;\n}\n\nconst LoginWithPlex = ({ onComplete }: LoginWithPlexProps) => {\n  const intl = useIntl();\n  const [authToken, setAuthToken] = useState<string | undefined>(undefined);\n  const { user, revalidate } = useUser();\n\n  // Effect that is triggered when the `authToken` comes back from the Plex OAuth\n  // We take the token and attempt to login. If we get a success message, we will\n  // ask swr to revalidate the user which _shouid_ come back with a valid user.\n\n  useEffect(() => {\n    const login = async () => {\n      try {\n        const response = await axios.post('/api/v1/auth/plex', { authToken });\n        if (response.data?.id) {\n          const { data: user } = await axios.get('/api/v1/auth/me');\n          revalidate(user, false);\n        }\n      } catch {\n        // auth failed silently, user can retry again\n      }\n    };\n    if (authToken) {\n      login();\n    }\n  }, [authToken, revalidate]);\n\n  // Effect that is triggered whenever `useUser`'s user changes. If we get a new\n  // valid user, we call onComplete which will take us to the next step in Setup.\n  useEffect(() => {\n    if (user) {\n      onComplete();\n    }\n  }, [user, onComplete]);\n\n  return (\n    <form>\n      <div className=\"mb-2 flex justify-center text-xl font-bold\">\n        {intl.formatMessage(messages.welcome)}\n      </div>\n      <div className=\"mb-2 flex justify-center pb-6 text-sm\">\n        {intl.formatMessage(messages.signinMessage)}\n      </div>\n      <div className=\"flex items-center justify-center\">\n        <PlexLoginButton onAuthToken={(authToken) => setAuthToken(authToken)} />\n      </div>\n    </form>\n  );\n};\n\nexport default LoginWithPlex;\n"
  },
  {
    "path": "src/components/Setup/SetupLogin.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport PlexLoginButton from '@app/components/Login/PlexLoginButton';\nimport JellyfinSetup from '@app/components/Setup/JellyfinSetup';\nimport { useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { MediaServerType } from '@server/constants/server';\nimport axios from 'axios';\nimport { useEffect, useState } from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nconst messages = defineMessages('components.Setup', {\n  welcome: 'Welcome to Seerr',\n  signinMessage: 'Get started by signing in',\n  signin: 'Sign in to your account',\n  signinWithJellyfin: 'Enter your Jellyfin details',\n  signinWithEmby: 'Enter your Emby details',\n  signinWithPlex: 'Enter your Plex details',\n  back: 'Go back',\n});\n\ninterface LoginWithMediaServerProps {\n  serverType: MediaServerType;\n  onCancel: () => void;\n  onComplete: () => void;\n}\n\nconst SetupLogin: React.FC<LoginWithMediaServerProps> = ({\n  serverType,\n  onCancel,\n  onComplete,\n}) => {\n  const [authToken, setAuthToken] = useState<string | undefined>(undefined);\n  const [mediaServerType, setMediaServerType] = useState<MediaServerType>(\n    MediaServerType.NOT_CONFIGURED\n  );\n  const { user, revalidate } = useUser();\n\n  // Effect that is triggered when the `authToken` comes back from the Plex OAuth\n  // We take the token and attempt to login. If we get a success message, we will\n  // ask swr to revalidate the user which _shouid_ come back with a valid user.\n\n  useEffect(() => {\n    const login = async () => {\n      try {\n        const response = await axios.post('/api/v1/auth/plex', {\n          authToken: authToken,\n        });\n\n        if (response.data?.id) {\n          const { data: user } = await axios.get('/api/v1/auth/me');\n          revalidate(user, false);\n        }\n      } catch {\n        // auth failed silently and user can attempt again\n      }\n    };\n    if (authToken && mediaServerType == MediaServerType.PLEX) {\n      login();\n    }\n  }, [authToken, mediaServerType, revalidate]);\n\n  useEffect(() => {\n    if (user) {\n      onComplete();\n    }\n  }, [user, mediaServerType, onComplete]);\n\n  return (\n    <div className=\"p-4\">\n      <div className=\"mb-2 flex justify-center text-xl font-bold\">\n        <FormattedMessage {...messages.signin} />\n      </div>\n      <div className=\"mb-2 flex justify-center pb-6 text-sm\">\n        {serverType === MediaServerType.JELLYFIN ? (\n          <FormattedMessage {...messages.signinWithJellyfin} />\n        ) : serverType === MediaServerType.EMBY ? (\n          <FormattedMessage {...messages.signinWithEmby} />\n        ) : (\n          <FormattedMessage {...messages.signinWithPlex} />\n        )}\n      </div>\n      {serverType === MediaServerType.PLEX && (\n        <>\n          <div className=\"flex justify-center bg-black/30 px-10 py-8\">\n            <PlexLoginButton\n              large\n              onAuthToken={(authToken) => {\n                setMediaServerType(MediaServerType.PLEX);\n                setAuthToken(authToken);\n              }}\n            />\n          </div>\n          <div className=\"mt-4\">\n            <Button buttonType=\"default\" onClick={() => onCancel()}>\n              <FormattedMessage {...messages.back} />\n            </Button>\n          </div>\n        </>\n      )}\n      {serverType === MediaServerType.JELLYFIN && (\n        <JellyfinSetup\n          revalidate={revalidate}\n          serverType={serverType}\n          onCancel={onCancel}\n        />\n      )}\n      {serverType === MediaServerType.EMBY && (\n        <JellyfinSetup\n          revalidate={revalidate}\n          serverType={serverType}\n          onCancel={onCancel}\n        />\n      )}\n    </div>\n  );\n};\n\nexport default SetupLogin;\n"
  },
  {
    "path": "src/components/Setup/SetupSteps.tsx",
    "content": "import { CheckIcon } from '@heroicons/react/24/solid';\n\ninterface CurrentStep {\n  stepNumber: number;\n  description: string;\n  active?: boolean;\n  completed?: boolean;\n  isLastStep?: boolean;\n}\n\nconst SetupSteps = ({\n  stepNumber,\n  description,\n  active = false,\n  completed = false,\n  isLastStep = false,\n}: CurrentStep) => {\n  return (\n    <li className=\"relative md:flex md:flex-1\">\n      <div className=\"flex items-center space-x-4 px-6 py-4 text-sm font-medium leading-5\">\n        <div\n          className={`flex h-10 w-10 flex-shrink-0 items-center justify-center border-2 ${\n            active ? 'border-indigo-600' : 'border-white'\n          } ${completed ? 'border-indigo-600 bg-indigo-600' : ''} rounded-full`}\n        >\n          {completed && <CheckIcon className=\"h-6 w-6 text-white\" />}\n          {!completed && (\n            <p className={active ? 'text-white' : 'text-indigo-200'}>\n              {stepNumber}\n            </p>\n          )}\n        </div>\n        <p\n          className={`text-sm font-medium leading-5 ${\n            active ? 'text-white' : 'text-indigo-200'\n          }`}\n        >\n          {description}\n        </p>\n      </div>\n\n      {!isLastStep && (\n        <div className=\"absolute right-0 top-0 hidden h-full w-5 md:block\">\n          <svg\n            className=\"h-full w-full text-gray-600\"\n            viewBox=\"0 0 22 80\"\n            fill=\"none\"\n            preserveAspectRatio=\"none\"\n          >\n            <path\n              d=\"M0 -2L20 40L0 82\"\n              vectorEffect=\"non-scaling-stroke\"\n              stroke=\"currentcolor\"\n              strokeLinejoin=\"round\"\n            />\n          </svg>\n        </div>\n      )}\n    </li>\n  );\n};\n\nexport default SetupSteps;\n"
  },
  {
    "path": "src/components/Setup/index.tsx",
    "content": "import EmbyLogo from '@app/assets/services/emby.svg';\nimport JellyfinLogo from '@app/assets/services/jellyfin.svg';\nimport PlexLogo from '@app/assets/services/plex.svg';\nimport AppDataWarning from '@app/components/AppDataWarning';\nimport Button from '@app/components/Common/Button';\nimport ImageFader from '@app/components/Common/ImageFader';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport LanguagePicker from '@app/components/Layout/LanguagePicker';\nimport SettingsJellyfin from '@app/components/Settings/SettingsJellyfin';\nimport SettingsPlex from '@app/components/Settings/SettingsPlex';\nimport SettingsServices from '@app/components/Settings/SettingsServices';\nimport SetupSteps from '@app/components/Setup/SetupSteps';\nimport useLocale from '@app/hooks/useLocale';\nimport useSettings from '@app/hooks/useSettings';\nimport defineMessages from '@app/utils/defineMessages';\nimport { MediaServerType } from '@server/constants/server';\nimport type { Library } from '@server/lib/settings';\nimport axios from 'axios';\nimport Image from 'next/image';\nimport { useRouter } from 'next/router';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\nimport SetupLogin from './SetupLogin';\n\nconst messages = defineMessages('components.Setup', {\n  welcome: 'Welcome to Seerr',\n  subtitle: 'Get started by choosing your media server',\n  configjellyfin: 'Configure Jellyfin',\n  configplex: 'Configure Plex',\n  configemby: 'Configure Emby',\n  setup: 'Setup',\n  finish: 'Finish Setup',\n  finishing: 'Finishing…',\n  continue: 'Continue',\n  servertype: 'Choose Server Type',\n  signin: 'Sign In',\n  configuremediaserver: 'Configure Media Server',\n  configureservices: 'Configure Services',\n  librarieserror:\n    'Validation failed. Please toggle the libraries again to continue.',\n});\n\nconst Setup = () => {\n  const intl = useIntl();\n  const [isUpdating, setIsUpdating] = useState(false);\n  const [currentStep, setCurrentStep] = useState(1);\n  const [mediaServerSettingsComplete, setMediaServerSettingsComplete] =\n    useState(false);\n  const [mediaServerType, setMediaServerType] = useState(\n    MediaServerType.NOT_CONFIGURED\n  );\n  const router = useRouter();\n  const { locale } = useLocale();\n  const settings = useSettings();\n  const toasts = useToasts();\n\n  const finishSetup = async () => {\n    setIsUpdating(true);\n    const response = await axios.post<{ initialized: boolean }>(\n      '/api/v1/settings/initialize'\n    );\n\n    setIsUpdating(false);\n    if (response.data.initialized) {\n      await axios.post('/api/v1/settings/main', { locale });\n      mutate('/api/v1/settings/public');\n\n      router.push('/');\n    }\n  };\n\n  const validateLibraries = useCallback(async () => {\n    try {\n      const endpointMap: Record<MediaServerType, string> = {\n        [MediaServerType.JELLYFIN]: '/api/v1/settings/jellyfin',\n        [MediaServerType.EMBY]: '/api/v1/settings/jellyfin',\n        [MediaServerType.PLEX]: '/api/v1/settings/plex',\n        [MediaServerType.NOT_CONFIGURED]: '',\n      };\n\n      const endpoint = endpointMap[mediaServerType];\n      if (!endpoint) return;\n\n      const response = await axios.get(endpoint);\n\n      const hasEnabledLibraries = response.data?.libraries?.some(\n        (library: Library) => library.enabled\n      );\n\n      setMediaServerSettingsComplete(hasEnabledLibraries);\n    } catch {\n      toasts.addToast(intl.formatMessage(messages.librarieserror), {\n        autoDismiss: true,\n        appearance: 'error',\n      });\n\n      setMediaServerSettingsComplete(false);\n    }\n  }, [intl, mediaServerType, toasts]);\n\n  const { data: backdrops } = useSWR<string[]>('/api/v1/backdrops', {\n    refreshInterval: 0,\n    refreshWhenHidden: false,\n    revalidateOnFocus: false,\n  });\n\n  useEffect(() => {\n    if (settings.currentSettings.initialized) {\n      router.push('/');\n    }\n\n    if (\n      settings.currentSettings.mediaServerType !==\n      MediaServerType.NOT_CONFIGURED\n    ) {\n      setMediaServerType(settings.currentSettings.mediaServerType);\n      if (currentStep < 3) {\n        setCurrentStep(3);\n      }\n    }\n  }, [\n    settings.currentSettings.mediaServerType,\n    settings.currentSettings.initialized,\n    router,\n    toasts,\n    intl,\n    currentStep,\n    mediaServerType,\n    validateLibraries,\n  ]);\n\n  useEffect(() => {\n    if (currentStep === 3) {\n      validateLibraries();\n    }\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [currentStep]);\n\n  const handleComplete = () => {\n    validateLibraries();\n  };\n\n  if (settings.currentSettings.initialized) return <></>;\n\n  return (\n    <div className=\"relative flex min-h-screen flex-col justify-center bg-gray-900 py-12\">\n      <PageTitle title={intl.formatMessage(messages.setup)} />\n      <ImageFader\n        backgroundImages={\n          backdrops?.map(\n            (backdrop) => `https://image.tmdb.org/t/p/original${backdrop}`\n          ) ?? []\n        }\n      />\n      <div className=\"absolute right-4 top-4 z-50\">\n        <LanguagePicker />\n      </div>\n      <div className=\"relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-4xl\">\n        <div className=\"relative mb-10 h-48 max-w-full sm:mx-auto sm:h-64 sm:max-w-md\">\n          <Image src=\"/logo_stacked.svg\" alt=\"Logo\" fill />\n        </div>\n        <AppDataWarning />\n        <nav className=\"relative z-50\">\n          <ul\n            className=\"divide-y divide-gray-600 rounded-md border border-gray-600 bg-gray-800/50 md:flex md:divide-y-0\"\n            style={{ backdropFilter: 'blur(5px)' }}\n          >\n            <SetupSteps\n              stepNumber={1}\n              description={intl.formatMessage(messages.servertype)}\n              active={currentStep === 1}\n              completed={currentStep > 1}\n            />\n            <SetupSteps\n              stepNumber={2}\n              description={intl.formatMessage(messages.signin)}\n              active={currentStep === 2}\n              completed={currentStep > 2}\n            />\n            <SetupSteps\n              stepNumber={3}\n              description={intl.formatMessage(messages.configuremediaserver)}\n              active={currentStep === 3}\n              completed={currentStep > 3}\n            />\n            <SetupSteps\n              stepNumber={4}\n              description={intl.formatMessage(messages.configureservices)}\n              active={currentStep === 4}\n              isLastStep\n            />\n          </ul>\n        </nav>\n        <div className=\"mt-10 w-full rounded-md border border-gray-600 bg-gray-800/50 p-4 text-white\">\n          {currentStep === 1 && (\n            <div className=\"flex flex-col items-center pb-6\">\n              <div className=\"mb-2 flex justify-center text-xl font-bold\">\n                {intl.formatMessage(messages.welcome)}\n              </div>\n              <div className=\"mb-2 flex justify-center pb-6 text-sm\">\n                {intl.formatMessage(messages.subtitle)}\n              </div>\n              <div className=\"grid grid-cols-3\">\n                <div className=\"flex flex-col divide-y divide-gray-600 rounded-l border border-gray-600 py-2\">\n                  <div className=\"mb-2 flex flex-1 items-center justify-center px-2 py-2\">\n                    <JellyfinLogo className=\"h-10\" />\n                  </div>\n                  <div className=\"px-2 pt-2\">\n                    <button\n                      onClick={() => {\n                        setMediaServerType(MediaServerType.JELLYFIN);\n                        setCurrentStep(2);\n                      }}\n                      className=\"button-md relative z-10 inline-flex h-full w-full items-center justify-center rounded-md border border-gray-600 bg-transparent px-4 py-2 text-sm font-medium leading-5 text-white transition duration-150 ease-in-out hover:z-20 hover:border-gray-200 focus:z-20 focus:border-gray-100 focus:outline-none active:border-gray-100\"\n                    >\n                      {intl.formatMessage(messages.configjellyfin)}\n                    </button>\n                  </div>\n                </div>\n                <div className=\"flex flex-col divide-y divide-gray-600 border-y border-gray-600 py-2\">\n                  <div className=\"mb-2 flex flex-1 items-center justify-center px-2 py-2\">\n                    <PlexLogo className=\"h-8\" />\n                  </div>\n                  <div className=\"px-2 pt-2\">\n                    <button\n                      onClick={() => {\n                        setMediaServerType(MediaServerType.PLEX);\n                        setCurrentStep(2);\n                      }}\n                      className=\"button-md relative z-10 inline-flex h-full w-full items-center justify-center rounded-md border border-gray-600 bg-transparent px-4 py-2 text-sm font-medium leading-5 text-white transition duration-150 ease-in-out hover:z-20 hover:border-gray-200 focus:z-20 focus:border-gray-100 focus:outline-none active:border-gray-100\"\n                    >\n                      {intl.formatMessage(messages.configplex)}\n                    </button>\n                  </div>\n                </div>\n                <div className=\"flex flex-col divide-y divide-gray-600 rounded-r border border-gray-600 py-2\">\n                  <div className=\"mb-2 flex flex-1 items-center justify-center px-2 py-2\">\n                    <EmbyLogo className=\"h-9\" />\n                  </div>\n                  <div className=\"px-2 pt-2\">\n                    <button\n                      onClick={() => {\n                        setMediaServerType(MediaServerType.EMBY);\n                        setCurrentStep(2);\n                      }}\n                      className=\"button-md relative z-10 inline-flex h-full w-full items-center justify-center rounded-md border border-gray-600 bg-transparent px-4 py-2 text-sm font-medium leading-5 text-white transition duration-150 ease-in-out hover:z-20 hover:border-gray-200 focus:z-20 focus:border-gray-100 focus:outline-none active:border-gray-100\"\n                    >\n                      {intl.formatMessage(messages.configemby)}\n                    </button>\n                  </div>\n                </div>\n              </div>\n            </div>\n          )}\n          {currentStep === 2 && (\n            <SetupLogin\n              serverType={mediaServerType}\n              onCancel={() => {\n                setMediaServerType(MediaServerType.NOT_CONFIGURED);\n                setCurrentStep(1);\n              }}\n              onComplete={() => setCurrentStep(3)}\n            />\n          )}\n          {currentStep === 3 && (\n            <div className=\"p-2\">\n              {mediaServerType === MediaServerType.PLEX ? (\n                <SettingsPlex onComplete={handleComplete} />\n              ) : (\n                <SettingsJellyfin isSetupSettings onComplete={handleComplete} />\n              )}\n              <div className=\"actions\">\n                <div className=\"flex justify-end\">\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"primary\"\n                      disabled={!mediaServerSettingsComplete}\n                      onClick={() => setCurrentStep(4)}\n                    >\n                      {intl.formatMessage(messages.continue)}\n                    </Button>\n                  </span>\n                </div>\n              </div>\n            </div>\n          )}\n          {currentStep === 4 && (\n            <div>\n              <SettingsServices />\n              <div className=\"actions\">\n                <div className=\"flex justify-end\">\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"primary\"\n                      onClick={() => finishSetup()}\n                      disabled={isUpdating}\n                    >\n                      {isUpdating\n                        ? intl.formatMessage(messages.finishing)\n                        : intl.formatMessage(messages.finish)}\n                    </Button>\n                  </span>\n                </div>\n              </div>\n            </div>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default Setup;\n"
  },
  {
    "path": "src/components/Slider/index.tsx",
    "content": "import TitleCard from '@app/components/TitleCard';\nimport globalMessages from '@app/i18n/globalMessages';\nimport { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';\nimport { debounce } from 'lodash';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useSpring } from 'react-spring';\n\ninterface SliderProps {\n  sliderKey: string;\n  items?: JSX.Element[];\n  isLoading: boolean;\n  isEmpty?: boolean;\n  emptyMessage?: React.ReactNode;\n  placeholder?: React.ReactNode;\n}\n\nenum Direction {\n  RIGHT,\n  LEFT,\n}\n\nconst Slider = ({\n  sliderKey,\n  items,\n  isLoading,\n  isEmpty = false,\n  emptyMessage,\n  placeholder = <TitleCard.Placeholder />,\n}: SliderProps) => {\n  const intl = useIntl();\n  const containerRef = useRef<HTMLDivElement>(null);\n  const [scrollPos, setScrollPos] = useState({ isStart: true, isEnd: false });\n\n  const handleScroll = useCallback(() => {\n    const scrollWidth = containerRef.current?.scrollWidth ?? 0;\n    const clientWidth =\n      containerRef.current?.getBoundingClientRect().width ?? 0;\n    const scrollPosition = containerRef.current?.scrollLeft ?? 0;\n\n    if (!items || items?.length === 0) {\n      setScrollPos({ isStart: true, isEnd: true });\n    } else if (clientWidth >= scrollWidth) {\n      setScrollPos({ isStart: true, isEnd: true });\n    } else if (\n      scrollPosition >=\n      (containerRef.current?.scrollWidth ?? 0) - clientWidth\n    ) {\n      setScrollPos({ isStart: false, isEnd: true });\n    } else if (scrollPosition > 0) {\n      setScrollPos({ isStart: false, isEnd: false });\n    } else {\n      setScrollPos({ isStart: true, isEnd: false });\n    }\n  }, [items]);\n\n  // eslint-disable-next-line react-hooks/exhaustive-deps\n  const debouncedScroll = useCallback(\n    debounce(() => handleScroll(), 50),\n    [handleScroll]\n  );\n\n  useEffect(() => {\n    const handleResize = () => {\n      debouncedScroll();\n    };\n\n    window.addEventListener('resize', handleResize, { passive: true });\n\n    return () => {\n      window.removeEventListener('resize', handleResize);\n    };\n  }, [debouncedScroll]);\n\n  useEffect(() => {\n    handleScroll();\n  }, [items, handleScroll]);\n\n  const onScroll = () => {\n    debouncedScroll();\n  };\n\n  const [, setX] = useSpring(() => ({\n    from: { x: 0 },\n    to: { x: 0 },\n    onChange: (results) => {\n      if (containerRef.current) {\n        containerRef.current.scrollLeft = results.value.x;\n      }\n    },\n  }));\n\n  const slide = (direction: Direction) => {\n    const clientWidth =\n      containerRef.current?.getBoundingClientRect().width ?? 0;\n    const cardWidth =\n      containerRef.current?.firstElementChild?.getBoundingClientRect().width ??\n      0;\n    const scrollPosition = containerRef.current?.scrollLeft ?? 0;\n    const visibleItems = Math.floor(clientWidth / cardWidth);\n    const scrollOffset = scrollPosition % cardWidth;\n\n    if (direction === Direction.LEFT) {\n      const newX = Math.max(\n        scrollPosition - scrollOffset - visibleItems * cardWidth,\n        0\n      );\n      setX.start({\n        from: { x: scrollPosition },\n        to: { x: newX },\n        onChange: (results) => {\n          if (containerRef.current) {\n            containerRef.current.scrollLeft = results.value.x;\n          }\n        },\n        reset: true,\n        config: { friction: 60, tension: 500, velocity: 20 },\n      });\n\n      if (newX === 0) {\n        setScrollPos({ isStart: true, isEnd: false });\n      } else {\n        setScrollPos({ isStart: false, isEnd: false });\n      }\n    } else if (direction === Direction.RIGHT) {\n      const newX = Math.min(\n        scrollPosition - scrollOffset + visibleItems * cardWidth,\n        containerRef.current?.scrollWidth ?? 0 - clientWidth\n      );\n      setX.start({\n        from: { x: scrollPosition },\n        to: { x: newX },\n        onChange: (results) => {\n          if (containerRef.current) {\n            containerRef.current.scrollLeft = results.value.x;\n          }\n        },\n        reset: true,\n        config: { friction: 60, tension: 500, velocity: 20 },\n      });\n\n      if (newX >= (containerRef.current?.scrollWidth ?? 0) - clientWidth) {\n        setScrollPos({ isStart: false, isEnd: true });\n      } else {\n        setScrollPos({ isStart: false, isEnd: false });\n      }\n    }\n  };\n\n  return (\n    <div className=\"relative\" data-testid=\"media-slider\">\n      <div className=\"absolute right-0 -mt-10 flex text-gray-400\">\n        <button\n          className={`${\n            scrollPos.isStart ? 'text-gray-800' : 'hover:text-white'\n          }`}\n          onClick={() => slide(Direction.LEFT)}\n          disabled={scrollPos.isStart}\n          type=\"button\"\n        >\n          <ChevronLeftIcon className=\"h-6 w-6\" />\n        </button>\n        <button\n          className={`${\n            scrollPos.isEnd ? 'text-gray-800' : 'hover:text-white'\n          }`}\n          onClick={() => slide(Direction.RIGHT)}\n          disabled={scrollPos.isEnd}\n          type=\"button\"\n        >\n          <ChevronRightIcon className=\"h-6 w-6\" />\n        </button>\n      </div>\n      <div\n        className=\"hide-scrollbar relative -my-2 -ml-4 -mr-4 overflow-y-auto overflow-x-scroll overscroll-x-contain whitespace-nowrap px-2 py-2\"\n        ref={containerRef}\n        onScroll={onScroll}\n      >\n        {items?.map((item, index) => (\n          <div\n            key={`${sliderKey}-${index}`}\n            className=\"inline-block px-2 align-top\"\n          >\n            {item}\n          </div>\n        ))}\n        {isLoading &&\n          [...Array(10)].map((_item, i) => (\n            <div\n              key={`placeholder-${i}`}\n              className=\"inline-block px-2 align-top\"\n            >\n              {placeholder}\n            </div>\n          ))}\n        {isEmpty && (\n          <div className=\"mb-16 mt-16 text-center font-medium text-gray-400\">\n            {emptyMessage\n              ? emptyMessage\n              : intl.formatMessage(globalMessages.noresults)}\n          </div>\n        )}\n      </div>\n    </div>\n  );\n};\n\nexport default Slider;\n"
  },
  {
    "path": "src/components/StatusBadge/index.tsx",
    "content": "import Spinner from '@app/assets/spinner.svg';\nimport Badge from '@app/components/Common/Badge';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport DownloadBlock from '@app/components/DownloadBlock';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { MediaStatus } from '@server/constants/media';\nimport { MediaServerType } from '@server/constants/server';\nimport type { DownloadingItem } from '@server/lib/downloadtracker';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.StatusBadge', {\n  status: '{status}',\n  status4k: '4K {status}',\n  playonplex: 'Play on {mediaServerName}',\n  openinarr: 'Open in {arr}',\n  managemedia: 'Manage {mediaType}',\n  seasonnumber: 'S{seasonNumber}',\n  seasonepisodenumber: 'S{seasonNumber}E{episodeNumber}',\n});\n\ninterface StatusBadgeProps {\n  status?: MediaStatus;\n  downloadItem?: DownloadingItem[];\n  is4k?: boolean;\n  inProgress?: boolean;\n  plexUrl?: string;\n  serviceUrl?: string;\n  tmdbId?: number;\n  mediaType?: 'movie' | 'tv';\n  title?: string | string[];\n}\n\nconst StatusBadge = ({\n  status,\n  downloadItem = [],\n  is4k = false,\n  inProgress = false,\n  plexUrl,\n  serviceUrl,\n  tmdbId,\n  mediaType,\n  title,\n}: StatusBadgeProps) => {\n  const intl = useIntl();\n  const { hasPermission } = useUser();\n  const settings = useSettings();\n\n  let mediaLink: string | undefined;\n  let mediaLinkDescription: string | undefined;\n\n  const calculateDownloadProgress = (media: DownloadingItem) => {\n    return Math.round(((media?.size - media?.sizeLeft) / media?.size) * 100);\n  };\n\n  if (\n    mediaType &&\n    plexUrl &&\n    hasPermission(\n      is4k\n        ? [\n            Permission.REQUEST_4K,\n            mediaType === 'movie'\n              ? Permission.REQUEST_4K_MOVIE\n              : Permission.REQUEST_4K_TV,\n          ]\n        : [\n            Permission.REQUEST,\n            mediaType === 'movie'\n              ? Permission.REQUEST_MOVIE\n              : Permission.REQUEST_TV,\n          ],\n      {\n        type: 'or',\n      }\n    ) &&\n    (!is4k ||\n      (mediaType === 'movie'\n        ? settings.currentSettings.movie4kEnabled\n        : settings.currentSettings.series4kEnabled))\n  ) {\n    mediaLink = plexUrl;\n    mediaLinkDescription = intl.formatMessage(messages.playonplex, {\n      mediaServerName:\n        settings.currentSettings.mediaServerType === MediaServerType.EMBY\n          ? 'Emby'\n          : settings.currentSettings.mediaServerType === MediaServerType.PLEX\n            ? 'Plex'\n            : 'Jellyfin',\n    });\n  } else if (hasPermission(Permission.MANAGE_REQUESTS)) {\n    if (mediaType && tmdbId) {\n      mediaLink = `/${mediaType}/${tmdbId}?manage=1`;\n      mediaLinkDescription = intl.formatMessage(messages.managemedia, {\n        mediaType: intl.formatMessage(\n          mediaType === 'movie' ? globalMessages.movie : globalMessages.tvshow\n        ),\n      });\n    } else if (hasPermission(Permission.ADMIN) && serviceUrl) {\n      mediaLink = serviceUrl;\n      mediaLinkDescription = intl.formatMessage(messages.openinarr, {\n        arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr',\n      });\n    }\n  }\n\n  const tooltipContent =\n    mediaType === 'tv' &&\n    downloadItem.length > 1 &&\n    downloadItem.every(\n      (item) =>\n        item.downloadId && item.downloadId === downloadItem[0].downloadId\n    ) ? (\n      <DownloadBlock\n        downloadItem={downloadItem[0]}\n        title={Array.isArray(title) ? title[0] : title}\n        is4k={is4k}\n      />\n    ) : (\n      <ul>\n        {downloadItem.map((status, index) => (\n          <li\n            key={`dl-status-${status.externalId}-${index}`}\n            className=\"border-b border-gray-700 last:border-b-0\"\n          >\n            <DownloadBlock\n              downloadItem={status}\n              title={Array.isArray(title) ? title[index] : title}\n              is4k={is4k}\n            />\n          </li>\n        ))}\n      </ul>\n    );\n\n  const badgeDownloadProgress = (\n    <div\n      className={`absolute left-0 top-0 z-10 flex h-full ${\n        status === MediaStatus.DELETED\n          ? 'bg-red-600/80'\n          : status === MediaStatus.PROCESSING\n            ? 'bg-indigo-500/80'\n            : 'bg-green-500/80'\n      } transition-all duration-200 ease-in-out`}\n      style={{\n        width: `${\n          downloadItem ? calculateDownloadProgress(downloadItem[0]) : 0\n        }%`,\n      }}\n    />\n  );\n\n  switch (status) {\n    case MediaStatus.AVAILABLE:\n      return (\n        <Tooltip\n          content={inProgress ? tooltipContent : mediaLinkDescription}\n          className={`${\n            inProgress && 'hidden max-h-96 w-96 overflow-y-auto sm:block'\n          }`}\n          tooltipConfig={{\n            ...(inProgress && { interactive: true, delayHide: 100 }),\n          }}\n        >\n          <Badge\n            badgeType=\"success\"\n            href={mediaLink}\n            className={`${\n              inProgress && 'relative !bg-gray-700/80 !px-0 hover:!bg-gray-700'\n            } overflow-hidden`}\n          >\n            {inProgress && badgeDownloadProgress}\n            <div\n              className={`relative z-20 flex items-center ${\n                inProgress && 'px-2'\n              }`}\n            >\n              <span>\n                {intl.formatMessage(\n                  is4k ? messages.status4k : messages.status,\n                  {\n                    status: inProgress\n                      ? intl.formatMessage(globalMessages.processing)\n                      : intl.formatMessage(globalMessages.available),\n                  }\n                )}\n              </span>\n              {inProgress && (\n                <>\n                  {mediaType === 'tv' &&\n                    downloadItem[0].episode &&\n                    (downloadItem.length > 1 &&\n                    downloadItem.every(\n                      (item) =>\n                        item.downloadId &&\n                        item.downloadId === downloadItem[0].downloadId\n                    ) ? (\n                      <span className=\"ml-1\">\n                        {intl.formatMessage(messages.seasonnumber, {\n                          seasonNumber: downloadItem[0].episode.seasonNumber,\n                        })}\n                      </span>\n                    ) : (\n                      <span className=\"ml-1\">\n                        {intl.formatMessage(messages.seasonepisodenumber, {\n                          seasonNumber: downloadItem[0].episode.seasonNumber,\n                          episodeNumber: downloadItem[0].episode.episodeNumber,\n                        })}\n                      </span>\n                    ))}\n                  <Spinner className=\"ml-1 h-3 w-3\" />\n                </>\n              )}\n            </div>\n          </Badge>\n        </Tooltip>\n      );\n\n    case MediaStatus.PARTIALLY_AVAILABLE:\n      return (\n        <Tooltip\n          content={inProgress ? tooltipContent : mediaLinkDescription}\n          className={`${\n            inProgress && 'hidden max-h-96 w-96 overflow-y-auto sm:block'\n          }`}\n          tooltipConfig={{\n            ...(inProgress && { interactive: true, delayHide: 100 }),\n          }}\n        >\n          <Badge\n            badgeType=\"success\"\n            href={mediaLink}\n            className={`${\n              inProgress && 'relative !bg-gray-700/80 !px-0 hover:!bg-gray-700'\n            } overflow-hidden`}\n          >\n            {inProgress && badgeDownloadProgress}\n            <div\n              className={`relative z-20 flex items-center ${\n                inProgress && 'px-2'\n              }`}\n            >\n              <span>\n                {intl.formatMessage(\n                  is4k ? messages.status4k : messages.status,\n                  {\n                    status: inProgress\n                      ? intl.formatMessage(globalMessages.processing)\n                      : intl.formatMessage(globalMessages.partiallyavailable),\n                  }\n                )}\n              </span>\n              {inProgress && (\n                <>\n                  {mediaType === 'tv' &&\n                    downloadItem[0].episode &&\n                    (downloadItem.length > 1 &&\n                    downloadItem.every(\n                      (item) =>\n                        item.downloadId &&\n                        item.downloadId === downloadItem[0].downloadId\n                    ) ? (\n                      <span className=\"ml-1\">\n                        {intl.formatMessage(messages.seasonnumber, {\n                          seasonNumber: downloadItem[0].episode.seasonNumber,\n                        })}\n                      </span>\n                    ) : (\n                      <span className=\"ml-1\">\n                        {intl.formatMessage(messages.seasonepisodenumber, {\n                          seasonNumber: downloadItem[0].episode.seasonNumber,\n                          episodeNumber: downloadItem[0].episode.episodeNumber,\n                        })}\n                      </span>\n                    ))}\n                  <Spinner className=\"ml-1 h-3 w-3\" />\n                </>\n              )}\n            </div>\n          </Badge>\n        </Tooltip>\n      );\n\n    case MediaStatus.PROCESSING:\n      return (\n        <Tooltip\n          content={inProgress ? tooltipContent : mediaLinkDescription}\n          className={`${\n            inProgress && 'hidden max-h-96 w-96 overflow-y-auto sm:block'\n          }`}\n          tooltipConfig={{\n            ...(inProgress && { interactive: true, delayHide: 100 }),\n          }}\n        >\n          <Badge\n            badgeType=\"primary\"\n            href={mediaLink}\n            className={`${\n              inProgress && 'relative !bg-gray-700/80 !px-0 hover:!bg-gray-700'\n            } overflow-hidden`}\n          >\n            {inProgress && badgeDownloadProgress}\n            <div\n              className={`relative z-20 flex items-center ${\n                inProgress && 'px-2'\n              }`}\n            >\n              <span>\n                {intl.formatMessage(\n                  is4k ? messages.status4k : messages.status,\n                  {\n                    status: inProgress\n                      ? intl.formatMessage(globalMessages.processing)\n                      : intl.formatMessage(globalMessages.requested),\n                  }\n                )}\n              </span>\n              {inProgress && (\n                <>\n                  {mediaType === 'tv' &&\n                    downloadItem[0].episode &&\n                    (downloadItem.length > 1 &&\n                    downloadItem.every(\n                      (item) =>\n                        item.downloadId &&\n                        item.downloadId === downloadItem[0].downloadId\n                    ) ? (\n                      <span className=\"ml-1\">\n                        {intl.formatMessage(messages.seasonnumber, {\n                          seasonNumber: downloadItem[0].episode.seasonNumber,\n                        })}\n                      </span>\n                    ) : (\n                      <span className=\"ml-1\">\n                        {intl.formatMessage(messages.seasonepisodenumber, {\n                          seasonNumber: downloadItem[0].episode.seasonNumber,\n                          episodeNumber: downloadItem[0].episode.episodeNumber,\n                        })}\n                      </span>\n                    ))}\n                  <Spinner className=\"ml-1 h-3 w-3\" />\n                </>\n              )}\n            </div>\n          </Badge>\n        </Tooltip>\n      );\n\n    case MediaStatus.PENDING:\n      return (\n        <Tooltip content={mediaLinkDescription}>\n          <Badge badgeType=\"warning\" href={mediaLink}>\n            {intl.formatMessage(is4k ? messages.status4k : messages.status, {\n              status: intl.formatMessage(globalMessages.pending),\n            })}\n          </Badge>\n        </Tooltip>\n      );\n\n    case MediaStatus.BLOCKLISTED:\n      return (\n        <Tooltip content={mediaLinkDescription}>\n          <Badge badgeType=\"danger\" href={mediaLink}>\n            {intl.formatMessage(is4k ? messages.status4k : messages.status, {\n              status: intl.formatMessage(globalMessages.blocklisted),\n            })}\n          </Badge>\n        </Tooltip>\n      );\n\n    case MediaStatus.DELETED:\n      return (\n        <Tooltip\n          content={inProgress ? tooltipContent : mediaLinkDescription}\n          className={`${\n            inProgress && 'hidden max-h-96 w-96 overflow-y-auto sm:block'\n          }`}\n          tooltipConfig={{\n            ...(inProgress && { interactive: true, delayHide: 100 }),\n          }}\n        >\n          <Badge\n            badgeType=\"danger\"\n            href={mediaLink}\n            className={`${\n              inProgress && 'relative !bg-gray-700/80 !px-0 hover:!bg-gray-700'\n            } overflow-hidden`}\n          >\n            {inProgress && badgeDownloadProgress}\n            <div\n              className={`relative z-20 flex items-center ${\n                inProgress && 'px-2'\n              }`}\n            >\n              <span>\n                {intl.formatMessage(\n                  is4k ? messages.status4k : messages.status,\n                  {\n                    status: inProgress\n                      ? intl.formatMessage(globalMessages.processing)\n                      : intl.formatMessage(globalMessages.deleted),\n                  }\n                )}\n              </span>\n              {inProgress && (\n                <>\n                  {mediaType === 'tv' &&\n                    downloadItem[0].episode &&\n                    (downloadItem.length > 1 &&\n                    downloadItem.every(\n                      (item) =>\n                        item.downloadId &&\n                        item.downloadId === downloadItem[0].downloadId\n                    ) ? (\n                      <span className=\"ml-1\">\n                        {intl.formatMessage(messages.seasonnumber, {\n                          seasonNumber: downloadItem[0].episode.seasonNumber,\n                        })}\n                      </span>\n                    ) : (\n                      <span className=\"ml-1\">\n                        {intl.formatMessage(messages.seasonepisodenumber, {\n                          seasonNumber: downloadItem[0].episode.seasonNumber,\n                          episodeNumber: downloadItem[0].episode.episodeNumber,\n                        })}\n                      </span>\n                    ))}\n                  <Spinner className=\"ml-1 h-3 w-3\" />\n                </>\n              )}\n            </div>\n          </Badge>\n        </Tooltip>\n      );\n\n    default:\n      return null;\n  }\n};\n\nexport default StatusBadge;\n"
  },
  {
    "path": "src/components/StatusChecker/index.tsx",
    "content": "import Modal from '@app/components/Common/Modal';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport type { StatusResponse } from '@server/interfaces/api/settingsInterfaces';\nimport { Fragment, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.StatusChecker', {\n  appUpdated: '{applicationTitle} Updated',\n  appUpdatedDescription:\n    'Please click the button below to reload the application.',\n  reloadApp: 'Reload {applicationTitle}',\n  restartRequired: 'Server Restart Required',\n  restartRequiredDescription:\n    'Please restart the server to apply the updated settings.',\n});\n\nconst StatusChecker = () => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const { hasPermission } = useUser();\n  const { data, error } = useSWR<StatusResponse>('/api/v1/status', {\n    refreshInterval: 60 * 1000,\n  });\n  const [alertDismissed, setAlertDismissed] = useState(false);\n\n  useEffect(() => {\n    if (!data?.restartRequired) {\n      setAlertDismissed(false);\n    }\n  }, [data?.restartRequired]);\n\n  if (!data && !error) {\n    return null;\n  }\n\n  if (!data) {\n    return null;\n  }\n\n  return (\n    <Transition\n      as={Fragment}\n      enter=\"transition-opacity duration-300\"\n      enterFrom=\"opacity-0\"\n      enterTo=\"opacity-100\"\n      leave=\"transition-opacity duration-300\"\n      leaveFrom=\"opacity-100\"\n      leaveTo=\"opacity-0\"\n      appear\n      show={\n        !alertDismissed &&\n        ((hasPermission(Permission.ADMIN) && data.restartRequired) ||\n          data.commitTag !== process.env.commitTag)\n      }\n    >\n      {hasPermission(Permission.ADMIN) && data.restartRequired ? (\n        <Modal\n          title={intl.formatMessage(messages.restartRequired)}\n          backgroundClickable={false}\n          onOk={() => {\n            setAlertDismissed(true);\n            if (data.commitTag !== process.env.commitTag) {\n              location.reload();\n            }\n          }}\n          okText={intl.formatMessage(globalMessages.close)}\n        >\n          {intl.formatMessage(messages.restartRequiredDescription)}\n        </Modal>\n      ) : (\n        <Modal\n          title={intl.formatMessage(messages.appUpdated, {\n            applicationTitle: settings.currentSettings.applicationTitle,\n          })}\n          onOk={() => location.reload()}\n          okText={intl.formatMessage(messages.reloadApp, {\n            applicationTitle: settings.currentSettings.applicationTitle,\n          })}\n          backgroundClickable={false}\n        >\n          {intl.formatMessage(messages.appUpdatedDescription)}\n        </Modal>\n      )}\n    </Transition>\n  );\n};\n\nexport default StatusChecker;\n"
  },
  {
    "path": "src/components/TitleCard/ErrorCard.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { CheckIcon, TrashIcon } from '@heroicons/react/24/solid';\nimport axios from 'axios';\nimport { useIntl } from 'react-intl';\nimport { mutate } from 'swr';\n\ninterface ErrorCardProps {\n  id: number;\n  tmdbId: number;\n  tvdbId?: number;\n  type: 'movie' | 'tv';\n  canExpand?: boolean;\n}\n\nconst messages = defineMessages('components.TitleCard', {\n  mediaerror: '{mediaType} Not Found',\n  tmdbid: 'TMDB ID',\n  tvdbid: 'TheTVDB ID',\n  cleardata: 'Clear Data',\n});\n\nconst ErrorCard = ({ id, tmdbId, tvdbId, type, canExpand }: ErrorCardProps) => {\n  const intl = useIntl();\n\n  const deleteMedia = async () => {\n    await axios.delete(`/api/v1/media/${id}`);\n    mutate('/api/v1/media?filter=allavailable&take=20&sort=mediaAdded');\n    mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');\n  };\n\n  return (\n    <div\n      className={canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'}\n      data-testid=\"title-card\"\n    >\n      <div\n        className=\"relative transform-gpu cursor-default overflow-hidden rounded-xl bg-gray-800 bg-cover shadow outline-none ring-1 ring-gray-700 transition duration-300\"\n        style={{\n          paddingBottom: '150%',\n        }}\n      >\n        <div className=\"absolute inset-0 h-full w-full overflow-hidden\">\n          <div className=\"absolute left-0 right-0 flex items-center justify-between p-2\">\n            <div\n              className={`pointer-events-none z-40 rounded-full shadow ${\n                type === 'movie' ? 'bg-blue-500' : 'bg-purple-600'\n              }`}\n            >\n              <div className=\"flex h-4 items-center px-2 py-2 text-center text-xs font-medium uppercase tracking-wider text-white sm:h-5\">\n                {type === 'movie'\n                  ? intl.formatMessage(globalMessages.movie)\n                  : intl.formatMessage(globalMessages.tvshow)}\n              </div>\n            </div>\n            <div className=\"pointer-events-none z-40\">\n              <div className=\"flex h-4 w-4 items-center justify-center rounded-full bg-green-400 text-white shadow sm:h-5 sm:w-5\">\n                <CheckIcon className=\"h-3 w-3 sm:h-4 sm:w-4\" />\n              </div>\n            </div>\n          </div>\n\n          <div className=\"flex h-full w-full items-end\">\n            <div className=\"px-2 pb-11 text-white\">\n              <h1\n                className=\"whitespace-normal text-xl font-bold leading-tight\"\n                style={{\n                  WebkitLineClamp: 3,\n                  display: '-webkit-box',\n                  overflow: 'hidden',\n                  WebkitBoxOrient: 'vertical',\n                  wordBreak: 'break-word',\n                }}\n                data-testid=\"title-card-title\"\n              >\n                {intl.formatMessage(messages.mediaerror, {\n                  mediaType: intl.formatMessage(\n                    type === 'movie'\n                      ? globalMessages.movie\n                      : globalMessages.tvshow\n                  ),\n                })}\n              </h1>\n              <div\n                className=\"whitespace-normal text-xs\"\n                style={{\n                  WebkitLineClamp: 3,\n                  display: '-webkit-box',\n                  overflow: 'hidden',\n                  WebkitBoxOrient: 'vertical',\n                  wordBreak: 'break-word',\n                }}\n              >\n                <div className=\"flex items-center\">\n                  <span className=\"mr-2 font-bold text-gray-400\">\n                    {intl.formatMessage(messages.tmdbid)}\n                  </span>\n                  {tmdbId}\n                </div>\n                {!!tvdbId && (\n                  <div className=\"mt-2 flex items-center sm:mt-1\">\n                    <span className=\"mr-2 font-bold text-gray-400\">\n                      {intl.formatMessage(messages.tvdbid)}\n                    </span>\n                    {tvdbId}\n                  </div>\n                )}\n              </div>\n            </div>\n          </div>\n\n          <div className=\"absolute bottom-0 left-0 right-0 flex justify-between px-2 py-2\">\n            <Button\n              buttonType=\"danger\"\n              buttonSize=\"sm\"\n              onClick={(e) => {\n                e.preventDefault();\n                deleteMedia();\n              }}\n              className=\"h-7 w-full\"\n            >\n              <TrashIcon />\n              <span>{intl.formatMessage(messages.cleardata)}</span>\n            </Button>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n};\nexport default ErrorCard;\n"
  },
  {
    "path": "src/components/TitleCard/Placeholder.tsx",
    "content": "interface PlaceholderProps {\n  canExpand?: boolean;\n}\n\nconst Placeholder = ({ canExpand = false }: PlaceholderProps) => {\n  return (\n    <div\n      className={`relative animate-pulse rounded-xl bg-gray-700 ${\n        canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'\n      }`}\n    >\n      <div className=\"w-full\" style={{ paddingBottom: '150%' }} />\n    </div>\n  );\n};\n\nexport default Placeholder;\n"
  },
  {
    "path": "src/components/TitleCard/TmdbTitleCard.tsx",
    "content": "import TitleCard from '@app/components/TitleCard';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport { useInView } from 'react-intersection-observer';\nimport useSWR from 'swr';\n\nexport interface TmdbTitleCardProps {\n  id: number;\n  tmdbId: number;\n  tvdbId?: number;\n  type: 'movie' | 'tv';\n  canExpand?: boolean;\n  isAddedToWatchlist?: boolean;\n  mutateParent?: () => void;\n}\n\nconst isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {\n  return (movie as MovieDetails).title !== undefined;\n};\n\nconst TmdbTitleCard = ({\n  id,\n  tmdbId,\n  tvdbId,\n  type,\n  canExpand,\n  isAddedToWatchlist = false,\n  mutateParent,\n}: TmdbTitleCardProps) => {\n  const { hasPermission } = useUser();\n\n  const { ref, inView } = useInView({\n    triggerOnce: true,\n  });\n  const url =\n    type === 'movie' ? `/api/v1/movie/${tmdbId}` : `/api/v1/tv/${tmdbId}`;\n  const { data: title, error } = useSWR<MovieDetails | TvDetails>(\n    inView ? `${url}` : null\n  );\n\n  if (!title && !error) {\n    return (\n      <div ref={ref}>\n        <TitleCard.Placeholder canExpand={canExpand} />\n      </div>\n    );\n  }\n\n  if (!title) {\n    return hasPermission(Permission.ADMIN) ? (\n      <TitleCard.ErrorCard\n        id={id}\n        tmdbId={tmdbId}\n        tvdbId={tvdbId}\n        type={type}\n      />\n    ) : null;\n  }\n\n  return isMovie(title) ? (\n    <TitleCard\n      key={title.id}\n      id={title.id}\n      isAddedToWatchlist={\n        title.mediaInfo?.watchlists?.length || isAddedToWatchlist\n      }\n      image={title.posterPath}\n      status={title.mediaInfo?.status}\n      summary={title.overview}\n      title={title.title}\n      userScore={title.voteAverage}\n      year={title.releaseDate}\n      mediaType={'movie'}\n      canExpand={canExpand}\n      mutateParent={mutateParent}\n    />\n  ) : (\n    <TitleCard\n      key={title.id}\n      id={title.id}\n      isAddedToWatchlist={\n        title.mediaInfo?.watchlists?.length || isAddedToWatchlist\n      }\n      image={title.posterPath}\n      status={title.mediaInfo?.status}\n      summary={title.overview}\n      title={title.name}\n      userScore={title.voteAverage}\n      year={title.firstAirDate}\n      mediaType={'tv'}\n      canExpand={canExpand}\n      mutateParent={mutateParent}\n    />\n  );\n};\n\nexport default TmdbTitleCard;\n"
  },
  {
    "path": "src/components/TitleCard/index.tsx",
    "content": "import Spinner from '@app/assets/spinner.svg';\nimport BlocklistModal from '@app/components/BlocklistModal';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport StatusBadgeMini from '@app/components/Common/StatusBadgeMini';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport RequestModal from '@app/components/RequestModal';\nimport ErrorCard from '@app/components/TitleCard/ErrorCard';\nimport Placeholder from '@app/components/TitleCard/Placeholder';\nimport { useIsTouch } from '@app/hooks/useIsTouch';\nimport { Permission, UserType, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { withProperties } from '@app/utils/typeHelpers';\nimport { Transition } from '@headlessui/react';\nimport {\n  ArrowDownTrayIcon,\n  EyeIcon,\n  EyeSlashIcon,\n  MinusCircleIcon,\n  StarIcon,\n} from '@heroicons/react/24/outline';\nimport { MediaStatus } from '@server/constants/media';\nimport type { Watchlist } from '@server/entity/Watchlist';\nimport type { MediaType } from '@server/models/Search';\nimport axios from 'axios';\nimport Link from 'next/link';\nimport { Fragment, useCallback, useEffect, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport { mutate } from 'swr';\n\ninterface TitleCardProps {\n  id: number;\n  image?: string;\n  summary?: string;\n  year?: string;\n  title: string;\n  userScore?: number;\n  mediaType: MediaType;\n  status?: MediaStatus;\n  canExpand?: boolean;\n  inProgress?: boolean;\n  isAddedToWatchlist?: number | boolean;\n  mutateParent?: () => void;\n}\n\nconst messages = defineMessages('components.TitleCard', {\n  addToWatchList: 'Add to watchlist',\n  watchlistSuccess:\n    '<strong>{title}</strong> added to watchlist  successfully!',\n  watchlistDeleted:\n    '<strong>{title}</strong> Removed from watchlist  successfully!',\n  watchlistCancel: 'watchlist for <strong>{title}</strong> canceled.',\n  watchlistError: 'Something went wrong. Please try again.',\n});\n\nconst TitleCard = ({\n  id,\n  image,\n  summary,\n  year,\n  title,\n  status,\n  mediaType,\n  isAddedToWatchlist = false,\n  inProgress = false,\n  canExpand = false,\n  mutateParent,\n}: TitleCardProps) => {\n  const isTouch = useIsTouch();\n  const intl = useIntl();\n  const { user, hasPermission } = useUser();\n  const [isUpdating, setIsUpdating] = useState(false);\n  const [currentStatus, setCurrentStatus] = useState(status);\n  const [showDetail, setShowDetail] = useState(false);\n  const [showRequestModal, setShowRequestModal] = useState(false);\n  const { addToast } = useToasts();\n  const [toggleWatchlist, setToggleWatchlist] =\n    useState<boolean>(!isAddedToWatchlist);\n  const [showBlocklistModal, setShowBlocklistModal] = useState(false);\n  const cardRef = useRef<HTMLDivElement>(null);\n\n  // Just to get the year from the date\n  if (year) {\n    year = year.slice(0, 4);\n  }\n\n  useEffect(() => {\n    setCurrentStatus(status);\n  }, [status]);\n\n  const requestComplete = useCallback((newStatus: MediaStatus) => {\n    setCurrentStatus(newStatus);\n    setShowRequestModal(false);\n  }, []);\n\n  const requestUpdating = useCallback(\n    (status: boolean) => setIsUpdating(status),\n    []\n  );\n\n  const closeBlocklistModal = useCallback(\n    () => setShowBlocklistModal(false),\n    []\n  );\n\n  const onClickWatchlistBtn = async (): Promise<void> => {\n    setIsUpdating(true);\n    try {\n      const response = await axios.post<Watchlist>('/api/v1/watchlist', {\n        tmdbId: id,\n        mediaType,\n        title,\n      });\n      mutate('/api/v1/discover/watchlist');\n      if (response.data) {\n        addToast(\n          <span>\n            {intl.formatMessage(messages.watchlistSuccess, {\n              title,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'success', autoDismiss: true }\n        );\n      }\n    } catch {\n      addToast(intl.formatMessage(messages.watchlistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      setIsUpdating(false);\n      setToggleWatchlist((prevState) => !prevState);\n    }\n  };\n\n  const onClickDeleteWatchlistBtn = async (): Promise<void> => {\n    setIsUpdating(true);\n    try {\n      const response = await axios.delete<Watchlist>(\n        `/api/v1/watchlist/${id}?mediaType=${mediaType}`\n      );\n\n      if (response.status === 204) {\n        addToast(\n          <span>\n            {intl.formatMessage(messages.watchlistDeleted, {\n              title,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'info', autoDismiss: true }\n        );\n      }\n    } catch {\n      addToast(intl.formatMessage(messages.watchlistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      setIsUpdating(false);\n      mutate('/api/v1/discover/watchlist');\n      if (mutateParent) {\n        mutateParent();\n      }\n      setToggleWatchlist((prevState) => !prevState);\n    }\n  };\n\n  const onClickHideItemBtn = async (): Promise<void> => {\n    setIsUpdating(true);\n    const topNode = cardRef.current;\n\n    if (topNode) {\n      try {\n        await axios.post('/api/v1/blocklist', {\n          tmdbId: id,\n          mediaType,\n          title,\n          user: user?.id,\n        });\n        addToast(\n          <span>\n            {intl.formatMessage(globalMessages.blocklistSuccess, {\n              title,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'success', autoDismiss: true }\n        );\n        setCurrentStatus(MediaStatus.BLOCKLISTED);\n      } catch (e) {\n        if (e?.response?.status === 412) {\n          addToast(\n            <span>\n              {intl.formatMessage(globalMessages.blocklistDuplicateError, {\n                title,\n                strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n              })}\n            </span>,\n            { appearance: 'info', autoDismiss: true }\n          );\n        } else {\n          addToast(intl.formatMessage(globalMessages.blocklistError), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        }\n      }\n\n      setIsUpdating(false);\n      closeBlocklistModal();\n    } else {\n      addToast(intl.formatMessage(globalMessages.blocklistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n  };\n\n  const onClickShowBlocklistBtn = async (): Promise<void> => {\n    setIsUpdating(true);\n    const topNode = cardRef.current;\n\n    if (topNode) {\n      const res = await axios.delete(\n        `/api/v1/blocklist/${id}?mediaType=${mediaType}`\n      );\n\n      if (res.status === 204) {\n        addToast(\n          <span>\n            {intl.formatMessage(globalMessages.removeFromBlocklistSuccess, {\n              title,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'success', autoDismiss: true }\n        );\n        setCurrentStatus(MediaStatus.UNKNOWN);\n      } else {\n        addToast(intl.formatMessage(globalMessages.blocklistError), {\n          appearance: 'error',\n          autoDismiss: true,\n        });\n      }\n    } else {\n      addToast(intl.formatMessage(globalMessages.blocklistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    }\n\n    setIsUpdating(false);\n  };\n\n  const closeModal = useCallback(() => setShowRequestModal(false), []);\n\n  const showRequestButton = hasPermission(\n    [\n      Permission.REQUEST,\n      mediaType === 'movie' || mediaType === 'collection'\n        ? Permission.REQUEST_MOVIE\n        : Permission.REQUEST_TV,\n    ],\n    { type: 'or' }\n  );\n\n  const showHideButton = hasPermission([Permission.MANAGE_BLOCKLIST], {\n    type: 'or',\n  });\n\n  return (\n    <div\n      className={canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'}\n      data-testid=\"title-card\"\n      ref={cardRef}\n    >\n      <RequestModal\n        tmdbId={id}\n        show={showRequestModal}\n        type={\n          mediaType === 'movie'\n            ? 'movie'\n            : mediaType === 'collection'\n              ? 'collection'\n              : 'tv'\n        }\n        onComplete={requestComplete}\n        onUpdating={requestUpdating}\n        onCancel={closeModal}\n      />\n      <BlocklistModal\n        tmdbId={id}\n        type={\n          mediaType === 'movie'\n            ? 'movie'\n            : mediaType === 'collection'\n              ? 'collection'\n              : 'tv'\n        }\n        show={showBlocklistModal}\n        onCancel={closeBlocklistModal}\n        onComplete={onClickHideItemBtn}\n        isUpdating={isUpdating}\n      />\n      <div\n        className={`relative transform-gpu cursor-default overflow-hidden rounded-xl bg-gray-800 bg-cover outline-none ring-1 transition duration-300 ${\n          showDetail\n            ? 'scale-105 shadow-lg ring-gray-500'\n            : 'scale-100 shadow ring-gray-700'\n        }`}\n        style={{\n          paddingBottom: '150%',\n        }}\n        onMouseEnter={() => {\n          if (!isTouch) {\n            setShowDetail(true);\n          }\n        }}\n        onMouseLeave={() => setShowDetail(false)}\n        onClick={() => setShowDetail(true)}\n        onKeyDown={(e) => {\n          if (e.key === 'Enter') {\n            setShowDetail(true);\n          }\n        }}\n        role=\"link\"\n        tabIndex={0}\n      >\n        <div className=\"absolute inset-0 h-full w-full overflow-hidden\">\n          <CachedImage\n            type=\"tmdb\"\n            className=\"absolute inset-0 h-full w-full\"\n            alt=\"\"\n            src={\n              image\n                ? `https://image.tmdb.org/t/p/w300_and_h450_face${image}`\n                : `/images/seerr_poster_not_found_logo_top.png`\n            }\n            style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n            fill\n          />\n          <div className=\"absolute left-0 right-0 flex items-center justify-between p-2\">\n            <div\n              className={`pointer-events-none z-40 self-start rounded-full border shadow-md ${\n                mediaType === 'movie' || mediaType === 'collection'\n                  ? 'border-blue-500 bg-blue-600/80'\n                  : 'border-purple-600 bg-purple-600/80'\n              }`}\n            >\n              <div className=\"flex h-4 items-center px-2 py-2 text-center text-xs font-medium uppercase tracking-wider text-white sm:h-5\">\n                {mediaType === 'movie'\n                  ? intl.formatMessage(globalMessages.movie)\n                  : mediaType === 'collection'\n                    ? intl.formatMessage(globalMessages.collection)\n                    : intl.formatMessage(globalMessages.tvshow)}\n              </div>\n            </div>\n            {showDetail && currentStatus !== MediaStatus.BLOCKLISTED && (\n              <div className=\"flex flex-col gap-1\">\n                {user?.userType !== UserType.PLEX &&\n                  (toggleWatchlist ? (\n                    <Button\n                      buttonType={'ghost'}\n                      className=\"z-40\"\n                      buttonSize={'sm'}\n                      onClick={onClickWatchlistBtn}\n                    >\n                      <StarIcon className={'h-3 text-amber-300'} />\n                    </Button>\n                  ) : (\n                    <Button\n                      className=\"z-40\"\n                      buttonSize={'sm'}\n                      onClick={onClickDeleteWatchlistBtn}\n                    >\n                      <MinusCircleIcon className={'h-3'} />\n                    </Button>\n                  ))}\n                {showHideButton &&\n                  currentStatus !== MediaStatus.PROCESSING &&\n                  currentStatus !== MediaStatus.AVAILABLE &&\n                  currentStatus !== MediaStatus.PARTIALLY_AVAILABLE &&\n                  currentStatus !== MediaStatus.PENDING && (\n                    <Button\n                      buttonType={'ghost'}\n                      className=\"z-40\"\n                      buttonSize={'sm'}\n                      onClick={() => setShowBlocklistModal(true)}\n                    >\n                      <EyeSlashIcon className={'h-3'} />\n                    </Button>\n                  )}\n              </div>\n            )}\n            {showDetail &&\n              showHideButton &&\n              currentStatus == MediaStatus.BLOCKLISTED && (\n                <Tooltip\n                  content={intl.formatMessage(\n                    globalMessages.removefromBlocklist\n                  )}\n                >\n                  <Button\n                    buttonType={'ghost'}\n                    className=\"z-40\"\n                    buttonSize={'sm'}\n                    onClick={() => onClickShowBlocklistBtn()}\n                  >\n                    <EyeIcon className={'h-3'} />\n                  </Button>\n                </Tooltip>\n              )}\n            {currentStatus && currentStatus !== MediaStatus.UNKNOWN && (\n              <div className=\"flex flex-col items-center gap-1\">\n                <div className=\"pointer-events-none z-40 flex\">\n                  <StatusBadgeMini\n                    status={currentStatus}\n                    inProgress={inProgress}\n                    shrink\n                  />\n                </div>\n              </div>\n            )}\n          </div>\n          <Transition\n            as={Fragment}\n            show={isUpdating}\n            enter=\"transition-opacity ease-in-out duration-300\"\n            enterFrom=\"opacity-0\"\n            enterTo=\"opacity-100\"\n            leave=\"transition-opacity ease-in-out duration-300\"\n            leaveFrom=\"opacity-100\"\n            leaveTo=\"opacity-0\"\n          >\n            <div className=\"absolute inset-0 z-40 flex items-center justify-center rounded-xl bg-gray-800/75 text-white\">\n              <Spinner className=\"h-10 w-10\" />\n            </div>\n          </Transition>\n\n          <Transition\n            as={Fragment}\n            show={!image || showDetail || showRequestModal}\n            enter=\"transition-opacity\"\n            enterFrom=\"opacity-0\"\n            enterTo=\"opacity-100\"\n            leave=\"transition-opacity\"\n            leaveFrom=\"opacity-100\"\n            leaveTo=\"opacity-0\"\n          >\n            <div className=\"absolute inset-0 overflow-hidden rounded-xl\">\n              <Link\n                href={\n                  mediaType === 'movie'\n                    ? `/movie/${id}`\n                    : mediaType === 'collection'\n                      ? `/collection/${id}`\n                      : `/tv/${id}`\n                }\n                className=\"absolute inset-0 h-full w-full cursor-pointer overflow-hidden text-left\"\n                style={{\n                  background:\n                    'linear-gradient(180deg, rgba(45, 55, 72, 0.4) 0%, rgba(45, 55, 72, 0.9) 100%)',\n                }}\n              >\n                <div className=\"flex h-full w-full items-end\">\n                  <div\n                    className={`px-2 text-white ${\n                      !showRequestButton ||\n                      (currentStatus &&\n                        currentStatus !== MediaStatus.UNKNOWN &&\n                        currentStatus !== MediaStatus.DELETED)\n                        ? 'pb-2'\n                        : 'pb-11'\n                    }`}\n                  >\n                    {year && <div className=\"text-sm font-medium\">{year}</div>}\n\n                    <h1\n                      className=\"whitespace-normal text-xl font-bold leading-tight\"\n                      style={{\n                        WebkitLineClamp: 3,\n                        display: '-webkit-box',\n                        overflow: 'hidden',\n                        WebkitBoxOrient: 'vertical',\n                        wordBreak: 'break-word',\n                      }}\n                      data-testid=\"title-card-title\"\n                    >\n                      {title}\n                    </h1>\n                    <div\n                      className=\"whitespace-normal text-xs\"\n                      style={{\n                        WebkitLineClamp:\n                          !showRequestButton ||\n                          (currentStatus &&\n                            currentStatus !== MediaStatus.UNKNOWN &&\n                            currentStatus !== MediaStatus.DELETED)\n                            ? 5\n                            : 3,\n                        display: '-webkit-box',\n                        overflow: 'hidden',\n                        WebkitBoxOrient: 'vertical',\n                        wordBreak: 'break-word',\n                      }}\n                    >\n                      {summary}\n                    </div>\n                  </div>\n                </div>\n              </Link>\n\n              <div className=\"absolute bottom-0 left-0 right-0 flex justify-between px-2 py-2\">\n                {showRequestButton &&\n                  (!currentStatus ||\n                    currentStatus === MediaStatus.UNKNOWN ||\n                    currentStatus === MediaStatus.DELETED) && (\n                    <Button\n                      buttonType=\"primary\"\n                      buttonSize=\"sm\"\n                      onClick={(e) => {\n                        e.preventDefault();\n                        setShowRequestModal(true);\n                      }}\n                      className=\"h-7 w-full\"\n                    >\n                      <ArrowDownTrayIcon />\n                      <span>{intl.formatMessage(globalMessages.request)}</span>\n                    </Button>\n                  )}\n              </div>\n            </div>\n          </Transition>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default withProperties(TitleCard, { Placeholder, ErrorCard });\n"
  },
  {
    "path": "src/components/Toast/index.tsx",
    "content": "import { Transition } from '@headlessui/react';\nimport {\n  CheckCircleIcon,\n  ExclamationCircleIcon,\n  ExclamationTriangleIcon,\n  InformationCircleIcon,\n} from '@heroicons/react/24/outline';\nimport { XMarkIcon } from '@heroicons/react/24/solid';\nimport { Fragment } from 'react';\nimport type { ToastProps } from 'react-toast-notifications';\n\nconst Toast = ({\n  appearance,\n  children,\n  onDismiss,\n  transitionState,\n}: ToastProps) => {\n  return (\n    <div className=\"toast pointer-events-none flex max-w-full items-end justify-center px-2 py-2 sm:items-start sm:justify-end\">\n      <Transition\n        as={Fragment}\n        show={transitionState === 'entered'}\n        enter=\"transition duration-300 transform-gpu\"\n        enterFrom=\"opacity-0 scale-95\"\n        enterTo=\"opacity-100 scale-100\"\n        leave=\"transition duration-150 transform-gpu\"\n        leaveFrom=\"opacity-100 scale-100\"\n        leaveTo=\"opacity-0 scale-90\"\n      >\n        <div className=\"pointer-events-auto w-full max-w-sm rounded-lg bg-gray-800 shadow-lg ring-1 ring-gray-500\">\n          <div className=\"overflow-hidden rounded-lg ring-1 ring-black ring-opacity-5\">\n            <div className=\"p-4\">\n              <div className=\"flex items-start\">\n                <div className=\"flex-shrink-0\">\n                  {appearance === 'success' && (\n                    <CheckCircleIcon className=\"h-6 w-6 text-green-400\" />\n                  )}\n                  {appearance === 'error' && (\n                    <ExclamationCircleIcon className=\"h-6 w-6 text-red-500\" />\n                  )}\n                  {appearance === 'info' && (\n                    <InformationCircleIcon className=\"h-6 w-6 text-indigo-500\" />\n                  )}\n                  {appearance === 'warning' && (\n                    <ExclamationTriangleIcon className=\"h-6 w-6 text-orange-400\" />\n                  )}\n                </div>\n                <div className=\"ml-3 w-0 flex-1 text-white\">{children}</div>\n                <div className=\"ml-4 flex flex-shrink-0\">\n                  <button\n                    onClick={() => onDismiss()}\n                    className=\"inline-flex text-gray-400 transition duration-150 ease-in-out focus:text-gray-500 focus:outline-none\"\n                  >\n                    <XMarkIcon className=\"h-5 w-5\" />\n                  </button>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </Transition>\n    </div>\n  );\n};\n\nexport default Toast;\n"
  },
  {
    "path": "src/components/ToastContainer/index.tsx",
    "content": "import type { ToastContainerProps } from 'react-toast-notifications';\n\nconst ToastContainer = ({ hasToasts, ...props }: ToastContainerProps) => {\n  return (\n    <div\n      id=\"toast-container\"\n      className=\"fixed right-0 top-4 box-border max-h-full max-w-full overflow-hidden px-4\"\n      style={{\n        pointerEvents: hasToasts ? 'all' : 'none',\n        zIndex: 10000,\n        paddingTop: 'env(safe-area-inset-top)',\n      }}\n      {...props}\n    />\n  );\n};\n\nexport default ToastContainer;\n"
  },
  {
    "path": "src/components/TvDetails/Season/index.tsx",
    "content": "import AirDateBadge from '@app/components/AirDateBadge';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { SeasonWithEpisodes } from '@server/models/Tv';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.TvDetails.Season', {\n  somethingwentwrong: 'Something went wrong while retrieving season data.',\n  noepisodes: 'Episode list unavailable.',\n});\n\ntype SeasonProps = {\n  seasonNumber: number;\n  tvId: number;\n};\n\nconst Season = ({ seasonNumber, tvId }: SeasonProps) => {\n  const intl = useIntl();\n  const { data, error } = useSWR<SeasonWithEpisodes>(\n    `/api/v1/tv/${tvId}/season/${seasonNumber}`\n  );\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <div>{intl.formatMessage(messages.somethingwentwrong)}</div>;\n  }\n\n  return (\n    <div className=\"flex flex-col justify-center divide-y divide-gray-700\">\n      {data.episodes.length === 0 ? (\n        <p>{intl.formatMessage(messages.noepisodes)}</p>\n      ) : (\n        data.episodes\n          .slice()\n          .reverse()\n          .map((episode) => {\n            return (\n              <div\n                className=\"flex flex-col space-y-4 py-4 xl:flex-row xl:space-x-4 xl:space-y-4\"\n                key={`season-${seasonNumber}-episode-${episode.episodeNumber}`}\n              >\n                <div className=\"flex-1\">\n                  <div className=\"flex flex-col space-y-2 xl:flex-row xl:items-center xl:space-x-2 xl:space-y-0\">\n                    <h3 className=\"text-lg\">\n                      {episode.episodeNumber} - {episode.name}\n                    </h3>\n                    {episode.airDate && (\n                      <AirDateBadge airDate={episode.airDate} />\n                    )}\n                  </div>\n                  {episode.overview && <p>{episode.overview}</p>}\n                </div>\n                {episode.stillPath && (\n                  <div className=\"relative aspect-video xl:h-32\">\n                    <CachedImage\n                      type=\"tmdb\"\n                      className=\"rounded-lg object-contain\"\n                      src={episode.stillPath}\n                      alt=\"\"\n                      fill\n                    />\n                  </div>\n                )}\n              </div>\n            );\n          })\n      )}\n    </div>\n  );\n};\n\nexport default Season;\n"
  },
  {
    "path": "src/components/TvDetails/TvCast/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport PersonCard from '@app/components/PersonCard';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TvDetails } from '@server/models/Tv';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.TvDetails.TvCast', {\n  fullseriescast: 'Full Series Cast',\n});\n\nconst TvCast = () => {\n  const router = useRouter();\n  const intl = useIntl();\n  const { data, error } = useSWR<TvDetails>(`/api/v1/tv/${router.query.tvId}`);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[intl.formatMessage(messages.fullseriescast), data.name]}\n      />\n      <div className=\"mb-5 mt-1\">\n        <Header\n          subtext={\n            <Link href={`/tv/${data.id}`} className=\"hover:underline\">\n              {data.name}\n            </Link>\n          }\n        >\n          {intl.formatMessage(messages.fullseriescast)}\n        </Header>\n      </div>\n      <ul className=\"cards-vertical\">\n        {data?.credits.cast.map((person) => {\n          return (\n            <li key={person.id}>\n              <PersonCard\n                name={person.name}\n                personId={person.id}\n                subName={person.character}\n                profilePath={person.profilePath}\n                canExpand\n              />\n            </li>\n          );\n        })}\n      </ul>\n    </>\n  );\n};\n\nexport default TvCast;\n"
  },
  {
    "path": "src/components/TvDetails/TvCrew/index.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport PersonCard from '@app/components/PersonCard';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TvDetails } from '@server/models/Tv';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.TvDetails.TvCrew', {\n  fullseriescrew: 'Full Series Crew',\n});\n\nconst TvCrew = () => {\n  const router = useRouter();\n  const intl = useIntl();\n  const { data, error } = useSWR<TvDetails>(`/api/v1/tv/${router.query.tvId}`);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[intl.formatMessage(messages.fullseriescrew), data.name]}\n      />\n      <div className=\"mb-5 mt-1\">\n        <Header\n          subtext={\n            <Link href={`/tv/${data.id}`} className=\"hover:underline\">\n              {data.name}\n            </Link>\n          }\n        >\n          {intl.formatMessage(messages.fullseriescrew)}\n        </Header>\n      </div>\n      <ul className=\"cards-vertical\">\n        {data?.credits.crew.map((person, index) => {\n          return (\n            <li key={`crew-${person.id}-${index}`}>\n              <PersonCard\n                name={person.name}\n                personId={person.id}\n                subName={person.job}\n                profilePath={person.profilePath}\n                canExpand\n              />\n            </li>\n          );\n        })}\n      </ul>\n    </>\n  );\n};\n\nexport default TvCrew;\n"
  },
  {
    "path": "src/components/TvDetails/TvRecommendations.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TvResult } from '@server/models/Search';\nimport type { TvDetails } from '@server/models/Tv';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.TvDetails', {\n  recommendations: 'Recommendations',\n});\n\nconst TvRecommendations = () => {\n  const router = useRouter();\n  const intl = useIntl();\n  const { data: tvData } = useSWR<TvDetails>(`/api/v1/tv/${router.query.tvId}`);\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<TvResult>(`/api/v1/tv/${router.query.tvId}/recommendations`);\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[intl.formatMessage(messages.recommendations), tvData?.name]}\n      />\n      <div className=\"mb-5 mt-1\">\n        <Header\n          subtext={\n            <Link href={`/tv/${tvData?.id}`} className=\"hover:underline\">\n              {tvData?.name}\n            </Link>\n          }\n        >\n          {intl.formatMessage(messages.recommendations)}\n        </Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isReachingEnd={isReachingEnd}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default TvRecommendations;\n"
  },
  {
    "path": "src/components/TvDetails/TvSimilar.tsx",
    "content": "import Header from '@app/components/Common/Header';\nimport ListView from '@app/components/Common/ListView';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useDiscover from '@app/hooks/useDiscover';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { TvResult } from '@server/models/Search';\nimport type { TvDetails } from '@server/models/Tv';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.TvDetails', {\n  similar: 'Similar Series',\n});\n\nconst TvSimilar = () => {\n  const router = useRouter();\n  const intl = useIntl();\n  const { data: tvData } = useSWR<TvDetails>(`/api/v1/tv/${router.query.tvId}`);\n  const {\n    isLoadingInitialData,\n    isEmpty,\n    isLoadingMore,\n    isReachingEnd,\n    titles,\n    fetchMore,\n    error,\n  } = useDiscover<TvResult>(`/api/v1/tv/${router.query.tvId}/similar`);\n\n  if (error) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle title={[intl.formatMessage(messages.similar), tvData?.name]} />\n      <div className=\"mb-5 mt-1\">\n        <Header\n          subtext={\n            <Link href={`/tv/${tvData?.id}`} className=\"hover:underline\">\n              {tvData?.name}\n            </Link>\n          }\n        >\n          {intl.formatMessage(messages.similar)}\n        </Header>\n      </div>\n      <ListView\n        items={titles}\n        isEmpty={isEmpty}\n        isReachingEnd={isReachingEnd}\n        isLoading={\n          isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)\n        }\n        onScrollBottom={fetchMore}\n      />\n    </>\n  );\n};\n\nexport default TvSimilar;\n"
  },
  {
    "path": "src/components/TvDetails/index.tsx",
    "content": "import RTAudFresh from '@app/assets/rt_aud_fresh.svg';\nimport RTAudRotten from '@app/assets/rt_aud_rotten.svg';\nimport RTFresh from '@app/assets/rt_fresh.svg';\nimport RTRotten from '@app/assets/rt_rotten.svg';\nimport Spinner from '@app/assets/spinner.svg';\nimport TmdbLogo from '@app/assets/tmdb_logo.svg';\nimport BlocklistModal from '@app/components/BlocklistModal';\nimport Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport type { PlayButtonLink } from '@app/components/Common/PlayButton';\nimport PlayButton from '@app/components/Common/PlayButton';\nimport StatusBadgeMini from '@app/components/Common/StatusBadgeMini';\nimport Tag from '@app/components/Common/Tag';\nimport Tooltip from '@app/components/Common/Tooltip';\nimport ExternalLinkBlock from '@app/components/ExternalLinkBlock';\nimport IssueModal from '@app/components/IssueModal';\nimport ManageSlideOver from '@app/components/ManageSlideOver';\nimport MediaSlider from '@app/components/MediaSlider';\nimport PersonCard from '@app/components/PersonCard';\nimport RequestButton from '@app/components/RequestButton';\nimport RequestModal from '@app/components/RequestModal';\nimport Slider from '@app/components/Slider';\nimport StatusBadge from '@app/components/StatusBadge';\nimport Season from '@app/components/TvDetails/Season';\nimport useDeepLinks from '@app/hooks/useDeepLinks';\nimport useLocale from '@app/hooks/useLocale';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, UserType, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport { sortCrewPriority } from '@app/utils/creditHelpers';\nimport defineMessages from '@app/utils/defineMessages';\nimport { refreshIntervalHelper } from '@app/utils/refreshIntervalHelper';\nimport { Disclosure, Transition } from '@headlessui/react';\nimport { ChevronDownIcon } from '@heroicons/react/24/outline';\nimport {\n  ArrowRightCircleIcon,\n  CogIcon,\n  ExclamationTriangleIcon,\n  EyeSlashIcon,\n  FilmIcon,\n  MinusCircleIcon,\n  PlayIcon,\n  StarIcon,\n} from '@heroicons/react/24/solid';\nimport type { RTRating } from '@server/api/rating/rottentomatoes';\nimport { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants';\nimport { IssueStatus } from '@server/constants/issue';\nimport {\n  MediaRequestStatus,\n  MediaStatus,\n  MediaType,\n} from '@server/constants/media';\nimport { MediaServerType } from '@server/constants/server';\nimport type { Crew } from '@server/models/common';\nimport type { TvDetails as TvDetailsType } from '@server/models/Tv';\nimport axios from 'axios';\nimport { countries } from 'country-flag-icons';\nimport 'country-flag-icons/3x2/flags.css';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.TvDetails', {\n  firstAirDate: 'First Air Date',\n  nextAirDate: 'Next Air Date',\n  originallanguage: 'Original Language',\n  overview: 'Overview',\n  cast: 'Cast',\n  recommendations: 'Recommendations',\n  similar: 'Similar Series',\n  watchtrailer: 'Watch Trailer',\n  overviewunavailable: 'Overview unavailable.',\n  originaltitle: 'Original Title',\n  showtype: 'Series Type',\n  anime: 'Anime',\n  network: '{networkCount, plural, one {Network} other {Networks}}',\n  viewfullcrew: 'View Full Crew',\n  play: 'Play on {mediaServerName}',\n  play4k: 'Play 4K on {mediaServerName}',\n  seasons: '{seasonCount, plural, one {# Season} other {# Seasons}}',\n  episodeRuntime: 'Episode Runtime',\n  episodeRuntimeMinutes: '{runtime} minutes',\n  streamingproviders: 'Currently Streaming On',\n  productioncountries:\n    'Production {countryCount, plural, one {Country} other {Countries}}',\n  reportissue: 'Report an Issue',\n  manageseries: 'Manage Series',\n  seasonstitle: 'Seasons',\n  episodeCount: '{episodeCount, plural, one {# Episode} other {# Episodes}}',\n  seasonnumber: 'Season {seasonNumber}',\n  status4k: '4K {status}',\n  rtcriticsscore: 'Rotten Tomatoes Tomatometer',\n  rtaudiencescore: 'Rotten Tomatoes Audience Score',\n  tmdbuserscore: 'TMDB User Score',\n  watchlistSuccess: '<strong>{title}</strong> added to watchlist successfully!',\n  watchlistDeleted:\n    '<strong>{title}</strong> Removed from watchlist successfully!',\n  watchlistError: 'Something went wrong. Please try again.',\n  removefromwatchlist: 'Remove From Watchlist',\n  addtowatchlist: 'Add To Watchlist',\n});\n\ninterface TvDetailsProps {\n  tv?: TvDetailsType;\n}\n\nconst TvDetails = ({ tv }: TvDetailsProps) => {\n  const settings = useSettings();\n  const { user, hasPermission } = useUser();\n  const router = useRouter();\n  const intl = useIntl();\n  const { locale } = useLocale();\n  const [showRequestModal, setShowRequestModal] = useState(false);\n  const [showManager, setShowManager] = useState(router.query.manage == '1');\n  const [showIssueModal, setShowIssueModal] = useState(false);\n  const [isUpdating, setIsUpdating] = useState<boolean>(false);\n  const [toggleWatchlist, setToggleWatchlist] = useState<boolean>(\n    !tv?.onUserWatchlist\n  );\n  const [isBlocklistUpdating, setIsBlocklistUpdating] =\n    useState<boolean>(false);\n  const [showBlocklistModal, setShowBlocklistModal] = useState(false);\n  const { addToast } = useToasts();\n\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<TvDetailsType>(`/api/v1/tv/${router.query.tvId}`, {\n    fallbackData: tv,\n    refreshInterval: refreshIntervalHelper(\n      {\n        downloadStatus: tv?.mediaInfo?.downloadStatus,\n        downloadStatus4k: tv?.mediaInfo?.downloadStatus4k,\n      },\n      15000\n    ),\n  });\n\n  const { data: ratingData } = useSWR<RTRating>(\n    `/api/v1/tv/${router.query.tvId}/ratings`\n  );\n\n  const sortedCrew = useMemo(\n    () => sortCrewPriority(data?.credits.crew ?? []),\n    [data]\n  );\n\n  useEffect(() => {\n    setShowManager(router.query.manage == '1');\n  }, [router.query.manage]);\n\n  const closeBlocklistModal = useCallback(\n    () => setShowBlocklistModal(false),\n    []\n  );\n\n  const { mediaUrl: plexUrl, mediaUrl4k: plexUrl4k } = useDeepLinks({\n    mediaUrl: data?.mediaInfo?.mediaUrl,\n    mediaUrl4k: data?.mediaInfo?.mediaUrl4k,\n    iOSPlexUrl: data?.mediaInfo?.iOSPlexUrl,\n    iOSPlexUrl4k: data?.mediaInfo?.iOSPlexUrl4k,\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  const mediaLinks: PlayButtonLink[] = [];\n\n  if (\n    plexUrl &&\n    hasPermission([Permission.REQUEST, Permission.REQUEST_TV], {\n      type: 'or',\n    })\n  ) {\n    mediaLinks.push({\n      text: getAvailableMediaServerName(),\n      url: plexUrl,\n      svg: <PlayIcon />,\n    });\n  }\n\n  if (\n    settings.currentSettings.series4kEnabled &&\n    plexUrl4k &&\n    hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_TV], {\n      type: 'or',\n    })\n  ) {\n    mediaLinks.push({\n      text: getAvailable4kMediaServerName(),\n      url: plexUrl4k,\n      svg: <PlayIcon />,\n    });\n  }\n\n  const trailerVideo = data.relatedVideos\n    ?.filter((r) => r.type === 'Trailer')\n    .sort((a, b) => a.size - b.size)\n    .pop();\n  const trailerUrl =\n    trailerVideo?.site === 'YouTube' &&\n    settings.currentSettings.youtubeUrl != ''\n      ? `${settings.currentSettings.youtubeUrl}${trailerVideo?.key}`\n      : trailerVideo?.url;\n\n  if (trailerUrl) {\n    mediaLinks.push({\n      text: intl.formatMessage(messages.watchtrailer),\n      url: trailerUrl,\n      svg: <FilmIcon />,\n    });\n  }\n\n  const discoverRegion = user?.settings?.discoverRegion\n    ? user.settings.discoverRegion\n    : settings.currentSettings.discoverRegion\n      ? settings.currentSettings.discoverRegion\n      : 'US';\n  const seriesAttributes: React.ReactNode[] = [];\n\n  const contentRating = data.contentRatings.results.find(\n    (r) => r.iso_3166_1 === discoverRegion\n  )?.rating;\n  if (contentRating) {\n    seriesAttributes.push(\n      <span className=\"rounded-md border p-0.5 py-0\">{contentRating}</span>\n    );\n  }\n\n  // Does NOT include \"Specials\"\n  const seasonCount = data.seasons.filter(\n    (season) => season.seasonNumber !== 0 && season.episodeCount !== 0\n  ).length;\n\n  if (seasonCount) {\n    seriesAttributes.push(\n      intl.formatMessage(messages.seasons, { seasonCount: seasonCount })\n    );\n  }\n\n  if (data.genres.length) {\n    seriesAttributes.push(\n      data.genres\n        .map((g) => (\n          <Link\n            href={`/discover/tv?genre=${g.id}`}\n            key={`genre-${g.id}`}\n            className=\"hover:underline\"\n          >\n            {g.name}\n          </Link>\n        ))\n        .reduce((prev, curr) => (\n          <>\n            {intl.formatMessage(globalMessages.delimitedlist, {\n              a: prev,\n              b: curr,\n            })}\n          </>\n        ))\n    );\n  }\n\n  const getAllRequestedSeasons = (is4k: boolean): number[] => {\n    const requestedSeasons = (data?.mediaInfo?.requests ?? [])\n      .filter(\n        (request) =>\n          request.is4k === is4k &&\n          request.status !== MediaRequestStatus.DECLINED &&\n          request.status !== MediaRequestStatus.COMPLETED\n      )\n      .reduce((requestedSeasons, request) => {\n        return [\n          ...requestedSeasons,\n          ...request.seasons.map((sr) => sr.seasonNumber),\n        ];\n      }, [] as number[]);\n\n    const availableSeasons = (data?.mediaInfo?.seasons ?? [])\n      .filter(\n        (season) =>\n          (season[is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE ||\n            season[is4k ? 'status4k' : 'status'] ===\n              MediaStatus.PARTIALLY_AVAILABLE ||\n            season[is4k ? 'status4k' : 'status'] === MediaStatus.PROCESSING) &&\n          !requestedSeasons.includes(season.seasonNumber)\n      )\n      .map((season) => season.seasonNumber);\n\n    return [...requestedSeasons, ...availableSeasons];\n  };\n\n  const showHasSpecials = data.seasons.some(\n    (season) =>\n      season.seasonNumber === 0 &&\n      settings.currentSettings.enableSpecialEpisodes\n  );\n\n  const isComplete =\n    (showHasSpecials ? seasonCount + 1 : seasonCount) <=\n    getAllRequestedSeasons(false).length;\n\n  const is4kComplete =\n    (showHasSpecials ? seasonCount + 1 : seasonCount) <=\n    getAllRequestedSeasons(true).length;\n\n  const streamingRegion = user?.settings?.streamingRegion\n    ? user.settings.streamingRegion\n    : settings.currentSettings.streamingRegion\n      ? settings.currentSettings.streamingRegion\n      : 'US';\n  const streamingProviders =\n    data?.watchProviders?.find(\n      (provider) => provider.iso_3166_1 === streamingRegion\n    )?.flatrate ?? [];\n\n  function getAvailableMediaServerName() {\n    if (settings.currentSettings.mediaServerType === MediaServerType.EMBY) {\n      return intl.formatMessage(messages.play, { mediaServerName: 'Emby' });\n    }\n\n    if (settings.currentSettings.mediaServerType === MediaServerType.PLEX) {\n      return intl.formatMessage(messages.play, { mediaServerName: 'Plex' });\n    }\n\n    return intl.formatMessage(messages.play, { mediaServerName: 'Jellyfin' });\n  }\n\n  function getAvailable4kMediaServerName() {\n    if (settings.currentSettings.mediaServerType === MediaServerType.EMBY) {\n      return intl.formatMessage(messages.play, { mediaServerName: 'Emby' });\n    }\n\n    if (settings.currentSettings.mediaServerType === MediaServerType.PLEX) {\n      return intl.formatMessage(messages.play4k, { mediaServerName: 'Plex' });\n    }\n\n    return intl.formatMessage(messages.play, { mediaServerName: 'Jellyfin' });\n  }\n\n  const onClickWatchlistBtn = async (): Promise<void> => {\n    setIsUpdating(true);\n\n    try {\n      await axios.post('/api/v1/watchlist', {\n        tmdbId: tv?.id,\n        mediaType: MediaType.TV,\n        title: tv?.name,\n      });\n      addToast(\n        <span>\n          {intl.formatMessage(messages.watchlistSuccess, {\n            title: tv?.name,\n            strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n          })}\n        </span>,\n        { appearance: 'success', autoDismiss: true }\n      );\n\n      setIsUpdating(false);\n      setToggleWatchlist((prevState) => !prevState);\n    } catch {\n      addToast(intl.formatMessage(messages.watchlistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n\n      setIsUpdating(false);\n    }\n  };\n\n  const onClickDeleteWatchlistBtn = async (): Promise<void> => {\n    setIsUpdating(true);\n\n    try {\n      await axios.delete(\n        `/api/v1/watchlist/${tv?.id}?mediaType=${MediaType.TV}`\n      );\n\n      addToast(\n        <span>\n          {intl.formatMessage(messages.watchlistDeleted, {\n            title: tv?.name,\n            strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n          })}\n        </span>,\n        { appearance: 'info', autoDismiss: true }\n      );\n\n      setIsUpdating(false);\n      setToggleWatchlist((prevState) => !prevState);\n    } catch {\n      addToast(intl.formatMessage(messages.watchlistError), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n\n      setIsUpdating(false);\n    }\n  };\n\n  const onClickHideItemBtn = async (): Promise<void> => {\n    setIsBlocklistUpdating(true);\n\n    try {\n      const res = await axios.post('/api/v1/blocklist', {\n        tmdbId: tv?.id,\n        mediaType: 'tv',\n        title: tv?.name,\n        user: user?.id,\n      });\n\n      if (res.status === 201) {\n        addToast(\n          <span>\n            {intl.formatMessage(globalMessages.blocklistSuccess, {\n              title: tv?.name,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'success', autoDismiss: true }\n        );\n\n        revalidate();\n      }\n    } catch (e) {\n      if (e?.response?.status === 412) {\n        addToast(\n          <span>\n            {intl.formatMessage(globalMessages.blocklistDuplicateError, {\n              title: tv?.name,\n              strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n            })}\n          </span>,\n          { appearance: 'info', autoDismiss: true }\n        );\n      } else {\n        addToast(intl.formatMessage(globalMessages.blocklistError), {\n          appearance: 'error',\n          autoDismiss: true,\n        });\n      }\n    }\n\n    setIsBlocklistUpdating(false);\n    closeBlocklistModal();\n  };\n\n  const showHideButton = hasPermission([Permission.MANAGE_BLOCKLIST], {\n    type: 'or',\n  });\n\n  return (\n    <div\n      className=\"media-page\"\n      style={{\n        height: 493,\n      }}\n    >\n      {data.backdropPath && (\n        <div className=\"media-page-bg-image\">\n          <CachedImage\n            type=\"tmdb\"\n            alt=\"\"\n            src={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data.backdropPath}`}\n            style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n            fill\n            priority\n          />\n          <div\n            className=\"absolute inset-0\"\n            style={{\n              backgroundImage:\n                'linear-gradient(180deg, rgba(17, 24, 39, 0.47) 0%, rgba(17, 24, 39, 1) 100%)',\n            }}\n          />\n        </div>\n      )}\n      <PageTitle title={data.name} />\n      <BlocklistModal\n        tmdbId={data.id}\n        type=\"tv\"\n        show={showBlocklistModal}\n        onCancel={closeBlocklistModal}\n        onComplete={onClickHideItemBtn}\n        isUpdating={isBlocklistUpdating}\n      />\n      <IssueModal\n        onCancel={() => setShowIssueModal(false)}\n        show={showIssueModal}\n        mediaType=\"tv\"\n        tmdbId={data.id}\n      />\n      <RequestModal\n        tmdbId={data.id}\n        show={showRequestModal}\n        type=\"tv\"\n        onComplete={() => {\n          revalidate();\n          setShowRequestModal(false);\n        }}\n        onCancel={() => setShowRequestModal(false)}\n      />\n      <ManageSlideOver\n        data={data}\n        mediaType=\"tv\"\n        onClose={() => {\n          setShowManager(false);\n          router.push({\n            pathname: router.pathname,\n            query: { tvId: router.query.tvId },\n          });\n        }}\n        revalidate={() => revalidate()}\n        show={showManager}\n      />\n      <div className=\"media-header\">\n        <div className=\"media-poster\">\n          <CachedImage\n            type=\"tmdb\"\n            src={\n              data.posterPath\n                ? `https://image.tmdb.org/t/p/w600_and_h900_bestv2${data.posterPath}`\n                : '/images/seerr_poster_not_found.png'\n            }\n            alt=\"\"\n            sizes=\"100vw\"\n            style={{ width: '100%', height: 'auto' }}\n            width={600}\n            height={900}\n            priority\n          />\n        </div>\n        <div className=\"media-title\">\n          <div className=\"media-status\">\n            <StatusBadge\n              status={data.mediaInfo?.status}\n              downloadItem={data.mediaInfo?.downloadStatus}\n              title={data.name}\n              inProgress={(data.mediaInfo?.downloadStatus ?? []).length > 0}\n              tmdbId={data.mediaInfo?.tmdbId}\n              mediaType=\"tv\"\n              plexUrl={plexUrl}\n              serviceUrl={data.mediaInfo?.serviceUrl}\n            />\n            {settings.currentSettings.series4kEnabled &&\n              hasPermission(\n                [\n                  Permission.MANAGE_REQUESTS,\n                  Permission.REQUEST_4K,\n                  Permission.REQUEST_4K_TV,\n                ],\n                {\n                  type: 'or',\n                }\n              ) && (\n                <StatusBadge\n                  status={data.mediaInfo?.status4k}\n                  downloadItem={data.mediaInfo?.downloadStatus4k}\n                  title={data.name}\n                  is4k\n                  inProgress={\n                    (data.mediaInfo?.downloadStatus4k ?? []).length > 0\n                  }\n                  tmdbId={data.mediaInfo?.tmdbId}\n                  mediaType=\"tv\"\n                  plexUrl={plexUrl4k}\n                  serviceUrl={data.mediaInfo?.serviceUrl4k}\n                />\n              )}\n          </div>\n          <h1 data-testid=\"media-title\">\n            {data.name}{' '}\n            {data.firstAirDate && (\n              <span className=\"media-year\">\n                ({data.firstAirDate.slice(0, 4)})\n              </span>\n            )}\n          </h1>\n          <span className=\"media-attributes\">\n            {seriesAttributes.length > 0 &&\n              seriesAttributes\n                .map((t, k) => <span key={k}>{t}</span>)\n                .reduce((prev, curr) => (\n                  <>\n                    {prev}\n                    <span>|</span>\n                    {curr}\n                  </>\n                ))}\n          </span>\n        </div>\n        <div className=\"media-actions\">\n          {showHideButton &&\n            data?.mediaInfo?.status !== MediaStatus.PROCESSING &&\n            data?.mediaInfo?.status !== MediaStatus.AVAILABLE &&\n            data?.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE &&\n            data?.mediaInfo?.status !== MediaStatus.PENDING &&\n            data?.mediaInfo?.status !== MediaStatus.BLOCKLISTED && (\n              <Tooltip\n                content={intl.formatMessage(globalMessages.addToBlocklist)}\n              >\n                <Button\n                  buttonType={'ghost'}\n                  className=\"z-40 mr-2\"\n                  buttonSize={'md'}\n                  onClick={() => setShowBlocklistModal(true)}\n                >\n                  <EyeSlashIcon />\n                </Button>\n              </Tooltip>\n            )}\n          {data?.mediaInfo?.status !== MediaStatus.BLOCKLISTED &&\n            user?.userType !== UserType.PLEX && (\n              <>\n                {toggleWatchlist ? (\n                  <Tooltip\n                    content={intl.formatMessage(messages.addtowatchlist)}\n                  >\n                    <Button\n                      buttonType={'ghost'}\n                      className=\"z-40 mr-2\"\n                      buttonSize={'md'}\n                      onClick={onClickWatchlistBtn}\n                    >\n                      {isUpdating ? (\n                        <Spinner />\n                      ) : (\n                        <StarIcon className={'text-amber-300'} />\n                      )}\n                    </Button>\n                  </Tooltip>\n                ) : (\n                  <Tooltip\n                    content={intl.formatMessage(messages.removefromwatchlist)}\n                  >\n                    <Button\n                      className=\"z-40 mr-2\"\n                      buttonSize={'md'}\n                      onClick={onClickDeleteWatchlistBtn}\n                    >\n                      {isUpdating ? <Spinner /> : <MinusCircleIcon />}\n                    </Button>\n                  </Tooltip>\n                )}\n              </>\n            )}\n          <div className=\"z-20\">\n            <PlayButton links={mediaLinks} />\n          </div>\n          <RequestButton\n            mediaType=\"tv\"\n            onUpdate={() => revalidate()}\n            tmdbId={data?.id}\n            media={data?.mediaInfo}\n            isShowComplete={isComplete}\n            is4kShowComplete={is4kComplete}\n          />\n          {(data.mediaInfo?.status === MediaStatus.AVAILABLE ||\n            data.mediaInfo?.status === MediaStatus.PARTIALLY_AVAILABLE ||\n            (settings.currentSettings.series4kEnabled &&\n              hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_TV], {\n                type: 'or',\n              }) &&\n              (data.mediaInfo?.status4k === MediaStatus.AVAILABLE ||\n                data?.mediaInfo?.status4k ===\n                  MediaStatus.PARTIALLY_AVAILABLE))) &&\n            hasPermission(\n              [Permission.CREATE_ISSUES, Permission.MANAGE_ISSUES],\n              {\n                type: 'or',\n              }\n            ) && (\n              <Tooltip content={intl.formatMessage(messages.reportissue)}>\n                <Button\n                  buttonType=\"warning\"\n                  onClick={() => setShowIssueModal(true)}\n                  className=\"ml-2 first:ml-0\"\n                >\n                  <ExclamationTriangleIcon />\n                </Button>\n              </Tooltip>\n            )}\n          {hasPermission(Permission.MANAGE_REQUESTS) && data.mediaInfo && (\n            <Tooltip content={intl.formatMessage(messages.manageseries)}>\n              <Button\n                buttonType=\"ghost\"\n                onClick={() => setShowManager(true)}\n                className=\"relative ml-2 first:ml-0\"\n              >\n                <CogIcon className=\"!mr-0\" />\n                {hasPermission(\n                  [Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES],\n                  {\n                    type: 'or',\n                  }\n                ) &&\n                  (\n                    data.mediaInfo?.issues.filter(\n                      (issue) => issue.status === IssueStatus.OPEN\n                    ) ?? []\n                  ).length > 0 && (\n                    <>\n                      <div className=\"absolute -right-1 -top-1 h-3 w-3 rounded-full bg-red-600\" />\n                      <div className=\"absolute -right-1 -top-1 h-3 w-3 animate-ping rounded-full bg-red-600\" />\n                    </>\n                  )}\n              </Button>\n            </Tooltip>\n          )}\n        </div>\n      </div>\n      <div className=\"media-overview\">\n        <div className=\"media-overview-left\">\n          {data.tagline && <div className=\"tagline\">{data.tagline}</div>}\n          <h2>{intl.formatMessage(messages.overview)}</h2>\n          <p>\n            {data.overview\n              ? data.overview\n              : intl.formatMessage(messages.overviewunavailable)}\n          </p>\n          {sortedCrew.length > 0 && (\n            <>\n              <ul className=\"media-crew\">\n                {(data.createdBy.length > 0\n                  ? [\n                      ...data.createdBy.map(\n                        (person): Partial<Crew> => ({\n                          id: person.id,\n                          job: 'Creator',\n                          name: person.name,\n                        })\n                      ),\n                      ...sortedCrew,\n                    ]\n                  : sortedCrew\n                )\n                  .slice(0, 6)\n                  .map((person) => (\n                    <li key={`crew-${person.job}-${person.id}`}>\n                      <span>{person.job}</span>\n                      <Link href={`/person/${person.id}`} className=\"crew-name\">\n                        {person.name}\n                      </Link>\n                    </li>\n                  ))}\n              </ul>\n              <div className=\"mt-4 flex justify-end\">\n                <Link\n                  href={`/tv/${data.id}/crew`}\n                  className=\"flex items-center text-gray-400 transition duration-300 hover:text-gray-100\"\n                >\n                  <span>{intl.formatMessage(messages.viewfullcrew)}</span>\n                  <ArrowRightCircleIcon className=\"ml-1.5 inline-block h-5 w-5\" />\n                </Link>\n              </div>\n            </>\n          )}\n          {data.keywords.length > 0 && (\n            <div className=\"mt-6\">\n              {data.keywords.map((keyword) => (\n                <Link\n                  href={`/discover/tv?keywords=${keyword.id}`}\n                  key={`keyword-id-${keyword.id}`}\n                  className=\"mb-2 mr-2 inline-flex last:mr-0\"\n                >\n                  <Tag>{keyword.name}</Tag>\n                </Link>\n              ))}\n            </div>\n          )}\n          <h2 className=\"py-4\">{intl.formatMessage(messages.seasonstitle)}</h2>\n          <div className=\"flex w-full flex-col space-y-2\">\n            {data.seasons\n              .slice()\n              .reverse()\n              .filter(\n                (season) =>\n                  settings.currentSettings.enableSpecialEpisodes ||\n                  season.seasonNumber !== 0\n              )\n              .map((season) => {\n                const show4k =\n                  settings.currentSettings.series4kEnabled &&\n                  hasPermission(\n                    [\n                      Permission.MANAGE_REQUESTS,\n                      Permission.REQUEST_4K,\n                      Permission.REQUEST_4K_TV,\n                    ],\n                    {\n                      type: 'or',\n                    }\n                  );\n                const mSeason = (data.mediaInfo?.seasons ?? []).find(\n                  (s) =>\n                    season.seasonNumber === s.seasonNumber &&\n                    s.status !== MediaStatus.UNKNOWN\n                );\n                const mSeason4k = (data.mediaInfo?.seasons ?? []).find(\n                  (s) =>\n                    season.seasonNumber === s.seasonNumber &&\n                    s.status4k !== MediaStatus.UNKNOWN\n                );\n                const request = (data.mediaInfo?.requests ?? [])\n                  .filter(\n                    (r) =>\n                      !!r.seasons.find(\n                        (s) => s.seasonNumber === season.seasonNumber\n                      ) && !r.is4k\n                  )\n                  .sort(\n                    (a, b) =>\n                      new Date(b.createdAt).getTime() -\n                      new Date(a.createdAt).getTime()\n                  )[0];\n                const request4k = (data.mediaInfo?.requests ?? [])\n                  .filter(\n                    (r) =>\n                      !!r.seasons.find(\n                        (s) => s.seasonNumber === season.seasonNumber\n                      ) && r.is4k\n                  )\n                  .sort(\n                    (a, b) =>\n                      new Date(b.createdAt).getTime() -\n                      new Date(a.createdAt).getTime()\n                  )[0];\n\n                if (season.episodeCount === 0) {\n                  return null;\n                }\n\n                return (\n                  <Disclosure key={`season-discoslure-${season.seasonNumber}`}>\n                    {({ open }) => (\n                      <>\n                        <Disclosure.Button\n                          className={`mt-2 flex w-full items-center justify-between space-x-2 border-gray-700 bg-gray-800 px-4 py-2 text-gray-200 ${\n                            open\n                              ? 'rounded-t-md border-l border-r border-t'\n                              : 'rounded-md border'\n                          }`}\n                        >\n                          <div className=\"flex flex-1 items-center space-x-2 text-lg\">\n                            <span>\n                              {season.seasonNumber === 0\n                                ? intl.formatMessage(globalMessages.specials)\n                                : intl.formatMessage(messages.seasonnumber, {\n                                    seasonNumber: season.seasonNumber,\n                                  })}\n                            </span>\n                            <Badge badgeType=\"dark\">\n                              {intl.formatMessage(messages.episodeCount, {\n                                episodeCount: season.episodeCount,\n                              })}\n                            </Badge>\n                          </div>\n                          {((!mSeason &&\n                            request?.status === MediaRequestStatus.APPROVED) ||\n                            mSeason?.status === MediaStatus.PROCESSING ||\n                            (request?.status === MediaRequestStatus.APPROVED &&\n                              mSeason?.status === MediaStatus.DELETED)) && (\n                            <>\n                              <div className=\"hidden md:flex\">\n                                <Badge badgeType=\"primary\">\n                                  {intl.formatMessage(globalMessages.requested)}\n                                </Badge>\n                              </div>\n                              <div className=\"flex md:hidden\">\n                                <StatusBadgeMini\n                                  status={MediaStatus.PROCESSING}\n                                />\n                              </div>\n                            </>\n                          )}\n                          {((!mSeason &&\n                            request?.status === MediaRequestStatus.PENDING) ||\n                            mSeason?.status === MediaStatus.PENDING) && (\n                            <>\n                              <div className=\"hidden md:flex\">\n                                <Badge badgeType=\"warning\">\n                                  {intl.formatMessage(globalMessages.pending)}\n                                </Badge>\n                              </div>\n                              <div className=\"flex md:hidden\">\n                                <StatusBadgeMini status={MediaStatus.PENDING} />\n                              </div>\n                            </>\n                          )}\n                          {mSeason?.status ===\n                            MediaStatus.PARTIALLY_AVAILABLE && (\n                            <>\n                              <div className=\"hidden md:flex\">\n                                <Badge badgeType=\"success\">\n                                  {intl.formatMessage(\n                                    globalMessages.partiallyavailable\n                                  )}\n                                </Badge>\n                              </div>\n                              <div className=\"flex md:hidden\">\n                                <StatusBadgeMini\n                                  status={MediaStatus.PARTIALLY_AVAILABLE}\n                                />\n                              </div>\n                            </>\n                          )}\n                          {mSeason?.status === MediaStatus.AVAILABLE && (\n                            <>\n                              <div className=\"hidden md:flex\">\n                                <Badge badgeType=\"success\">\n                                  {intl.formatMessage(globalMessages.available)}\n                                </Badge>\n                              </div>\n                              <div className=\"flex md:hidden\">\n                                <StatusBadgeMini\n                                  status={MediaStatus.AVAILABLE}\n                                />\n                              </div>\n                            </>\n                          )}\n                          {mSeason?.status === MediaStatus.DELETED &&\n                            request?.status !== MediaRequestStatus.APPROVED && (\n                              <>\n                                <div className=\"hidden md:flex\">\n                                  <Badge badgeType=\"danger\">\n                                    {intl.formatMessage(globalMessages.deleted)}\n                                  </Badge>\n                                </div>\n                                <div className=\"flex md:hidden\">\n                                  <StatusBadgeMini\n                                    status={MediaStatus.DELETED}\n                                  />\n                                </div>\n                              </>\n                            )}\n                          {((!mSeason4k &&\n                            request4k?.status ===\n                              MediaRequestStatus.APPROVED) ||\n                            mSeason4k?.status4k === MediaStatus.PROCESSING ||\n                            (request4k?.status ===\n                              MediaRequestStatus.APPROVED &&\n                              mSeason4k?.status4k === MediaStatus.DELETED)) &&\n                            show4k && (\n                              <>\n                                <div className=\"hidden md:flex\">\n                                  <Badge badgeType=\"primary\">\n                                    {intl.formatMessage(messages.status4k, {\n                                      status: intl.formatMessage(\n                                        globalMessages.requested\n                                      ),\n                                    })}\n                                  </Badge>\n                                </div>\n                                <div className=\"flex md:hidden\">\n                                  <StatusBadgeMini\n                                    status={MediaStatus.PROCESSING}\n                                    is4k={true}\n                                  />\n                                </div>\n                              </>\n                            )}\n                          {((!mSeason4k &&\n                            request4k?.status === MediaRequestStatus.PENDING) ||\n                            mSeason?.status4k === MediaStatus.PENDING) &&\n                            show4k && (\n                              <>\n                                <div className=\"hidden md:flex\">\n                                  <Badge badgeType=\"warning\">\n                                    {intl.formatMessage(messages.status4k, {\n                                      status: intl.formatMessage(\n                                        globalMessages.pending\n                                      ),\n                                    })}\n                                  </Badge>\n                                </div>\n                                <div className=\"flex md:hidden\">\n                                  <StatusBadgeMini\n                                    status={MediaStatus.PENDING}\n                                    is4k={true}\n                                  />\n                                </div>\n                              </>\n                            )}\n                          {mSeason4k?.status4k ===\n                            MediaStatus.PARTIALLY_AVAILABLE &&\n                            show4k && (\n                              <>\n                                <div className=\"hidden md:flex\">\n                                  <Badge badgeType=\"success\">\n                                    {intl.formatMessage(messages.status4k, {\n                                      status: intl.formatMessage(\n                                        globalMessages.partiallyavailable\n                                      ),\n                                    })}\n                                  </Badge>\n                                </div>\n                                <div className=\"flex md:hidden\">\n                                  <StatusBadgeMini\n                                    status={MediaStatus.PARTIALLY_AVAILABLE}\n                                    is4k={true}\n                                  />\n                                </div>\n                              </>\n                            )}\n                          {mSeason4k?.status4k === MediaStatus.AVAILABLE &&\n                            show4k && (\n                              <>\n                                <div className=\"hidden md:flex\">\n                                  <Badge badgeType=\"success\">\n                                    {intl.formatMessage(messages.status4k, {\n                                      status: intl.formatMessage(\n                                        globalMessages.available\n                                      ),\n                                    })}\n                                  </Badge>\n                                </div>\n                                <div className=\"flex md:hidden\">\n                                  <StatusBadgeMini\n                                    status={MediaStatus.AVAILABLE}\n                                    is4k={true}\n                                  />\n                                </div>\n                              </>\n                            )}\n                          {mSeason4k?.status4k === MediaStatus.DELETED &&\n                            request4k?.status !== MediaRequestStatus.APPROVED &&\n                            show4k && (\n                              <>\n                                <div className=\"hidden md:flex\">\n                                  <Badge badgeType=\"danger\">\n                                    {intl.formatMessage(messages.status4k, {\n                                      status: intl.formatMessage(\n                                        globalMessages.deleted\n                                      ),\n                                    })}\n                                  </Badge>\n                                </div>\n                                <div className=\"flex md:hidden\">\n                                  <StatusBadgeMini\n                                    status={MediaStatus.DELETED}\n                                    is4k={true}\n                                  />\n                                </div>\n                              </>\n                            )}\n                          <ChevronDownIcon\n                            className={`${\n                              open ? 'rotate-180' : ''\n                            } h-6 w-6 text-gray-500`}\n                          />\n                        </Disclosure.Button>\n                        <Transition\n                          show={open}\n                          enter=\"transition-opacity duration-100 ease-out\"\n                          enterFrom=\"opacity-0\"\n                          enterTo=\"opacity-100\"\n                          leave=\"transition-opacity duration-75 ease-out\"\n                          leaveFrom=\"opacity-100\"\n                          leaveTo=\"opacity-0\"\n                          // Not sure why this transition is adding a margin without this here\n                          style={{ margin: '0px' }}\n                        >\n                          <Disclosure.Panel className=\"w-full rounded-b-md border-b border-l border-r border-gray-700 px-4 pb-2\">\n                            <Season\n                              tvId={data.id}\n                              seasonNumber={season.seasonNumber}\n                            />\n                          </Disclosure.Panel>\n                        </Transition>\n                      </>\n                    )}\n                  </Disclosure>\n                );\n              })}\n          </div>\n        </div>\n        <div className=\"media-overview-right\">\n          <div className=\"media-facts\">\n            {(!!data.voteCount ||\n              (ratingData?.criticsRating && !!ratingData?.criticsScore) ||\n              (ratingData?.audienceRating && !!ratingData?.audienceScore)) && (\n              <div className=\"media-ratings\">\n                {ratingData?.criticsRating && !!ratingData?.criticsScore && (\n                  <Tooltip\n                    content={intl.formatMessage(messages.rtcriticsscore)}\n                  >\n                    <a\n                      href={ratingData.url}\n                      className=\"media-rating\"\n                      target=\"_blank\"\n                      rel=\"noreferrer\"\n                    >\n                      {ratingData.criticsRating === 'Rotten' ? (\n                        <RTRotten className=\"mr-1 w-6\" />\n                      ) : (\n                        <RTFresh className=\"mr-1 w-6\" />\n                      )}\n                      <span>{ratingData.criticsScore}%</span>\n                    </a>\n                  </Tooltip>\n                )}\n                {ratingData?.audienceRating && !!ratingData?.audienceScore && (\n                  <Tooltip\n                    content={intl.formatMessage(messages.rtaudiencescore)}\n                  >\n                    <a\n                      href={ratingData.url}\n                      className=\"media-rating\"\n                      target=\"_blank\"\n                      rel=\"noreferrer\"\n                    >\n                      {ratingData.audienceRating === 'Spilled' ? (\n                        <RTAudRotten className=\"mr-1 w-6\" />\n                      ) : (\n                        <RTAudFresh className=\"mr-1 w-6\" />\n                      )}\n                      <span>{ratingData.audienceScore}%</span>\n                    </a>\n                  </Tooltip>\n                )}\n                {!!data.voteCount && (\n                  <Tooltip content={intl.formatMessage(messages.tmdbuserscore)}>\n                    <a\n                      href={`https://www.themoviedb.org/tv/${data.id}?language=${locale}`}\n                      className=\"media-rating\"\n                      target=\"_blank\"\n                      rel=\"noreferrer\"\n                    >\n                      <TmdbLogo className=\"mr-1 w-6\" />\n                      <span>{Math.round(data.voteAverage * 10)}%</span>\n                    </a>\n                  </Tooltip>\n                )}\n              </div>\n            )}\n            {data.originalName &&\n              data.originalLanguage !== locale.slice(0, 2) && (\n                <div className=\"media-fact\">\n                  <span>{intl.formatMessage(messages.originaltitle)}</span>\n                  <span className=\"media-fact-value\">{data.originalName}</span>\n                </div>\n              )}\n            {data.keywords.some(\n              (keyword) => keyword.id === ANIME_KEYWORD_ID\n            ) && (\n              <div className=\"media-fact\">\n                <span>{intl.formatMessage(messages.showtype)}</span>\n                <span className=\"media-fact-value\">\n                  {intl.formatMessage(messages.anime)}\n                </span>\n              </div>\n            )}\n            <div className=\"media-fact\">\n              <span>{intl.formatMessage(globalMessages.status)}</span>\n              <span className=\"media-fact-value\">{data.status}</span>\n            </div>\n            {data.firstAirDate && (\n              <div className=\"media-fact\">\n                <span>{intl.formatMessage(messages.firstAirDate)}</span>\n                <span className=\"media-fact-value\">\n                  {intl.formatDate(data.firstAirDate, {\n                    year: 'numeric',\n                    month: 'long',\n                    day: 'numeric',\n                    timeZone: 'UTC',\n                  })}\n                </span>\n              </div>\n            )}\n            {data.nextEpisodeToAir &&\n              data.nextEpisodeToAir.airDate &&\n              data.nextEpisodeToAir.airDate !== data.firstAirDate && (\n                <div className=\"media-fact\">\n                  <span>{intl.formatMessage(messages.nextAirDate)}</span>\n                  <span className=\"media-fact-value\">\n                    {intl.formatDate(data.nextEpisodeToAir.airDate, {\n                      year: 'numeric',\n                      month: 'long',\n                      day: 'numeric',\n                      timeZone: 'UTC',\n                    })}\n                  </span>\n                </div>\n              )}\n            {data.episodeRunTime.length > 0 && (\n              <div className=\"media-fact\">\n                <span>{intl.formatMessage(messages.episodeRuntime)}</span>\n                <span className=\"media-fact-value\">\n                  {intl.formatMessage(messages.episodeRuntimeMinutes, {\n                    runtime: data.episodeRunTime[0],\n                  })}\n                </span>\n              </div>\n            )}\n            {data.originalLanguage && (\n              <div className=\"media-fact\">\n                <span>{intl.formatMessage(messages.originallanguage)}</span>\n                <span className=\"media-fact-value\">\n                  <Link href={`/discover/tv/language/${data.originalLanguage}`}>\n                    {intl.formatDisplayName(data.originalLanguage, {\n                      type: 'language',\n                      fallback: 'none',\n                    }) ??\n                      data.spokenLanguages.find(\n                        (lng) => lng.iso_639_1 === data.originalLanguage\n                      )?.name}\n                  </Link>\n                </span>\n              </div>\n            )}\n            {data.productionCountries.length > 0 && (\n              <div className=\"media-fact\">\n                <span>\n                  {intl.formatMessage(messages.productioncountries, {\n                    countryCount: data.productionCountries.length,\n                  })}\n                </span>\n                <span className=\"media-fact-value\">\n                  {data.productionCountries.map((c) => {\n                    return (\n                      <span\n                        className=\"flex items-center justify-end\"\n                        key={`prodcountry-${c.iso_3166_1}`}\n                      >\n                        {countries.includes(c.iso_3166_1) && (\n                          <span\n                            className={`mr-1.5 text-xs leading-5 flag:${c.iso_3166_1}`}\n                          />\n                        )}\n                        <span>\n                          {intl.formatDisplayName(c.iso_3166_1, {\n                            type: 'region',\n                            fallback: 'none',\n                          }) ?? c.name}\n                        </span>\n                      </span>\n                    );\n                  })}\n                </span>\n              </div>\n            )}\n            {data.networks.length > 0 && (\n              <div className=\"media-fact\">\n                <span>\n                  {intl.formatMessage(messages.network, {\n                    networkCount: data.networks.length,\n                  })}\n                </span>\n                <span className=\"media-fact-value\">\n                  {data.networks\n                    .map((n) => (\n                      <Link\n                        href={`/discover/tv/network/${n.id}`}\n                        key={`network-${n.id}`}\n                      >\n                        {n.name}\n                      </Link>\n                    ))\n                    .reduce((prev, curr) => (\n                      <>\n                        {intl.formatMessage(globalMessages.delimitedlist, {\n                          a: prev,\n                          b: curr,\n                        })}\n                      </>\n                    ))}\n                </span>\n              </div>\n            )}\n            {!!streamingProviders.length && (\n              <div className=\"media-fact flex-col gap-1\">\n                <span>{intl.formatMessage(messages.streamingproviders)}</span>\n                <span className=\"media-fact-value flex flex-row flex-wrap gap-5\">\n                  {streamingProviders.map((p) => {\n                    return (\n                      <Tooltip content={p.name}>\n                        <span\n                          className=\"opacity-50 transition duration-300 hover:opacity-100\"\n                          key={`provider-${p.id}`}\n                        >\n                          <CachedImage\n                            type=\"tmdb\"\n                            src={'https://image.tmdb.org/t/p/w45/' + p.logoPath}\n                            alt={p.name}\n                            width={32}\n                            height={32}\n                            className=\"rounded-md\"\n                          />\n                        </span>\n                      </Tooltip>\n                    );\n                  })}\n                </span>\n              </div>\n            )}\n            <div className=\"media-fact\">\n              <ExternalLinkBlock\n                mediaType=\"tv\"\n                tmdbId={data.id}\n                tvdbId={data.externalIds.tvdbId}\n                imdbId={data.externalIds.imdbId}\n                rtUrl={ratingData?.url}\n                mediaUrl={plexUrl ?? plexUrl4k}\n              />\n            </div>\n          </div>\n        </div>\n      </div>\n      {data.credits.cast.length > 0 && (\n        <>\n          <div className=\"slider-header\">\n            <Link\n              href=\"/tv/[tvId]/cast\"\n              as={`/tv/${data.id}/cast`}\n              className=\"slider-title\"\n            >\n              <span>{intl.formatMessage(messages.cast)}</span>\n              <ArrowRightCircleIcon />\n            </Link>\n          </div>\n          <Slider\n            sliderKey=\"cast\"\n            isLoading={false}\n            isEmpty={false}\n            items={data.credits.cast.slice(0, 20).map((person) => (\n              <PersonCard\n                key={`cast-item-${person.id}`}\n                personId={person.id}\n                name={person.name}\n                subName={person.character}\n                profilePath={person.profilePath}\n              />\n            ))}\n          />\n        </>\n      )}\n      <MediaSlider\n        sliderKey=\"recommendations\"\n        title={intl.formatMessage(messages.recommendations)}\n        url={`/api/v1/tv/${router.query.tvId}/recommendations`}\n        linkUrl={`/tv/${data.id}/recommendations`}\n        hideWhenEmpty\n      />\n      <MediaSlider\n        sliderKey=\"similar\"\n        title={intl.formatMessage(messages.similar)}\n        url={`/api/v1/tv/${router.query.tvId}/similar`}\n        linkUrl={`/tv/${data.id}/similar`}\n        hideWhenEmpty\n      />\n      <div className=\"extra-bottom-space relative\" />\n    </div>\n  );\n};\n\nexport default TvDetails;\n"
  },
  {
    "path": "src/components/UserList/BulkEditModal.tsx",
    "content": "import Modal from '@app/components/Common/Modal';\nimport PermissionEdit from '@app/components/PermissionEdit';\nimport type { User } from '@app/hooks/useUser';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { hasPermission } from '@server/lib/permissions';\nimport axios from 'axios';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\n\ninterface BulkEditProps {\n  selectedUserIds: number[];\n  users?: User[];\n  onCancel?: () => void;\n  onComplete?: (updatedUsers: User[]) => void;\n  onSaving?: (isSaving: boolean) => void;\n}\n\nconst messages = defineMessages('components.UserList', {\n  userssaved: 'User permissions saved successfully!',\n  userfail: 'Something went wrong while saving user permissions.',\n  edituser: 'Edit User Permissions',\n});\n\nconst BulkEditModal = ({\n  selectedUserIds,\n  users,\n  onCancel,\n  onComplete,\n  onSaving,\n}: BulkEditProps) => {\n  const { user: currentUser } = useUser();\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const [currentPermission, setCurrentPermission] = useState(0);\n  const [isSaving, setIsSaving] = useState(false);\n\n  useEffect(() => {\n    if (onSaving) {\n      onSaving(isSaving);\n    }\n  }, [isSaving, onSaving]);\n\n  const updateUsers = async () => {\n    try {\n      setIsSaving(true);\n      const { data: updated } = await axios.put<User[]>(`/api/v1/user`, {\n        ids: selectedUserIds,\n        permissions: currentPermission,\n      });\n      if (onComplete) {\n        onComplete(updated);\n      }\n      addToast(intl.formatMessage(messages.userssaved), {\n        appearance: 'success',\n        autoDismiss: true,\n      });\n    } catch {\n      addToast(intl.formatMessage(messages.userfail), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      setIsSaving(false);\n    }\n  };\n\n  useEffect(() => {\n    if (users) {\n      const selectedUsers = users.filter((u) => selectedUserIds.includes(u.id));\n      const { permissions: allPermissionsEqual } = selectedUsers.reduce(\n        ({ permissions: aPerms }, { permissions: bPerms }) => {\n          return {\n            permissions:\n              aPerms === bPerms || hasPermission(Permission.ADMIN, aPerms)\n                ? aPerms\n                : NaN,\n          };\n        },\n        { permissions: selectedUsers[0].permissions }\n      );\n      if (allPermissionsEqual) {\n        setCurrentPermission(allPermissionsEqual);\n      }\n    }\n  }, [users, selectedUserIds]);\n\n  return (\n    <Modal\n      title={intl.formatMessage(messages.edituser)}\n      onOk={() => {\n        updateUsers();\n      }}\n      okDisabled={isSaving}\n      okText={intl.formatMessage(globalMessages.save)}\n      onCancel={onCancel}\n    >\n      <div className=\"mb-6\">\n        <PermissionEdit\n          actingUser={currentUser}\n          currentPermission={currentPermission}\n          onUpdate={(newPermission) => setCurrentPermission(newPermission)}\n        />\n      </div>\n    </Modal>\n  );\n};\n\nexport default BulkEditModal;\n"
  },
  {
    "path": "src/components/UserList/JellyfinImportModal.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport Modal from '@app/components/Common/Modal';\nimport useSettings from '@app/hooks/useSettings';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { MediaServerType } from '@server/constants/server';\nimport type { UserResultsResponse } from '@server/interfaces/api/userInterfaces';\nimport axios from 'axios';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\ninterface JellyfinImportProps {\n  onCancel?: () => void;\n  onComplete?: () => void;\n  children?: React.ReactNode;\n}\n\nconst messages = defineMessages('components.UserList', {\n  importfromJellyfin: 'Import {mediaServerName} Users',\n  importfromJellyfinerror:\n    'Something went wrong while importing {mediaServerName} users.',\n  importedfromJellyfin:\n    '<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} imported successfully!',\n  user: 'User',\n  noJellyfinuserstoimport: 'There are no {mediaServerName} users to import.',\n  newJellyfinsigninenabled:\n    'The <strong>Enable New {mediaServerName} Sign-In</strong> setting is currently enabled. {mediaServerName} users with library access do not need to be imported in order to sign in.',\n});\n\nconst JellyfinImportModal: React.FC<JellyfinImportProps> = ({\n  onCancel,\n  onComplete,\n  children,\n}) => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const { addToast } = useToasts();\n  const [isImporting, setImporting] = useState(false);\n  const [selectedUsers, setSelectedUsers] = useState<string[]>([]);\n  const { data, error } = useSWR<\n    {\n      id: string;\n      title: string;\n      username: string;\n      email: string;\n      thumb: string;\n    }[]\n  >(`/api/v1/settings/jellyfin/users`, {\n    revalidateOnMount: true,\n  });\n\n  const { data: existingUsers } = useSWR<UserResultsResponse>(\n    `/api/v1/user?take=${children}`\n  );\n\n  const importUsers = async () => {\n    setImporting(true);\n\n    try {\n      const { data: createdUsers } = await axios.post(\n        '/api/v1/user/import-from-jellyfin',\n        { jellyfinUserIds: selectedUsers }\n      );\n\n      if (!createdUsers.length) {\n        throw new Error('No users were imported from Jellyfin.');\n      }\n\n      addToast(\n        intl.formatMessage(messages.importedfromJellyfin, {\n          userCount: createdUsers.length,\n          strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n          mediaServerName:\n            settings.currentSettings.mediaServerType === MediaServerType.EMBY\n              ? 'Emby'\n              : 'Jellyfin',\n        }),\n        {\n          autoDismiss: true,\n          appearance: 'success',\n        }\n      );\n\n      if (onComplete) {\n        onComplete();\n      }\n    } catch {\n      addToast(\n        intl.formatMessage(messages.importfromJellyfinerror, {\n          mediaServerName:\n            settings.currentSettings.mediaServerType === MediaServerType.EMBY\n              ? 'Emby'\n              : 'Jellyfin',\n        }),\n        {\n          autoDismiss: true,\n          appearance: 'error',\n        }\n      );\n    } finally {\n      setImporting(false);\n    }\n  };\n\n  const isSelectedUser = (JellyfinId: string): boolean =>\n    selectedUsers.includes(JellyfinId);\n\n  const isAllUsers = (): boolean => selectedUsers.length === data?.length;\n\n  const toggleUser = (JellyfinId: string): void => {\n    if (selectedUsers.includes(JellyfinId)) {\n      setSelectedUsers((users) => users.filter((user) => user !== JellyfinId));\n    } else {\n      setSelectedUsers((users) => [...users, JellyfinId]);\n    }\n  };\n\n  const toggleAllUsers = (): void => {\n    if (data && selectedUsers.length >= 0 && !isAllUsers()) {\n      setSelectedUsers(data.map((user) => user.id));\n    } else {\n      setSelectedUsers([]);\n    }\n  };\n\n  return (\n    <Modal\n      loading={!data && !error}\n      title={intl.formatMessage(messages.importfromJellyfin, {\n        mediaServerName:\n          settings.currentSettings.mediaServerType === MediaServerType.EMBY\n            ? 'Emby'\n            : 'Jellyfin',\n      })}\n      onOk={() => {\n        importUsers();\n      }}\n      okDisabled={isImporting || !selectedUsers.length}\n      okText={intl.formatMessage(\n        isImporting ? globalMessages.importing : globalMessages.import\n      )}\n      onCancel={onCancel}\n    >\n      {data?.length ? (\n        <>\n          {settings.currentSettings.newPlexLogin && (\n            <Alert\n              title={intl.formatMessage(messages.newJellyfinsigninenabled, {\n                mediaServerName:\n                  settings.currentSettings.mediaServerType ===\n                  MediaServerType.EMBY\n                    ? 'Emby'\n                    : 'Jellyfin',\n                strong: (msg: React.ReactNode) => (\n                  <strong className=\"font-semibold text-white\">{msg}</strong>\n                ),\n              })}\n              type=\"info\"\n            />\n          )}\n          <div className=\"flex flex-col\">\n            <div className=\"-mx-4 sm:mx-0\">\n              <div className=\"inline-block min-w-full py-2 align-middle\">\n                <div className=\"overflow-hidden shadow sm:rounded-lg\">\n                  <table className=\"min-w-full\">\n                    <thead>\n                      <tr>\n                        <th className=\"w-16 bg-gray-500 px-4 py-3\">\n                          <span\n                            role=\"checkbox\"\n                            tabIndex={0}\n                            aria-checked={isAllUsers()}\n                            onClick={() => toggleAllUsers()}\n                            onKeyDown={(e) => {\n                              if (e.key === 'Enter' || e.key === 'Space') {\n                                toggleAllUsers();\n                              }\n                            }}\n                            className=\"relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center pt-2 focus:outline-none\"\n                          >\n                            <span\n                              aria-hidden=\"true\"\n                              className={`${\n                                isAllUsers() ? 'bg-indigo-500' : 'bg-gray-800'\n                              } absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}\n                            />\n                            <span\n                              aria-hidden=\"true\"\n                              className={`${\n                                isAllUsers() ? 'translate-x-5' : 'translate-x-0'\n                              } absolute left-0 inline-block h-5 w-5 transform rounded-full border border-gray-200 bg-white shadow transition-transform duration-200 ease-in-out group-focus:border-blue-300 group-focus:ring`}\n                            />\n                          </span>\n                        </th>\n                        <th className=\"bg-gray-500 px-1 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6\">\n                          {intl.formatMessage(messages.user)}\n                        </th>\n                      </tr>\n                    </thead>\n                    <tbody className=\"divide-y divide-gray-700 bg-gray-600\">\n                      {data\n                        ?.filter(\n                          (user) =>\n                            !existingUsers?.results.some(\n                              (u) => u.jellyfinUserId === user.id\n                            )\n                        )\n                        .map((user) => (\n                          <tr key={`user-${user.id}`}>\n                            <td className=\"whitespace-nowrap px-4 py-4 text-sm font-medium leading-5 text-gray-100\">\n                              <span\n                                role=\"checkbox\"\n                                tabIndex={0}\n                                aria-checked={isSelectedUser(user.id)}\n                                onClick={() => toggleUser(user.id)}\n                                onKeyDown={(e) => {\n                                  if (e.key === 'Enter' || e.key === 'Space') {\n                                    toggleUser(user.id);\n                                  }\n                                }}\n                                className=\"relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center pt-2 focus:outline-none\"\n                              >\n                                <span\n                                  aria-hidden=\"true\"\n                                  className={`${\n                                    isSelectedUser(user.id)\n                                      ? 'bg-indigo-500'\n                                      : 'bg-gray-800'\n                                  } absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}\n                                />\n                                <span\n                                  aria-hidden=\"true\"\n                                  className={`${\n                                    isSelectedUser(user.id)\n                                      ? 'translate-x-5'\n                                      : 'translate-x-0'\n                                  } absolute left-0 inline-block h-5 w-5 transform rounded-full border border-gray-200 bg-white shadow transition-transform duration-200 ease-in-out group-focus:border-blue-300 group-focus:ring`}\n                                />\n                              </span>\n                            </td>\n                            <td className=\"whitespace-nowrap px-1 py-4 text-sm font-medium leading-5 text-gray-100 md:px-6\">\n                              <div className=\"flex items-center\">\n                                <CachedImage\n                                  type=\"avatar\"\n                                  className=\"h-10 w-10 flex-shrink-0 rounded-full\"\n                                  src={user.thumb}\n                                  alt=\"\"\n                                  width={40}\n                                  height={40}\n                                />\n                                <div className=\"ml-4\">\n                                  <div className=\"text-base font-bold leading-5\">\n                                    {user.username}\n                                  </div>\n                                  {/* {user.username &&\n                                  user.username.toLowerCase() !==\n                                  user.email && (\n                                    <div className=\"text-sm leading-5 text-gray-300\">\n                                      {user.email}\n                                    </div>\n                                  )} */}\n                                </div>\n                              </div>\n                            </td>\n                          </tr>\n                        ))}\n                    </tbody>\n                  </table>\n                </div>\n              </div>\n            </div>\n          </div>\n        </>\n      ) : (\n        <Alert\n          title={intl.formatMessage(messages.noJellyfinuserstoimport, {\n            mediaServerName:\n              settings.currentSettings.mediaServerType === MediaServerType.EMBY\n                ? 'Emby'\n                : 'Jellyfin',\n          })}\n          type=\"info\"\n        />\n      )}\n    </Modal>\n  );\n};\n\nexport default JellyfinImportModal;\n"
  },
  {
    "path": "src/components/UserList/PlexImportModal.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Modal from '@app/components/Common/Modal';\nimport useSettings from '@app/hooks/useSettings';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport axios from 'axios';\nimport Image from 'next/image';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\ninterface PlexImportProps {\n  onCancel?: () => void;\n  onComplete?: () => void;\n}\n\nconst messages = defineMessages('components.UserList', {\n  importfromplex: 'Import Plex Users',\n  importfromplexerror: 'Something went wrong while importing Plex users.',\n  importedfromplex:\n    '<strong>{userCount}</strong> Plex {userCount, plural, one {user} other {users}} imported successfully!',\n  user: 'User',\n  nouserstoimport: 'There are no Plex users to import.',\n  newplexsigninenabled:\n    'The <strong>Enable New Plex Sign-In</strong> setting is currently enabled. Plex users with library access do not need to be imported in order to sign in.',\n});\n\nconst PlexImportModal = ({ onCancel, onComplete }: PlexImportProps) => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const { addToast } = useToasts();\n  const [isImporting, setImporting] = useState(false);\n  const [selectedUsers, setSelectedUsers] = useState<string[]>([]);\n  const { data, error } = useSWR<\n    {\n      id: string;\n      title: string;\n      username: string;\n      email: string;\n      thumb: string;\n    }[]\n  >(`/api/v1/settings/plex/users`, {\n    revalidateOnMount: true,\n  });\n\n  const importUsers = async () => {\n    setImporting(true);\n\n    try {\n      const { data: createdUsers } = await axios.post(\n        '/api/v1/user/import-from-plex',\n        { plexIds: selectedUsers }\n      );\n\n      if (!Array.isArray(createdUsers) || createdUsers.length === 0) {\n        throw new Error('No users were imported from Plex.');\n      }\n\n      addToast(\n        intl.formatMessage(messages.importedfromplex, {\n          userCount: createdUsers.length,\n          strong: (msg: React.ReactNode) => <strong>{msg}</strong>,\n        }),\n        {\n          autoDismiss: true,\n          appearance: 'success',\n        }\n      );\n\n      if (onComplete) {\n        onComplete();\n      }\n    } catch {\n      addToast(intl.formatMessage(messages.importfromplexerror), {\n        autoDismiss: true,\n        appearance: 'error',\n      });\n    } finally {\n      setImporting(false);\n    }\n  };\n\n  const isSelectedUser = (plexId: string): boolean =>\n    selectedUsers.includes(plexId);\n\n  const isAllUsers = (): boolean => selectedUsers.length === data?.length;\n\n  const toggleUser = (plexId: string): void => {\n    if (selectedUsers.includes(plexId)) {\n      setSelectedUsers((users) => users.filter((user) => user !== plexId));\n    } else {\n      setSelectedUsers((users) => [...users, plexId]);\n    }\n  };\n\n  const toggleAllUsers = (): void => {\n    if (data && selectedUsers.length >= 0 && !isAllUsers()) {\n      setSelectedUsers(data.map((user) => user.id));\n    } else {\n      setSelectedUsers([]);\n    }\n  };\n\n  return (\n    <Modal\n      loading={!data && !error}\n      title={intl.formatMessage(messages.importfromplex)}\n      onOk={() => {\n        importUsers();\n      }}\n      okDisabled={isImporting || !selectedUsers.length}\n      okText={intl.formatMessage(\n        isImporting ? globalMessages.importing : globalMessages.import\n      )}\n      onCancel={onCancel}\n    >\n      {data?.length ? (\n        <>\n          {settings.currentSettings.newPlexLogin && (\n            <Alert\n              title={intl.formatMessage(messages.newplexsigninenabled, {\n                strong: (msg: React.ReactNode) => (\n                  <strong className=\"font-semibold text-white\">{msg}</strong>\n                ),\n              })}\n              type=\"info\"\n            />\n          )}\n          <div className=\"flex flex-col\">\n            <div className=\"-mx-4 sm:mx-0\">\n              <div className=\"inline-block min-w-full py-2 align-middle\">\n                <div className=\"overflow-hidden shadow sm:rounded-lg\">\n                  <table className=\"min-w-full\">\n                    <thead>\n                      <tr>\n                        <th className=\"w-16 bg-gray-500 px-4 py-3\">\n                          <span\n                            role=\"checkbox\"\n                            tabIndex={0}\n                            aria-checked={isAllUsers()}\n                            onClick={() => toggleAllUsers()}\n                            onKeyDown={(e) => {\n                              if (e.key === 'Enter' || e.key === 'Space') {\n                                toggleAllUsers();\n                              }\n                            }}\n                            className=\"relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center pt-2 focus:outline-none\"\n                          >\n                            <span\n                              aria-hidden=\"true\"\n                              className={`${\n                                isAllUsers() ? 'bg-indigo-500' : 'bg-gray-800'\n                              } absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}\n                            />\n                            <span\n                              aria-hidden=\"true\"\n                              className={`${\n                                isAllUsers() ? 'translate-x-5' : 'translate-x-0'\n                              } absolute left-0 inline-block h-5 w-5 rounded-full border border-gray-200 bg-white shadow transition-transform duration-200 ease-in-out group-focus:border-blue-300 group-focus:ring`}\n                            />\n                          </span>\n                        </th>\n                        <th className=\"bg-gray-500 px-1 py-3 text-left text-xs font-medium uppercase leading-4 tracking-wider text-gray-200 md:px-6\">\n                          {intl.formatMessage(messages.user)}\n                        </th>\n                      </tr>\n                    </thead>\n                    <tbody className=\"divide-y divide-gray-700 bg-gray-600\">\n                      {data?.map((user) => (\n                        <tr key={`user-${user.id}`}>\n                          <td className=\"whitespace-nowrap px-4 py-4 text-sm font-medium leading-5 text-gray-100\">\n                            <span\n                              role=\"checkbox\"\n                              tabIndex={0}\n                              aria-checked={isSelectedUser(user.id)}\n                              onClick={() => toggleUser(user.id)}\n                              onKeyDown={(e) => {\n                                if (e.key === 'Enter' || e.key === 'Space') {\n                                  toggleUser(user.id);\n                                }\n                              }}\n                              className=\"relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center pt-2 focus:outline-none\"\n                            >\n                              <span\n                                aria-hidden=\"true\"\n                                className={`${\n                                  isSelectedUser(user.id)\n                                    ? 'bg-indigo-500'\n                                    : 'bg-gray-800'\n                                } absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out`}\n                              />\n                              <span\n                                aria-hidden=\"true\"\n                                className={`${\n                                  isSelectedUser(user.id)\n                                    ? 'translate-x-5'\n                                    : 'translate-x-0'\n                                } absolute left-0 inline-block h-5 w-5 rounded-full border border-gray-200 bg-white shadow transition-transform duration-200 ease-in-out group-focus:border-blue-300 group-focus:ring`}\n                              />\n                            </span>\n                          </td>\n                          <td className=\"whitespace-nowrap px-1 py-4 text-sm font-medium leading-5 text-gray-100 md:px-6\">\n                            <div className=\"flex items-center\">\n                              <Image\n                                className=\"h-10 w-10 flex-shrink-0 rounded-full\"\n                                src={user.thumb}\n                                alt=\"\"\n                                width={40}\n                                height={40}\n                              />\n                              <div className=\"ml-4\">\n                                <div className=\"text-base font-bold leading-5\">\n                                  {user.username}\n                                </div>\n                                {user.username &&\n                                  user.username.toLowerCase() !==\n                                    user.email && (\n                                    <div className=\"text-sm leading-5 text-gray-300\">\n                                      {user.email}\n                                    </div>\n                                  )}\n                              </div>\n                            </div>\n                          </td>\n                        </tr>\n                      ))}\n                    </tbody>\n                  </table>\n                </div>\n              </div>\n            </div>\n          </div>\n        </>\n      ) : (\n        <Alert\n          title={intl.formatMessage(messages.nouserstoimport)}\n          type=\"info\"\n        />\n      )}\n    </Modal>\n  );\n};\n\nexport default PlexImportModal;\n"
  },
  {
    "path": "src/components/UserList/index.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport Header from '@app/components/Common/Header';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport Modal from '@app/components/Common/Modal';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport Table from '@app/components/Common/Table';\nimport BulkEditModal from '@app/components/UserList/BulkEditModal';\nimport PlexImportModal from '@app/components/UserList/PlexImportModal';\nimport useSettings from '@app/hooks/useSettings';\nimport { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';\nimport type { User } from '@app/hooks/useUser';\nimport { Permission, UserType, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport {\n  BarsArrowDownIcon,\n  ChevronLeftIcon,\n  ChevronRightIcon,\n  InboxArrowDownIcon,\n  PencilIcon,\n  UserPlusIcon,\n} from '@heroicons/react/24/solid';\nimport { MediaServerType } from '@server/constants/server';\nimport type { UserResultsResponse } from '@server/interfaces/api/userInterfaces';\nimport { hasPermission } from '@server/lib/permissions';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport validator from 'validator';\nimport * as Yup from 'yup';\nimport JellyfinImportModal from './JellyfinImportModal';\n\nconst messages = defineMessages('components.UserList', {\n  users: 'Users',\n  userlist: 'User List',\n  importfrommediaserver: 'Import {mediaServerName} Users',\n  user: 'User',\n  totalrequests: 'Requests',\n  accounttype: 'Type',\n  role: 'Role',\n  created: 'Joined',\n  bulkedit: 'Bulk Edit',\n  owner: 'Owner',\n  admin: 'Admin',\n  plexuser: 'Plex User',\n  deleteuser: 'Delete User',\n  userdeleted: 'User deleted successfully!',\n  userdeleteerror: 'Something went wrong while deleting the user.',\n  deleteconfirm:\n    'Are you sure you want to delete this user? All of their request data will be permanently removed.',\n  localuser: 'Local User',\n  mediaServerUser: '{mediaServerName} User',\n  createlocaluser: 'Create Local User',\n  creating: 'Creating…',\n  create: 'Create',\n  validationpasswordminchars:\n    'Password is too short; should be a minimum of 8 characters',\n  usercreatedfailed: 'Something went wrong while creating the user.',\n  usercreatedfailedexisting:\n    'The provided email address is already in use by another user.',\n  usercreatedsuccess: 'User created successfully!',\n  username: 'Username',\n  email: 'Email Address',\n  password: 'Password',\n  passwordinfodescription:\n    'Configure an application URL and enable email notifications to allow automatic password generation.',\n  autogeneratepassword: 'Automatically Generate Password',\n  autogeneratepasswordTip: 'Email a server-generated password to the user',\n  validationUsername: 'You must provide an username',\n  validationEmail: 'Email required',\n  sortCreated: 'Join Date',\n  sortDisplayName: 'Display Name',\n  sortRequests: 'Request Count',\n  localLoginDisabled:\n    'The <strong>Enable Local Sign-In</strong> setting is currently disabled.',\n});\n\ntype Sort = 'created' | 'updated' | 'requests' | 'displayname';\n\nconst UserList = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const settings = useSettings();\n  const { addToast } = useToasts();\n  const { user: currentUser, hasPermission: currentHasPermission } = useUser();\n  const [currentSort, setCurrentSort] = useState<Sort>('displayname');\n  const [currentPageSize, setCurrentPageSize] = useState<number>(10);\n\n  const page = router.query.page ? Number(router.query.page) : 1;\n  const pageIndex = page - 1;\n  const updateQueryParams = useUpdateQueryParams({ page: page.toString() });\n\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<UserResultsResponse>(\n    `/api/v1/user?take=${currentPageSize}&skip=${\n      pageIndex * currentPageSize\n    }&sort=${currentSort}`\n  );\n\n  const [isDeleting, setDeleting] = useState(false);\n  const [showImportModal, setShowImportModal] = useState(false);\n  const [deleteModal, setDeleteModal] = useState<{\n    isOpen: boolean;\n    user?: User;\n  }>({\n    isOpen: false,\n  });\n  const [createModal, setCreateModal] = useState<{\n    isOpen: boolean;\n  }>({\n    isOpen: false,\n  });\n  const [showBulkEditModal, setShowBulkEditModal] = useState(false);\n  const [selectedUsers, setSelectedUsers] = useState<number[]>([]);\n\n  useEffect(() => {\n    const filterString = window.localStorage.getItem('ul-filter-settings');\n\n    if (filterString) {\n      const filterSettings = JSON.parse(filterString);\n\n      setCurrentSort(filterSettings.currentSort);\n      setCurrentPageSize(filterSettings.currentPageSize);\n    }\n  }, []);\n\n  useEffect(() => {\n    window.localStorage.setItem(\n      'ul-filter-settings',\n      JSON.stringify({\n        currentSort,\n        currentPageSize,\n      })\n    );\n  }, [currentSort, currentPageSize]);\n\n  const isUserPermsEditable = (userId: number) =>\n    userId !== 1 && userId !== currentUser?.id;\n  const isAllUsersSelected = () => {\n    return (\n      selectedUsers.length ===\n      data?.results.filter((user) => user.id !== currentUser?.id).length\n    );\n  };\n  const isUserSelected = (userId: number) => selectedUsers.includes(userId);\n  const toggleAllUsers = () => {\n    if (\n      data &&\n      selectedUsers.length >= 0 &&\n      selectedUsers.length < data?.results.length - 1\n    ) {\n      setSelectedUsers(\n        data.results\n          .filter((user) => isUserPermsEditable(user.id))\n          .map((u) => u.id)\n      );\n    } else {\n      setSelectedUsers([]);\n    }\n  };\n  const toggleUser = (userId: number) => {\n    if (selectedUsers.includes(userId)) {\n      setSelectedUsers((users) => users.filter((u) => u !== userId));\n    } else {\n      setSelectedUsers((users) => [...users, userId]);\n    }\n  };\n\n  const deleteUser = async () => {\n    setDeleting(true);\n\n    try {\n      await axios.delete(`/api/v1/user/${deleteModal.user?.id}`);\n\n      addToast(intl.formatMessage(messages.userdeleted), {\n        autoDismiss: true,\n        appearance: 'success',\n      });\n      setDeleteModal({ isOpen: false, user: deleteModal.user });\n    } catch {\n      addToast(intl.formatMessage(messages.userdeleteerror), {\n        autoDismiss: true,\n        appearance: 'error',\n      });\n    } finally {\n      setDeleting(false);\n      revalidate();\n    }\n  };\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  const CreateUserSchema = Yup.object().shape({\n    username: Yup.string().required(\n      intl.formatMessage(messages.validationUsername)\n    ),\n    email: Yup.string()\n      .required()\n      .test(\n        'email',\n        intl.formatMessage(messages.validationEmail),\n        (value) => !value || validator.isEmail(value, { require_tld: false })\n      ),\n    password: Yup.lazy((value) =>\n      !value\n        ? Yup.string()\n        : Yup.string().min(\n            8,\n            intl.formatMessage(messages.validationpasswordminchars)\n          )\n    ),\n  });\n\n  if (!data) {\n    return <LoadingSpinner />;\n  }\n\n  const hasNextPage = data.pageInfo.pages > pageIndex + 1;\n  const hasPrevPage = pageIndex > 0;\n\n  const passwordGenerationEnabled =\n    settings.currentSettings.applicationUrl &&\n    settings.currentSettings.emailEnabled;\n\n  return (\n    <>\n      <PageTitle title={intl.formatMessage(messages.users)} />\n      <Transition\n        as=\"div\"\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={deleteModal.isOpen}\n      >\n        <Modal\n          onOk={() => deleteUser()}\n          okText={\n            isDeleting\n              ? intl.formatMessage(globalMessages.deleting)\n              : intl.formatMessage(globalMessages.delete)\n          }\n          okDisabled={isDeleting}\n          okButtonType=\"danger\"\n          onCancel={() =>\n            setDeleteModal({ isOpen: false, user: deleteModal.user })\n          }\n          title={intl.formatMessage(messages.deleteuser)}\n          subTitle={deleteModal.user?.username}\n        >\n          {intl.formatMessage(messages.deleteconfirm)}\n        </Modal>\n      </Transition>\n\n      <Transition\n        as=\"div\"\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={createModal.isOpen}\n      >\n        <Formik\n          initialValues={{\n            username: '',\n            email: '',\n            password: '',\n            genpassword: false,\n          }}\n          validationSchema={CreateUserSchema}\n          onSubmit={async (values) => {\n            try {\n              await axios.post('/api/v1/user', {\n                username: values.username,\n                email: values.email,\n                password: values.genpassword ? null : values.password,\n              });\n              addToast(intl.formatMessage(messages.usercreatedsuccess), {\n                appearance: 'success',\n                autoDismiss: true,\n              });\n              setCreateModal({ isOpen: false });\n            } catch (e) {\n              addToast(\n                intl.formatMessage(\n                  e?.response?.data?.errors?.includes('USER_EXISTS')\n                    ? messages.usercreatedfailedexisting\n                    : messages.usercreatedfailed\n                ),\n                {\n                  appearance: 'error',\n                  autoDismiss: true,\n                }\n              );\n            } finally {\n              revalidate();\n            }\n          }}\n        >\n          {({\n            errors,\n            touched,\n            isSubmitting,\n            values,\n            isValid,\n            setFieldValue,\n            handleSubmit,\n          }) => {\n            return (\n              <Modal\n                title={intl.formatMessage(messages.createlocaluser)}\n                onOk={() => handleSubmit()}\n                okText={\n                  isSubmitting\n                    ? intl.formatMessage(messages.creating)\n                    : intl.formatMessage(messages.create)\n                }\n                okDisabled={isSubmitting || !isValid}\n                okButtonType=\"primary\"\n                onCancel={() => setCreateModal({ isOpen: false })}\n              >\n                {!settings.currentSettings.localLogin && (\n                  <Alert\n                    title={intl.formatMessage(messages.localLoginDisabled, {\n                      strong: (msg: React.ReactNode) => (\n                        <strong className=\"font-semibold text-white\">\n                          {msg}\n                        </strong>\n                      ),\n                    })}\n                    type=\"warning\"\n                  />\n                )}\n                {currentHasPermission(Permission.ADMIN) &&\n                  !passwordGenerationEnabled && (\n                    <Alert\n                      title={intl.formatMessage(\n                        messages.passwordinfodescription\n                      )}\n                      type=\"info\"\n                    />\n                  )}\n                <Form className=\"section\">\n                  <div className=\"form-row\">\n                    <label htmlFor=\"username\" className=\"text-label\">\n                      {intl.formatMessage(messages.username)}\n                      <span className=\"label-required\">*</span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <Field id=\"username\" name=\"username\" type=\"text\" />\n                      </div>\n                      {errors.username &&\n                        touched.username &&\n                        typeof errors.username === 'string' && (\n                          <div className=\"error\">{errors.username}</div>\n                        )}\n                    </div>\n                  </div>\n                  <div className=\"form-row\">\n                    <label htmlFor=\"email\" className=\"text-label\">\n                      {intl.formatMessage(messages.email)}\n                      <span className=\"label-required\">*</span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <Field\n                          id=\"email\"\n                          name=\"email\"\n                          type=\"text\"\n                          inputMode=\"email\"\n                          autoComplete=\"off\"\n                          data-form-type=\"other\"\n                          data-1pignore=\"true\"\n                          data-lpignore=\"true\"\n                          data-bwignore=\"true\"\n                        />\n                      </div>\n                      {errors.email &&\n                        touched.email &&\n                        typeof errors.email === 'string' && (\n                          <div className=\"error\">{errors.email}</div>\n                        )}\n                    </div>\n                  </div>\n                  <div\n                    className={`form-row ${\n                      passwordGenerationEnabled ? '' : 'opacity-50'\n                    }`}\n                  >\n                    <label htmlFor=\"genpassword\" className=\"checkbox-label\">\n                      {intl.formatMessage(messages.autogeneratepassword)}\n                      <span className=\"label-tip\">\n                        {intl.formatMessage(messages.autogeneratepasswordTip)}\n                      </span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <Field\n                        type=\"checkbox\"\n                        id=\"genpassword\"\n                        name=\"genpassword\"\n                        disabled={!passwordGenerationEnabled}\n                        onClick={() => setFieldValue('password', '')}\n                      />\n                    </div>\n                  </div>\n                  <div\n                    className={`form-row ${\n                      values.genpassword ? 'opacity-50' : ''\n                    }`}\n                  >\n                    <label htmlFor=\"password\" className=\"text-label\">\n                      {intl.formatMessage(messages.password)}\n                      {!values.genpassword && (\n                        <span className=\"label-required\">*</span>\n                      )}\n                    </label>\n                    <div className=\"form-input-area\">\n                      <div className=\"form-input-field\">\n                        <SensitiveInput\n                          as=\"field\"\n                          id=\"password\"\n                          name=\"password\"\n                          type=\"password\"\n                          autoComplete=\"new-password\"\n                          disabled={values.genpassword}\n                        />\n                      </div>\n                      {errors.password &&\n                        touched.password &&\n                        typeof errors.password === 'string' && (\n                          <div className=\"error\">{errors.password}</div>\n                        )}\n                    </div>\n                  </div>\n                </Form>\n              </Modal>\n            );\n          }}\n        </Formik>\n      </Transition>\n\n      <Transition\n        as=\"div\"\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={showBulkEditModal}\n      >\n        <BulkEditModal\n          onCancel={() => setShowBulkEditModal(false)}\n          onComplete={() => {\n            setShowBulkEditModal(false);\n            revalidate();\n          }}\n          selectedUserIds={selectedUsers}\n          users={data.results}\n        />\n      </Transition>\n\n      <Transition\n        as=\"div\"\n        enter=\"transition-opacity duration-300\"\n        enterFrom=\"opacity-0\"\n        enterTo=\"opacity-100\"\n        leave=\"transition-opacity duration-300\"\n        leaveFrom=\"opacity-100\"\n        leaveTo=\"opacity-0\"\n        show={showImportModal}\n      >\n        {settings.currentSettings.mediaServerType === MediaServerType.PLEX ? (\n          <PlexImportModal\n            onCancel={() => setShowImportModal(false)}\n            onComplete={() => {\n              setShowImportModal(false);\n              revalidate();\n            }}\n          />\n        ) : (\n          <JellyfinImportModal\n            onCancel={() => setShowImportModal(false)}\n            onComplete={() => {\n              setShowImportModal(false);\n              revalidate();\n            }}\n          >\n            {data.pageInfo.results}\n          </JellyfinImportModal>\n        )}\n      </Transition>\n\n      <div className=\"flex flex-col justify-between lg:flex-row lg:items-end\">\n        <Header>{intl.formatMessage(messages.userlist)}</Header>\n        <div className=\"mt-2 flex flex-grow flex-col lg:flex-grow-0 lg:flex-row\">\n          <div className=\"mb-2 flex flex-grow flex-col justify-between sm:flex-row lg:mb-0 lg:flex-grow-0\">\n            <Button\n              className=\"mb-2 flex-grow sm:mb-0 sm:mr-2\"\n              buttonType=\"primary\"\n              onClick={() => setCreateModal({ isOpen: true })}\n            >\n              <UserPlusIcon />\n              <span>{intl.formatMessage(messages.createlocaluser)}</span>\n            </Button>\n            <Button\n              className=\"flex-grow lg:mr-2\"\n              buttonType=\"primary\"\n              onClick={() => setShowImportModal(true)}\n            >\n              <InboxArrowDownIcon />\n              <span>\n                {settings.currentSettings.mediaServerType ===\n                MediaServerType.EMBY\n                  ? intl.formatMessage(messages.importfrommediaserver, {\n                      mediaServerName: 'Emby',\n                    })\n                  : settings.currentSettings.mediaServerType ===\n                      MediaServerType.PLEX\n                    ? intl.formatMessage(messages.importfrommediaserver, {\n                        mediaServerName: 'Plex',\n                      })\n                    : intl.formatMessage(messages.importfrommediaserver, {\n                        mediaServerName: 'Jellyfin',\n                      })}\n              </span>\n            </Button>\n          </div>\n          <div className=\"mb-2 flex flex-grow lg:mb-0 lg:flex-grow-0\">\n            <span className=\"inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-800 px-3 text-sm text-gray-100\">\n              <BarsArrowDownIcon className=\"h-6 w-6\" />\n            </span>\n            <select\n              id=\"sort\"\n              name=\"sort\"\n              onChange={(e) => {\n                setCurrentSort(e.target.value as Sort);\n                router.push(router.pathname);\n              }}\n              value={currentSort}\n              className=\"rounded-r-only\"\n            >\n              <option value=\"created\">\n                {intl.formatMessage(messages.sortCreated)}\n              </option>\n              <option value=\"requests\">\n                {intl.formatMessage(messages.sortRequests)}\n              </option>\n              <option value=\"displayname\">\n                {intl.formatMessage(messages.sortDisplayName)}\n              </option>\n            </select>\n          </div>\n        </div>\n      </div>\n      <Table>\n        <thead>\n          <tr>\n            <Table.TH>\n              {(data.results ?? []).length > 1 && (\n                <input\n                  type=\"checkbox\"\n                  id=\"selectAll\"\n                  name=\"selectAll\"\n                  checked={isAllUsersSelected()}\n                  onChange={() => {\n                    toggleAllUsers();\n                  }}\n                />\n              )}\n            </Table.TH>\n            <Table.TH>{intl.formatMessage(messages.user)}</Table.TH>\n            <Table.TH>{intl.formatMessage(messages.totalrequests)}</Table.TH>\n            <Table.TH>{intl.formatMessage(messages.accounttype)}</Table.TH>\n            <Table.TH>{intl.formatMessage(messages.role)}</Table.TH>\n            <Table.TH>{intl.formatMessage(messages.created)}</Table.TH>\n            <Table.TH className=\"text-right\">\n              {(data.results ?? []).length > 1 && (\n                <Button\n                  buttonType=\"warning\"\n                  onClick={() => setShowBulkEditModal(true)}\n                  disabled={selectedUsers.length === 0}\n                >\n                  <PencilIcon />\n                  <span>{intl.formatMessage(messages.bulkedit)}</span>\n                </Button>\n              )}\n            </Table.TH>\n          </tr>\n        </thead>\n        <Table.TBody>\n          {data?.results.map((user) => (\n            <tr key={`user-list-${user.id}`} data-testid=\"user-list-row\">\n              <Table.TD>\n                {isUserPermsEditable(user.id) && (\n                  <input\n                    type=\"checkbox\"\n                    id={`user-list-select-${user.id}`}\n                    name={`user-list-select-${user.id}`}\n                    checked={isUserSelected(user.id)}\n                    onChange={() => {\n                      toggleUser(user.id);\n                    }}\n                  />\n                )}\n              </Table.TD>\n              <Table.TD>\n                <div className=\"flex items-center\">\n                  <Link\n                    href={`/users/${user.id}`}\n                    className=\"h-10 w-10 flex-shrink-0\"\n                  >\n                    <CachedImage\n                      type=\"avatar\"\n                      className=\"h-10 w-10 rounded-full object-cover\"\n                      src={user.avatar}\n                      alt=\"\"\n                      width={40}\n                      height={40}\n                    />\n                  </Link>\n                  <div className=\"ml-4\">\n                    <Link\n                      href={`/users/${user.id}`}\n                      className=\"text-base font-bold leading-5 transition duration-300 hover:underline\"\n                      data-testid=\"user-list-username-link\"\n                    >\n                      {user.username ||\n                        user.jellyfinUsername ||\n                        user.plexUsername ||\n                        user.email}\n                    </Link>\n                    {(\n                      user.username ||\n                      user.jellyfinUsername ||\n                      user.plexUsername\n                    )?.toLowerCase() !== user.email && (\n                      <div className=\"text-sm leading-5 text-gray-300\">\n                        {user.email}\n                      </div>\n                    )}\n                  </div>\n                </div>\n              </Table.TD>\n              <Table.TD>\n                {user.id === currentUser?.id ||\n                currentHasPermission(\n                  [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n                  { type: 'or' }\n                ) ? (\n                  <Link\n                    href={`/users/${user.id}/requests`}\n                    className=\"text-sm leading-5 transition duration-300 hover:underline\"\n                  >\n                    {user.requestCount}\n                  </Link>\n                ) : (\n                  user.requestCount\n                )}\n              </Table.TD>\n              <Table.TD>\n                {user.userType === UserType.PLEX ? (\n                  <Badge badgeType=\"warning\">\n                    {intl.formatMessage(messages.plexuser)}\n                  </Badge>\n                ) : user.userType === UserType.LOCAL ? (\n                  <Badge badgeType=\"default\">\n                    {intl.formatMessage(messages.localuser)}\n                  </Badge>\n                ) : user.userType === UserType.EMBY ? (\n                  <Badge badgeType=\"success\">\n                    {intl.formatMessage(messages.mediaServerUser, {\n                      mediaServerName: 'Emby',\n                    })}\n                  </Badge>\n                ) : user.userType === UserType.JELLYFIN ? (\n                  <Badge badgeType=\"default\">\n                    {intl.formatMessage(messages.mediaServerUser, {\n                      mediaServerName: 'Jellyfin',\n                    })}\n                  </Badge>\n                ) : null}\n              </Table.TD>\n              <Table.TD>\n                {user.id === 1\n                  ? intl.formatMessage(messages.owner)\n                  : hasPermission(Permission.ADMIN, user.permissions)\n                    ? intl.formatMessage(messages.admin)\n                    : intl.formatMessage(messages.user)}\n              </Table.TD>\n              <Table.TD>\n                {intl.formatDate(user.createdAt, {\n                  year: 'numeric',\n                  month: 'long',\n                  day: 'numeric',\n                })}\n              </Table.TD>\n              <Table.TD alignText=\"right\">\n                <Button\n                  buttonType=\"warning\"\n                  disabled={user.id === 1 && currentUser?.id !== 1}\n                  className=\"mr-2\"\n                  onClick={() =>\n                    router.push(\n                      '/users/[userId]/settings',\n                      `/users/${user.id}/settings`\n                    )\n                  }\n                >\n                  {intl.formatMessage(globalMessages.edit)}\n                </Button>\n                <Button\n                  buttonType=\"danger\"\n                  disabled={\n                    user.id === 1 ||\n                    (currentUser?.id !== 1 &&\n                      hasPermission(Permission.ADMIN, user.permissions))\n                  }\n                  onClick={() => setDeleteModal({ isOpen: true, user })}\n                >\n                  {intl.formatMessage(globalMessages.delete)}\n                </Button>\n              </Table.TD>\n            </tr>\n          ))}\n          <tr className=\"bg-gray-700\">\n            <Table.TD colSpan={8} noPadding>\n              <nav\n                className=\"flex w-screen flex-col items-center space-x-4 space-y-3 px-6 py-3 sm:flex-row sm:space-y-0 lg:w-full\"\n                aria-label=\"Pagination\"\n              >\n                <div className=\"hidden lg:flex lg:flex-1\">\n                  <p className=\"text-sm\">\n                    {data.results.length > 0 &&\n                      intl.formatMessage(globalMessages.showingresults, {\n                        from: pageIndex * currentPageSize + 1,\n                        to:\n                          data.results.length < currentPageSize\n                            ? pageIndex * currentPageSize + data.results.length\n                            : (pageIndex + 1) * currentPageSize,\n                        total: data.pageInfo.results,\n                        strong: (msg: React.ReactNode) => (\n                          <span className=\"font-medium\">{msg}</span>\n                        ),\n                      })}\n                  </p>\n                </div>\n                <div className=\"flex justify-center sm:flex-1 sm:justify-start lg:justify-center\">\n                  <span className=\"-mt-3 items-center text-sm sm:-ml-4 sm:mt-0 lg:ml-0\">\n                    {intl.formatMessage(globalMessages.resultsperpage, {\n                      pageSize: (\n                        <select\n                          id=\"pageSize\"\n                          name=\"pageSize\"\n                          onChange={(e) => {\n                            setCurrentPageSize(Number(e.target.value));\n                            router\n                              .push(router.pathname)\n                              .then(() => window.scrollTo(0, 0));\n                          }}\n                          value={currentPageSize}\n                          className=\"short inline\"\n                        >\n                          <option value=\"5\">5</option>\n                          <option value=\"10\">10</option>\n                          <option value=\"25\">25</option>\n                          <option value=\"50\">50</option>\n                          <option value=\"100\">100</option>\n                        </select>\n                      ),\n                    })}\n                  </span>\n                </div>\n                <div className=\"flex flex-auto justify-center space-x-2 sm:flex-1 sm:justify-end\">\n                  <Button\n                    disabled={!hasPrevPage}\n                    onClick={() =>\n                      updateQueryParams('page', (page - 1).toString())\n                    }\n                  >\n                    <ChevronLeftIcon />\n                    <span>{intl.formatMessage(globalMessages.previous)}</span>\n                  </Button>\n                  <Button\n                    disabled={!hasNextPage}\n                    onClick={() =>\n                      updateQueryParams('page', (page + 1).toString())\n                    }\n                  >\n                    <span>{intl.formatMessage(globalMessages.next)}</span>\n                    <ChevronRightIcon />\n                  </Button>\n                </div>\n              </nav>\n            </Table.TD>\n          </tr>\n        </Table.TBody>\n      </Table>\n    </>\n  );\n};\n\nexport default UserList;\n"
  },
  {
    "path": "src/components/UserProfile/ProfileHeader/index.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport CachedImage from '@app/components/Common/CachedImage';\nimport type { User } from '@app/hooks/useUser';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { CogIcon, UserIcon } from '@heroicons/react/24/solid';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('components.UserProfile.ProfileHeader', {\n  settings: 'Edit Settings',\n  profile: 'View Profile',\n  joindate: 'Joined {joindate}',\n  userid: 'User ID: {userid}',\n});\n\ninterface ProfileHeaderProps {\n  user: User;\n  isSettingsPage?: boolean;\n}\n\nconst ProfileHeader = ({ user, isSettingsPage }: ProfileHeaderProps) => {\n  const intl = useIntl();\n  const { user: loggedInUser, hasPermission } = useUser();\n\n  const subtextItems: React.ReactNode[] = [\n    intl.formatMessage(messages.joindate, {\n      joindate: intl.formatDate(user.createdAt, {\n        year: 'numeric',\n        month: 'long',\n        day: 'numeric',\n      }),\n    }),\n  ];\n\n  if (hasPermission(Permission.MANAGE_REQUESTS)) {\n    subtextItems.push(intl.formatMessage(messages.userid, { userid: user.id }));\n  }\n\n  return (\n    <div className=\"relative z-40 mb-12 mt-6 lg:flex lg:items-end lg:justify-between lg:space-x-5\">\n      <div className=\"flex items-end justify-items-end space-x-5\">\n        <div className=\"flex-shrink-0\">\n          <div className=\"relative\">\n            <CachedImage\n              type=\"avatar\"\n              className=\"h-24 w-24 rounded-full bg-gray-600 object-cover ring-1 ring-gray-700\"\n              src={user.avatar}\n              alt=\"\"\n              width={96}\n              height={96}\n            />\n            <span\n              className=\"absolute inset-0 rounded-full shadow-inner\"\n              aria-hidden=\"true\"\n            />\n          </div>\n        </div>\n        <div className=\"pt-1.5\">\n          <h1 className=\"mb-1 flex flex-col sm:flex-row sm:items-center\">\n            <Link\n              href={\n                user.id === loggedInUser?.id ? '/profile' : `/users/${user.id}`\n              }\n              className=\"text-overseerr text-lg font-bold hover:to-purple-200 sm:text-2xl\"\n            >\n              {user.displayName}\n            </Link>\n            {user.email && user.displayName.toLowerCase() !== user.email && (\n              <span className=\"text-sm text-gray-400 sm:ml-2 sm:text-lg\">\n                ({user.email})\n              </span>\n            )}\n          </h1>\n          <p className=\"text-sm font-medium text-gray-400\">\n            {subtextItems.reduce((prev, curr) => (\n              <>\n                {prev} | {curr}\n              </>\n            ))}\n          </p>\n        </div>\n      </div>\n      <div className=\"mt-6 flex flex-col-reverse justify-stretch space-y-4 space-y-reverse lg:flex-row lg:justify-end lg:space-x-3 lg:space-y-0 lg:space-x-reverse\">\n        {(loggedInUser?.id === user.id ||\n          (user.id !== 1 && hasPermission(Permission.MANAGE_USERS))) &&\n        !isSettingsPage ? (\n          <Link\n            href={\n              loggedInUser?.id === user.id\n                ? `/profile/settings`\n                : `/users/${user.id}/settings`\n            }\n            passHref\n            legacyBehavior\n          >\n            <Button as=\"a\">\n              <CogIcon />\n              <span>{intl.formatMessage(messages.settings)}</span>\n            </Button>\n          </Link>\n        ) : (\n          isSettingsPage && (\n            <Link\n              href={\n                loggedInUser?.id === user.id ? `/profile` : `/users/${user.id}`\n              }\n              passHref\n              legacyBehavior\n            >\n              <Button as=\"a\">\n                <UserIcon />\n                <span>{intl.formatMessage(messages.profile)}</span>\n              </Button>\n            </Link>\n          )\n        )}\n      </div>\n    </div>\n  );\n};\n\nexport default ProfileHeader;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx",
    "content": "import Badge from '@app/components/Common/Badge';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport LanguageSelector from '@app/components/LanguageSelector';\nimport QuotaSelector from '@app/components/QuotaSelector';\nimport RegionSelector from '@app/components/RegionSelector';\nimport { availableLanguages } from '@app/context/LanguageContext';\nimport useLocale from '@app/hooks/useLocale';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, UserType, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport { ApiErrorCode } from '@server/constants/error';\nimport type { UserSettingsGeneralResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport type { AvailableLocale } from '@server/types/languages';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useRouter } from 'next/router';\nimport { useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport validator from 'validator';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserGeneralSettings',\n  {\n    general: 'General',\n    generalsettings: 'General Settings',\n    displayName: 'Display Name',\n    email: 'Email',\n    save: 'Save Changes',\n    saving: 'Saving…',\n    mediaServerUser: '{mediaServerName} User',\n    accounttype: 'Account Type',\n    plexuser: 'Plex User',\n    localuser: 'Local User',\n    role: 'Role',\n    owner: 'Owner',\n    admin: 'Admin',\n    user: 'User',\n    toastSettingsSuccess: 'Settings saved successfully!',\n    toastSettingsFailure: 'Something went wrong while saving settings.',\n    toastSettingsFailureEmail: 'This email is already taken!',\n    toastSettingsFailureEmailEmpty:\n      'Another user already has this username. You must set an email',\n    region: 'Discover Region',\n    regionTip: 'Filter content by regional availability',\n    discoverRegion: 'Discover Region',\n    discoverRegionTip: 'Filter content by regional availability',\n    originallanguage: 'Discover Language',\n    originallanguageTip: 'Filter content by original language',\n    streamingRegion: 'Streaming Region',\n    streamingRegionTip: 'Show streaming sites by regional availability',\n    movierequestlimit: 'Movie Request Limit',\n    seriesrequestlimit: 'Series Request Limit',\n    enableOverride: 'Override Global Limit',\n    applanguage: 'Display Language',\n    languageDefault: 'Default ({language})',\n    discordId: 'Discord User ID',\n    discordIdTip:\n      'The <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> associated with your Discord user account',\n    validationemailrequired: 'Email required',\n    validationemailformat: 'Valid email required',\n    validationDiscordId: 'You must provide a valid Discord user ID',\n    plexwatchlistsyncmovies: 'Auto-Request Movies',\n    plexwatchlistsyncmoviestip:\n      'Automatically request movies on your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>',\n    plexwatchlistsyncseries: 'Auto-Request Series',\n    plexwatchlistsyncseriestip:\n      'Automatically request series on your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>',\n  }\n);\n\nconst UserGeneralSettings = () => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const { locale, setLocale } = useLocale();\n  const [movieQuotaEnabled, setMovieQuotaEnabled] = useState(false);\n  const [tvQuotaEnabled, setTvQuotaEnabled] = useState(false);\n  const router = useRouter();\n  const {\n    user,\n    hasPermission,\n    revalidate: revalidateUser,\n  } = useUser({\n    id: Number(router.query.userId),\n  });\n  const { user: currentUser, hasPermission: currentHasPermission } = useUser();\n  const { currentSettings } = useSettings();\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<UserSettingsGeneralResponse>(\n    user ? `/api/v1/user/${user?.id}/settings/main` : null\n  );\n\n  const UserGeneralSettingsSchema = Yup.object().shape({\n    email:\n      // email is required for everybody except non-admin jellyfin users\n      user?.id === 1 ||\n      (user?.userType !== UserType.JELLYFIN && user?.userType !== UserType.EMBY)\n        ? Yup.string()\n            .test(\n              'email',\n              intl.formatMessage(messages.validationemailformat),\n              (value) =>\n                !value || validator.isEmail(value, { require_tld: false })\n            )\n            .required(intl.formatMessage(messages.validationemailrequired))\n        : Yup.string().test(\n            'email',\n            intl.formatMessage(messages.validationemailformat),\n            (value) =>\n              !value || validator.isEmail(value, { require_tld: false })\n          ),\n    discordId: Yup.string()\n      .nullable()\n      .matches(/^\\d{17,19}$/, intl.formatMessage(messages.validationDiscordId)),\n  });\n\n  useEffect(() => {\n    setMovieQuotaEnabled(\n      data?.movieQuotaLimit != undefined && data?.movieQuotaDays != undefined\n    );\n    setTvQuotaEnabled(\n      data?.tvQuotaLimit != undefined && data?.tvQuotaDays != undefined\n    );\n  }, [data]);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.general),\n          intl.formatMessage(globalMessages.usersettings),\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.generalsettings)}\n        </h3>\n      </div>\n      <Formik\n        initialValues={{\n          displayName: data?.username !== user?.email ? data?.username : '',\n          email: data?.email?.includes('@') ? data.email : '',\n          discordId: data?.discordId ?? '',\n          locale: data?.locale,\n          discoverRegion: data?.discoverRegion,\n          streamingRegion: data?.streamingRegion,\n          originalLanguage: data?.originalLanguage,\n          movieQuotaLimit: data?.movieQuotaLimit,\n          movieQuotaDays: data?.movieQuotaDays,\n          tvQuotaLimit: data?.tvQuotaLimit,\n          tvQuotaDays: data?.tvQuotaDays,\n          watchlistSyncMovies: data?.watchlistSyncMovies,\n          watchlistSyncTv: data?.watchlistSyncTv,\n        }}\n        validationSchema={UserGeneralSettingsSchema}\n        enableReinitialize\n        onSubmit={async (values) => {\n          try {\n            await axios.post(`/api/v1/user/${user?.id}/settings/main`, {\n              username: values.displayName,\n              email:\n                values.email || user?.jellyfinUsername || user?.plexUsername,\n              discordId: values.discordId,\n              locale: values.locale,\n              discoverRegion: values.discoverRegion,\n              streamingRegion: values.streamingRegion,\n              originalLanguage: values.originalLanguage,\n              movieQuotaLimit: movieQuotaEnabled\n                ? values.movieQuotaLimit\n                : null,\n              movieQuotaDays: movieQuotaEnabled ? values.movieQuotaDays : null,\n              tvQuotaLimit: tvQuotaEnabled ? values.tvQuotaLimit : null,\n              tvQuotaDays: tvQuotaEnabled ? values.tvQuotaDays : null,\n              watchlistSyncMovies: values.watchlistSyncMovies,\n              watchlistSyncTv: values.watchlistSyncTv,\n            });\n\n            if (currentUser?.id === user?.id && setLocale) {\n              setLocale(\n                (values.locale\n                  ? values.locale\n                  : currentSettings.locale) as AvailableLocale\n              );\n            }\n\n            addToast(intl.formatMessage(messages.toastSettingsSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch (e) {\n            if (e?.response?.data?.message === ApiErrorCode.InvalidEmail) {\n              if (values.email) {\n                addToast(\n                  intl.formatMessage(messages.toastSettingsFailureEmail),\n                  {\n                    autoDismiss: true,\n                    appearance: 'error',\n                  }\n                );\n              } else {\n                addToast(\n                  intl.formatMessage(messages.toastSettingsFailureEmailEmpty),\n                  {\n                    autoDismiss: true,\n                    appearance: 'error',\n                  }\n                );\n              }\n            } else {\n              addToast(intl.formatMessage(messages.toastSettingsFailure), {\n                autoDismiss: true,\n                appearance: 'error',\n              });\n            }\n          } finally {\n            revalidate();\n            revalidateUser();\n          }\n        }}\n      >\n        {({\n          errors,\n          touched,\n          isSubmitting,\n          isValid,\n          values,\n          setFieldValue,\n        }) => {\n          return (\n            <Form className=\"section\">\n              <div className=\"form-row\">\n                <label className=\"text-label\">\n                  {intl.formatMessage(messages.accounttype)}\n                </label>\n                <div className=\"mb-1 text-sm font-medium leading-5 text-gray-400 sm:mt-2\">\n                  <div className=\"flex max-w-lg items-center\">\n                    {user?.userType === UserType.PLEX ? (\n                      <Badge badgeType=\"warning\">\n                        {intl.formatMessage(messages.plexuser)}\n                      </Badge>\n                    ) : user?.userType === UserType.LOCAL ? (\n                      <Badge badgeType=\"default\">\n                        {intl.formatMessage(messages.localuser)}\n                      </Badge>\n                    ) : user?.userType === UserType.EMBY ? (\n                      <Badge badgeType=\"success\">\n                        {intl.formatMessage(messages.mediaServerUser, {\n                          mediaServerName: 'Emby',\n                        })}\n                      </Badge>\n                    ) : user?.userType === UserType.JELLYFIN ? (\n                      <Badge badgeType=\"default\">\n                        {intl.formatMessage(messages.mediaServerUser, {\n                          mediaServerName: 'Jellyfin',\n                        })}\n                      </Badge>\n                    ) : null}\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label className=\"text-label\">\n                  {intl.formatMessage(messages.role)}\n                </label>\n                <div className=\"mb-1 text-sm font-medium leading-5 text-gray-400 sm:mt-2\">\n                  <div className=\"flex max-w-lg items-center\">\n                    {user?.id === 1\n                      ? intl.formatMessage(messages.owner)\n                      : hasPermission(Permission.ADMIN)\n                        ? intl.formatMessage(messages.admin)\n                        : intl.formatMessage(messages.user)}\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"displayName\" className=\"text-label\">\n                  {intl.formatMessage(messages.displayName)}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <Field\n                      id=\"displayName\"\n                      name=\"displayName\"\n                      type=\"text\"\n                      placeholder={\n                        user?.jellyfinUsername ||\n                        user?.plexUsername ||\n                        user?.email\n                      }\n                    />\n                  </div>\n                  {errors.displayName &&\n                    touched.displayName &&\n                    typeof errors.displayName === 'string' && (\n                      <div className=\"error\">{errors.displayName}</div>\n                    )}\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"email\" className=\"text-label\">\n                  {intl.formatMessage(messages.email)}\n                  {user?.warnings.find((w) => w === 'userEmailRequired') && (\n                    <span className=\"label-required\">*</span>\n                  )}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <Field\n                      id=\"email\"\n                      name=\"email\"\n                      type=\"text\"\n                      placeholder=\"example@domain.com\"\n                      disabled={user?.plexUsername}\n                      className={\n                        user?.warnings.find((w) => w === 'userEmailRequired')\n                          ? 'border-2 border-red-400 focus:border-blue-600'\n                          : ''\n                      }\n                    />\n                  </div>\n                  {errors.email && touched.email && (\n                    <div className=\"error\">{errors.email}</div>\n                  )}\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"discordId\" className=\"text-label\">\n                  {intl.formatMessage(messages.discordId)}\n                  {currentUser?.id === user?.id && (\n                    <span className=\"label-tip\">\n                      {intl.formatMessage(messages.discordIdTip, {\n                        FindDiscordIdLink: (msg: React.ReactNode) => (\n                          <a\n                            href=\"https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-\"\n                            target=\"_blank\"\n                            rel=\"noreferrer\"\n                          >\n                            {msg}\n                          </a>\n                        ),\n                      })}\n                    </span>\n                  )}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <Field id=\"discordId\" name=\"discordId\" type=\"text\" />\n                  </div>\n                  {errors.discordId &&\n                    touched.discordId &&\n                    typeof errors.discordId === 'string' && (\n                      <div className=\"error\">{errors.discordId}</div>\n                    )}\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"locale\" className=\"text-label\">\n                  {intl.formatMessage(messages.applanguage)}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <Field as=\"select\" id=\"locale\" name=\"locale\">\n                      <option value=\"\" lang={locale}>\n                        {intl.formatMessage(messages.languageDefault, {\n                          language:\n                            availableLanguages[currentSettings.locale].display,\n                        })}\n                      </option>\n                      {(\n                        Object.keys(\n                          availableLanguages\n                        ) as (keyof typeof availableLanguages)[]\n                      ).map((key) => (\n                        <option\n                          key={key}\n                          value={availableLanguages[key].code}\n                          lang={availableLanguages[key].code}\n                        >\n                          {availableLanguages[key].display}\n                        </option>\n                      ))}\n                    </Field>\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"discoverRegion\" className=\"text-label\">\n                  <span>{intl.formatMessage(messages.discoverRegion)}</span>\n                  <span className=\"label-tip\">\n                    {intl.formatMessage(messages.discoverRegionTip)}\n                  </span>\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field relative z-[22]\">\n                    <RegionSelector\n                      name=\"discoverRegion\"\n                      value={values.discoverRegion ?? ''}\n                      isUserSetting\n                      onChange={setFieldValue}\n                    />\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"originalLanguage\" className=\"text-label\">\n                  <span>{intl.formatMessage(messages.originallanguage)}</span>\n                  <span className=\"label-tip\">\n                    {intl.formatMessage(messages.originallanguageTip)}\n                  </span>\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field relative z-[21]\">\n                    <LanguageSelector\n                      setFieldValue={setFieldValue}\n                      serverValue={currentSettings.originalLanguage}\n                      value={values.originalLanguage}\n                      isUserSettings\n                    />\n                  </div>\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"streamingRegionTip\" className=\"text-label\">\n                  <span>{intl.formatMessage(messages.streamingRegion)}</span>\n                  <span className=\"label-tip\">\n                    {intl.formatMessage(messages.streamingRegionTip)}\n                  </span>\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field relative z-20\">\n                    <RegionSelector\n                      name=\"streamingRegion\"\n                      value={values.streamingRegion || ''}\n                      isUserSetting\n                      onChange={setFieldValue}\n                      regionType=\"streaming\"\n                      disableAll\n                    />\n                  </div>\n                </div>\n              </div>\n              {currentHasPermission(Permission.MANAGE_USERS) &&\n                !hasPermission(Permission.MANAGE_USERS) && (\n                  <>\n                    <div className=\"form-row\">\n                      <label htmlFor=\"movieQuotaLimit\" className=\"text-label\">\n                        <span>\n                          {intl.formatMessage(messages.movierequestlimit)}\n                        </span>\n                      </label>\n                      <div className=\"form-input-area\">\n                        <div className=\"flex flex-col\">\n                          <div className=\"mb-4 flex items-center\">\n                            <input\n                              type=\"checkbox\"\n                              checked={movieQuotaEnabled}\n                              onChange={() => setMovieQuotaEnabled((s) => !s)}\n                            />\n                            <span className=\"ml-2 text-gray-300\">\n                              {intl.formatMessage(messages.enableOverride)}\n                            </span>\n                          </div>\n                          <QuotaSelector\n                            isDisabled={!movieQuotaEnabled}\n                            dayFieldName=\"movieQuotaDays\"\n                            limitFieldName=\"movieQuotaLimit\"\n                            mediaType=\"movie\"\n                            onChange={setFieldValue}\n                            defaultDays={values.movieQuotaDays}\n                            defaultLimit={values.movieQuotaLimit}\n                            dayOverride={\n                              !movieQuotaEnabled\n                                ? data?.globalMovieQuotaDays\n                                : undefined\n                            }\n                            limitOverride={\n                              !movieQuotaEnabled\n                                ? data?.globalMovieQuotaLimit\n                                : undefined\n                            }\n                          />\n                        </div>\n                      </div>\n                    </div>\n                    <div className=\"form-row\">\n                      <label htmlFor=\"tvQuotaLimit\" className=\"text-label\">\n                        <span>\n                          {intl.formatMessage(messages.seriesrequestlimit)}\n                        </span>\n                      </label>\n                      <div className=\"form-input-area\">\n                        <div className=\"flex flex-col\">\n                          <div className=\"mb-4 flex items-center\">\n                            <input\n                              type=\"checkbox\"\n                              checked={tvQuotaEnabled}\n                              onChange={() => setTvQuotaEnabled((s) => !s)}\n                            />\n                            <span className=\"ml-2 text-gray-300\">\n                              {intl.formatMessage(messages.enableOverride)}\n                            </span>\n                          </div>\n                          <QuotaSelector\n                            isDisabled={!tvQuotaEnabled}\n                            dayFieldName=\"tvQuotaDays\"\n                            limitFieldName=\"tvQuotaLimit\"\n                            mediaType=\"tv\"\n                            onChange={setFieldValue}\n                            defaultDays={values.tvQuotaDays}\n                            defaultLimit={values.tvQuotaLimit}\n                            dayOverride={\n                              !tvQuotaEnabled\n                                ? data?.globalTvQuotaDays\n                                : undefined\n                            }\n                            limitOverride={\n                              !tvQuotaEnabled\n                                ? data?.globalTvQuotaLimit\n                                : undefined\n                            }\n                          />\n                        </div>\n                      </div>\n                    </div>\n                  </>\n                )}\n              {hasPermission(\n                [Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_MOVIE],\n                { type: 'or' }\n              ) &&\n                user?.userType === UserType.PLEX && (\n                  <div className=\"form-row\">\n                    <label\n                      htmlFor=\"watchlistSyncMovies\"\n                      className=\"checkbox-label\"\n                    >\n                      <span>\n                        {intl.formatMessage(messages.plexwatchlistsyncmovies)}\n                      </span>\n                      <span className=\"label-tip\">\n                        {intl.formatMessage(\n                          messages.plexwatchlistsyncmoviestip,\n                          {\n                            PlexWatchlistSupportLink: (\n                              msg: React.ReactNode\n                            ) => (\n                              <a\n                                href=\"https://support.plex.tv/articles/universal-watchlist/\"\n                                className=\"text-white transition duration-300 hover:underline\"\n                                target=\"_blank\"\n                                rel=\"noreferrer\"\n                              >\n                                {msg}\n                              </a>\n                            ),\n                          }\n                        )}\n                      </span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <Field\n                        type=\"checkbox\"\n                        id=\"watchlistSyncMovies\"\n                        name=\"watchlistSyncMovies\"\n                        onChange={() => {\n                          setFieldValue(\n                            'watchlistSyncMovies',\n                            !values.watchlistSyncMovies\n                          );\n                        }}\n                      />\n                    </div>\n                  </div>\n                )}\n              {hasPermission(\n                [Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_TV],\n                { type: 'or' }\n              ) &&\n                user?.userType === UserType.PLEX && (\n                  <div className=\"form-row\">\n                    <label htmlFor=\"watchlistSyncTv\" className=\"checkbox-label\">\n                      <span>\n                        {intl.formatMessage(messages.plexwatchlistsyncseries)}\n                      </span>\n                      <span className=\"label-tip\">\n                        {intl.formatMessage(\n                          messages.plexwatchlistsyncseriestip,\n                          {\n                            PlexWatchlistSupportLink: (\n                              msg: React.ReactNode\n                            ) => (\n                              <a\n                                href=\"https://support.plex.tv/articles/universal-watchlist/\"\n                                className=\"text-white transition duration-300 hover:underline\"\n                                target=\"_blank\"\n                                rel=\"noreferrer\"\n                              >\n                                {msg}\n                              </a>\n                            ),\n                          }\n                        )}\n                      </span>\n                    </label>\n                    <div className=\"form-input-area\">\n                      <Field\n                        type=\"checkbox\"\n                        id=\"watchlistSyncTv\"\n                        name=\"watchlistSyncTv\"\n                        onChange={() => {\n                          setFieldValue(\n                            'watchlistSyncTv',\n                            !values.watchlistSyncTv\n                          );\n                        }}\n                      />\n                    </div>\n                  </div>\n                )}\n              <div className=\"actions\">\n                <div className=\"flex justify-end\">\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"primary\"\n                      type=\"submit\"\n                      disabled={isSubmitting || !isValid}\n                    >\n                      <ArrowDownOnSquareIcon />\n                      <span>\n                        {isSubmitting\n                          ? intl.formatMessage(globalMessages.saving)\n                          : intl.formatMessage(globalMessages.save)}\n                      </span>\n                    </Button>\n                  </span>\n                </div>\n              </div>\n            </Form>\n          );\n        }}\n      </Formik>\n    </>\n  );\n};\n\nexport default UserGeneralSettings;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserLinkedAccountsSettings/LinkJellyfinModal.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Modal from '@app/components/Common/Modal';\nimport useSettings from '@app/hooks/useSettings';\nimport { useUser } from '@app/hooks/useUser';\nimport defineMessages from '@app/utils/defineMessages';\nimport { Transition } from '@headlessui/react';\nimport { MediaServerType } from '@server/constants/server';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.LinkJellyfinModal',\n  {\n    title: 'Link {mediaServerName} Account',\n    description:\n      'Enter your {mediaServerName} credentials to link your account with {applicationName}.',\n    username: 'Username',\n    password: 'Password',\n    usernameRequired: 'You must provide a username',\n    passwordRequired: 'You must provide a password',\n    saving: 'Adding…',\n    save: 'Link',\n    errorUnauthorized:\n      'Unable to connect to {mediaServerName} using your credentials',\n    errorExists: 'This account is already linked to a {applicationName} user',\n    errorUnknown: 'An unknown error occurred',\n  }\n);\n\ninterface LinkJellyfinModalProps {\n  show: boolean;\n  onClose: () => void;\n  onSave: () => void;\n}\n\nconst LinkJellyfinModal: React.FC<LinkJellyfinModalProps> = ({\n  show,\n  onClose,\n  onSave,\n}) => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const { user } = useUser();\n  const [error, setError] = useState<string | null>(null);\n\n  const JellyfinLoginSchema = Yup.object().shape({\n    username: Yup.string().required(\n      intl.formatMessage(messages.usernameRequired)\n    ),\n    password: Yup.string().required(\n      intl.formatMessage(messages.passwordRequired)\n    ),\n  });\n\n  const applicationName = settings.currentSettings.applicationTitle;\n  const mediaServerName =\n    settings.currentSettings.mediaServerType === MediaServerType.EMBY\n      ? 'Emby'\n      : 'Jellyfin';\n\n  return (\n    <Transition\n      appear\n      show={show}\n      enter=\"transition ease-in-out duration-300 transform opacity-0\"\n      enterFrom=\"opacity-0\"\n      enterTo=\"opacuty-100\"\n      leave=\"transition ease-in-out duration-300 transform opacity-100\"\n      leaveFrom=\"opacity-100\"\n      leaveTo=\"opacity-0\"\n    >\n      <Formik\n        initialValues={{\n          username: '',\n          password: '',\n        }}\n        validationSchema={JellyfinLoginSchema}\n        onSubmit={async ({ username, password }) => {\n          try {\n            setError(null);\n            await axios.post(\n              `/api/v1/user/${user?.id}/settings/linked-accounts/jellyfin`,\n              {\n                username,\n                password,\n              }\n            );\n            onSave();\n          } catch (e) {\n            if (e?.response?.status === 401) {\n              setError(\n                intl.formatMessage(messages.errorUnauthorized, {\n                  mediaServerName,\n                })\n              );\n            } else if (e?.response?.status === 422) {\n              setError(\n                intl.formatMessage(messages.errorExists, { applicationName })\n              );\n            } else {\n              setError(intl.formatMessage(messages.errorUnknown));\n            }\n          }\n        }}\n      >\n        {({ errors, touched, handleSubmit, isSubmitting, isValid }) => {\n          return (\n            <Modal\n              onCancel={() => {\n                setError(null);\n                onClose();\n              }}\n              okButtonType=\"primary\"\n              okButtonProps={{ type: 'submit', form: 'link-jellyfin-account' }}\n              okText={\n                isSubmitting\n                  ? intl.formatMessage(messages.saving)\n                  : intl.formatMessage(messages.save)\n              }\n              okDisabled={isSubmitting || !isValid}\n              onOk={() => handleSubmit()}\n              title={intl.formatMessage(messages.title, { mediaServerName })}\n              dialogClass=\"sm:max-w-lg\"\n            >\n              <Form id=\"link-jellyfin-account\">\n                {intl.formatMessage(messages.description, {\n                  mediaServerName,\n                  applicationName,\n                })}\n                {error && (\n                  <div className=\"mt-2\">\n                    <Alert type=\"error\">{error}</Alert>\n                  </div>\n                )}\n                <label htmlFor=\"username\" className=\"text-label\">\n                  {intl.formatMessage(messages.username)}\n                </label>\n                <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n                  <div className=\"flex rounded-md shadow-sm\">\n                    <Field\n                      id=\"username\"\n                      name=\"username\"\n                      type=\"text\"\n                      placeholder={intl.formatMessage(messages.username)}\n                    />\n                  </div>\n                  {errors.username && touched.username && (\n                    <div className=\"error\">{errors.username}</div>\n                  )}\n                </div>\n                <label htmlFor=\"password\" className=\"text-label\">\n                  {intl.formatMessage(messages.password)}\n                </label>\n                <div className=\"mb-2 mt-1 sm:col-span-2 sm:mt-0\">\n                  <div className=\"flex rounded-md shadow-sm\">\n                    <Field\n                      id=\"password\"\n                      name=\"password\"\n                      type=\"password\"\n                      placeholder={intl.formatMessage(messages.password)}\n                    />\n                  </div>\n                  {errors.password && touched.password && (\n                    <div className=\"error\">{errors.password}</div>\n                  )}\n                </div>\n              </Form>\n            </Modal>\n          );\n        }}\n      </Formik>\n    </Transition>\n  );\n};\n\nexport default LinkJellyfinModal;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserLinkedAccountsSettings/index.tsx",
    "content": "import EmbyLogo from '@app/assets/services/emby-icon-only.svg';\nimport JellyfinLogo from '@app/assets/services/jellyfin-icon.svg';\nimport PlexLogo from '@app/assets/services/plex.svg';\nimport Alert from '@app/components/Common/Alert';\nimport ConfirmButton from '@app/components/Common/ConfirmButton';\nimport Dropdown from '@app/components/Common/Dropdown';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport useSettings from '@app/hooks/useSettings';\nimport { Permission, UserType, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport PlexOAuth from '@app/utils/plex';\nimport { TrashIcon } from '@heroicons/react/24/solid';\nimport { MediaServerType } from '@server/constants/server';\nimport axios from 'axios';\nimport { useRouter } from 'next/router';\nimport { useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\nimport LinkJellyfinModal from './LinkJellyfinModal';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserLinkedAccountsSettings',\n  {\n    linkedAccounts: 'Linked Accounts',\n    linkedAccountsHint:\n      'These external accounts are linked to your {applicationName} account.',\n    noLinkedAccounts:\n      'You do not have any external accounts linked to your account.',\n    noPermissionDescription:\n      \"You do not have permission to modify this user's linked accounts.\",\n    plexErrorUnauthorized: 'Unable to connect to Plex using your credentials',\n    plexErrorExists: 'This account is already linked to a Plex user',\n    errorUnknown: 'An unknown error occurred',\n    deleteFailed: 'Unable to delete linked account.',\n  }\n);\n\nconst plexOAuth = new PlexOAuth();\n\nenum LinkedAccountType {\n  Plex = 'Plex',\n  Jellyfin = 'Jellyfin',\n  Emby = 'Emby',\n}\n\ntype LinkedAccount = {\n  type: LinkedAccountType;\n  username: string;\n};\n\nconst UserLinkedAccountsSettings = () => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const router = useRouter();\n  const { user: currentUser } = useUser();\n  const {\n    user,\n    hasPermission,\n    revalidate: revalidateUser,\n  } = useUser({ id: Number(router.query.userId) });\n  const { data: passwordInfo } = useSWR<{ hasPassword: boolean }>(\n    user ? `/api/v1/user/${user?.id}/settings/password` : null\n  );\n  const [showJellyfinModal, setShowJellyfinModal] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n\n  const applicationName = settings.currentSettings.applicationTitle;\n\n  const accounts: LinkedAccount[] = useMemo(() => {\n    const accounts: LinkedAccount[] = [];\n    if (!user) return accounts;\n    if (user.userType === UserType.PLEX && user.plexUsername)\n      accounts.push({\n        type: LinkedAccountType.Plex,\n        username: user.plexUsername,\n      });\n    if (user.userType === UserType.EMBY && user.jellyfinUsername)\n      accounts.push({\n        type: LinkedAccountType.Emby,\n        username: user.jellyfinUsername,\n      });\n    if (user.userType === UserType.JELLYFIN && user.jellyfinUsername)\n      accounts.push({\n        type: LinkedAccountType.Jellyfin,\n        username: user.jellyfinUsername,\n      });\n    return accounts;\n  }, [user]);\n\n  const linkPlexAccount = async () => {\n    setError(null);\n    try {\n      const authToken = await plexOAuth.login();\n      await axios.post(\n        `/api/v1/user/${user?.id}/settings/linked-accounts/plex`,\n        {\n          authToken,\n        }\n      );\n      await revalidateUser();\n    } catch (e) {\n      switch (e?.response?.status) {\n        case 401:\n          setError(intl.formatMessage(messages.plexErrorUnauthorized));\n          break;\n        case 422:\n          setError(intl.formatMessage(messages.plexErrorExists));\n          break;\n        default:\n          setError(intl.formatMessage(messages.errorUnknown));\n      }\n    }\n  };\n\n  const linkable = [\n    {\n      name: 'Plex',\n      action: () => {\n        plexOAuth.preparePopup();\n        setTimeout(() => linkPlexAccount(), 1500);\n      },\n      hide:\n        settings.currentSettings.mediaServerType !== MediaServerType.PLEX ||\n        accounts.some((a) => a.type === LinkedAccountType.Plex),\n    },\n    {\n      name: 'Jellyfin',\n      action: () => setShowJellyfinModal(true),\n      hide:\n        settings.currentSettings.mediaServerType !== MediaServerType.JELLYFIN ||\n        accounts.some((a) => a.type === LinkedAccountType.Jellyfin),\n    },\n    {\n      name: 'Emby',\n      action: () => setShowJellyfinModal(true),\n      hide:\n        settings.currentSettings.mediaServerType !== MediaServerType.EMBY ||\n        accounts.some((a) => a.type === LinkedAccountType.Emby),\n    },\n  ].filter((l) => !l.hide);\n\n  const deleteRequest = async (account: string) => {\n    try {\n      await axios.delete(\n        `/api/v1/user/${user?.id}/settings/linked-accounts/${account}`\n      );\n    } catch {\n      setError(intl.formatMessage(messages.deleteFailed));\n    }\n\n    await revalidateUser();\n  };\n\n  if (\n    currentUser?.id !== user?.id &&\n    hasPermission(Permission.ADMIN) &&\n    currentUser?.id !== 1\n  ) {\n    return (\n      <>\n        <div className=\"mb-6\">\n          <h3 className=\"heading\">\n            {intl.formatMessage(messages.linkedAccounts)}\n          </h3>\n        </div>\n        <Alert\n          title={intl.formatMessage(messages.noPermissionDescription)}\n          type=\"error\"\n        />\n      </>\n    );\n  }\n\n  const enableMediaServerUnlink = user?.id !== 1 && passwordInfo?.hasPassword;\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.linkedAccounts),\n          intl.formatMessage(globalMessages.usersettings),\n          user?.displayName,\n        ]}\n      />\n      <div className=\"mb-6 flex items-end justify-between\">\n        <div>\n          <h3 className=\"heading\">\n            {intl.formatMessage(messages.linkedAccounts)}\n          </h3>\n          <h6 className=\"description\">\n            {intl.formatMessage(messages.linkedAccountsHint, {\n              applicationName,\n            })}\n          </h6>\n        </div>\n        {currentUser?.id === user?.id && !!linkable.length && (\n          <div>\n            <Dropdown text=\"Link Account\" buttonType=\"ghost\">\n              {linkable.map(({ name, action }) => (\n                <Dropdown.Item key={name} onClick={action}>\n                  {name}\n                </Dropdown.Item>\n              ))}\n            </Dropdown>\n          </div>\n        )}\n      </div>\n      {error && <Alert title={error} type=\"error\" />}\n      {accounts.length ? (\n        <ul className=\"space-y-4\">\n          {accounts.map((acct, i) => (\n            <li\n              key={i}\n              className=\"flex items-center gap-4 overflow-hidden rounded-lg bg-gray-800/50 px-4 py-5 shadow ring-1 ring-gray-700 sm:p-6\"\n            >\n              <div className=\"w-12\">\n                {acct.type === LinkedAccountType.Plex ? (\n                  <div className=\"flex aspect-square h-full items-center justify-center rounded-full bg-neutral-800\">\n                    <PlexLogo className=\"w-9\" />\n                  </div>\n                ) : acct.type === LinkedAccountType.Emby ? (\n                  <EmbyLogo />\n                ) : (\n                  <JellyfinLogo />\n                )}\n              </div>\n              <div>\n                <div className=\"truncate text-sm font-bold text-gray-300\">\n                  {acct.type}\n                </div>\n                <div className=\"text-xl font-semibold text-white\">\n                  {acct.username}\n                </div>\n              </div>\n              <div className=\"flex-grow\" />\n              {enableMediaServerUnlink && (\n                <ConfirmButton\n                  onClick={() => {\n                    deleteRequest(\n                      acct.type === LinkedAccountType.Plex ? 'plex' : 'jellyfin'\n                    );\n                  }}\n                  confirmText={intl.formatMessage(globalMessages.areyousure)}\n                >\n                  <TrashIcon />\n                  <span>{intl.formatMessage(globalMessages.delete)}</span>\n                </ConfirmButton>\n              )}\n            </li>\n          ))}\n        </ul>\n      ) : (\n        <div className=\"mt-4 text-center md:py-12\">\n          <h3 className=\"text-lg font-semibold text-gray-400\">\n            {intl.formatMessage(messages.noLinkedAccounts)}\n          </h3>\n        </div>\n      )}\n\n      <LinkJellyfinModal\n        show={showJellyfinModal}\n        onClose={() => setShowJellyfinModal(false)}\n        onSave={() => {\n          setShowJellyfinModal(false);\n          revalidateUser();\n        }}\n      />\n    </>\n  );\n};\n\nexport default UserLinkedAccountsSettings;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsDiscord.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserNotificationSettings',\n  {\n    discordsettingssaved: 'Discord notification settings saved successfully!',\n    discordsettingsfailed: 'Discord notification settings failed to save.',\n    discordId: 'User ID',\n    discordIdTip:\n      'The <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> associated with your user account',\n    validationDiscordId: 'You must provide a valid user ID',\n  }\n);\n\nconst UserNotificationsDiscord = () => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const router = useRouter();\n  const { user } = useUser({ id: Number(router.query.userId) });\n  const { user: currentUser } = useUser();\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<UserSettingsNotificationsResponse>(\n    user ? `/api/v1/user/${user?.id}/settings/notifications` : null\n  );\n\n  const UserNotificationsDiscordSchema = Yup.object().shape({\n    discordId: Yup.string()\n      .when('types', {\n        is: (types: number) => !!types,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationDiscordId)),\n        otherwise: Yup.string().nullable(),\n      })\n      .matches(/^\\d{17,19}$/, intl.formatMessage(messages.validationDiscordId)),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        discordId: data?.discordId,\n        types:\n          (data?.discordEnabledTypes ?? 0) &\n          (data?.notificationTypes.discord ?? 0),\n      }}\n      validationSchema={UserNotificationsDiscordSchema}\n      enableReinitialize\n      onSubmit={async (values) => {\n        try {\n          await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {\n            pgpKey: data?.pgpKey,\n            discordId: values.discordId,\n            pushbulletAccessToken: data?.pushbulletAccessToken,\n            pushoverApplicationToken: data?.pushoverApplicationToken,\n            pushoverUserKey: data?.pushoverUserKey,\n            telegramChatId: data?.telegramChatId,\n            telegramSendSilently: data?.telegramSendSilently,\n            notificationTypes: {\n              discord: values.types,\n            },\n          });\n          addToast(intl.formatMessage(messages.discordsettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.discordsettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        isValid,\n        values,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"discordId\" className=\"text-label\">\n                {intl.formatMessage(messages.discordId)}\n                {!!data?.discordEnabledTypes && (\n                  <span className=\"label-required\">*</span>\n                )}\n                {currentUser?.id === user?.id && (\n                  <span className=\"label-tip\">\n                    {intl.formatMessage(messages.discordIdTip, {\n                      FindDiscordIdLink: (msg: React.ReactNode) => (\n                        <a\n                          href=\"https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-\"\n                          target=\"_blank\"\n                          rel=\"noreferrer\"\n                        >\n                          {msg}\n                        </a>\n                      ),\n                    })}\n                  </span>\n                )}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field id=\"discordId\" name=\"discordId\" type=\"text\" />\n                </div>\n                {errors.discordId &&\n                  touched.discordId &&\n                  typeof errors.discordId === 'string' && (\n                    <div className=\"error\">{errors.discordId}</div>\n                  )}\n              </div>\n            </div>\n            <NotificationTypeSelector\n              user={user}\n              enabledTypes={data?.discordEnabledTypes ?? 0}\n              currentTypes={values.types}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n              }}\n              error={\n                errors.types && touched.types\n                  ? (errors.types as string)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={isSubmitting || !isValid}\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default UserNotificationsDiscord;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport NotificationTypeSelector, {\n  ALL_NOTIFICATIONS,\n} from '@app/components/NotificationTypeSelector';\nimport { OpenPgpLink } from '@app/components/Settings/Notifications/NotificationsEmail';\nimport SettingsBadge from '@app/components/Settings/SettingsBadge';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport axios from 'axios';\nimport { Form, Formik } from 'formik';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserNotificationSettings',\n  {\n    emailsettingssaved: 'Email notification settings saved successfully!',\n    emailsettingsfailed: 'Email notification settings failed to save.',\n    pgpPublicKey: 'PGP Public Key',\n    pgpPublicKeyTip:\n      'Encrypt email messages using <OpenPgpLink>OpenPGP</OpenPgpLink>',\n    validationPgpPublicKey: 'You must provide a valid PGP public key',\n  }\n);\n\nconst UserEmailSettings = () => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const router = useRouter();\n  const { user } = useUser({ id: Number(router.query.userId) });\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<UserSettingsNotificationsResponse>(\n    user ? `/api/v1/user/${user?.id}/settings/notifications` : null\n  );\n\n  const UserNotificationsEmailSchema = Yup.object().shape({\n    pgpKey: Yup.string()\n      .nullable()\n      .matches(\n        /-----BEGIN PGP PUBLIC KEY BLOCK-----.+-----END PGP PUBLIC KEY BLOCK-----/s,\n        intl.formatMessage(messages.validationPgpPublicKey)\n      ),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        pgpKey: data?.pgpKey,\n        types: data?.notificationTypes.email ?? ALL_NOTIFICATIONS,\n      }}\n      validationSchema={UserNotificationsEmailSchema}\n      enableReinitialize\n      onSubmit={async (values) => {\n        try {\n          await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {\n            pgpKey: values.pgpKey,\n            discordId: data?.discordId,\n            pushbulletAccessToken: data?.pushbulletAccessToken,\n            pushoverApplicationToken: data?.pushoverApplicationToken,\n            pushoverUserKey: data?.pushoverUserKey,\n            telegramChatId: data?.telegramChatId,\n            telegramSendSilently: data?.telegramSendSilently,\n            notificationTypes: {\n              email: values.types,\n            },\n          });\n          addToast(intl.formatMessage(messages.emailsettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.emailsettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        isValid,\n        values,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"pgpKey\" className=\"text-label\">\n                <span className=\"mr-2\">\n                  {intl.formatMessage(messages.pgpPublicKey)}\n                </span>\n                <SettingsBadge badgeType=\"advanced\" />\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.pgpPublicKeyTip, {\n                    OpenPgpLink: OpenPgpLink,\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <SensitiveInput\n                    as=\"field\"\n                    type=\"textarea\"\n                    id=\"pgpKey\"\n                    name=\"pgpKey\"\n                    rows=\"10\"\n                    className=\"font-mono text-xs\"\n                  />\n                </div>\n                {errors.pgpKey &&\n                  touched.pgpKey &&\n                  typeof errors.pgpKey === 'string' && (\n                    <div className=\"error\">{errors.pgpKey}</div>\n                  )}\n              </div>\n            </div>\n            <NotificationTypeSelector\n              user={user}\n              currentTypes={values.types}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n              }}\n              error={\n                errors.types && touched.types\n                  ? (errors.types as string)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={isSubmitting || !isValid}\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default UserEmailSettings;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsPushbullet.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport axios from 'axios';\nimport { Form, Formik } from 'formik';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserNotificationSettings',\n  {\n    pushbulletsettingssaved:\n      'Pushbullet notification settings saved successfully!',\n    pushbulletsettingsfailed:\n      'Pushbullet notification settings failed to save.',\n    pushbulletAccessToken: 'Access Token',\n    pushbulletAccessTokenTip:\n      'Create a token from your <PushbulletSettingsLink>Account Settings</PushbulletSettingsLink>',\n    validationPushbulletAccessToken: 'You must provide an access token',\n  }\n);\n\nconst UserPushbulletSettings = () => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const router = useRouter();\n  const { user } = useUser({ id: Number(router.query.userId) });\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<UserSettingsNotificationsResponse>(\n    user ? `/api/v1/user/${user?.id}/settings/notifications` : null\n  );\n\n  const UserNotificationsPushbulletSchema = Yup.object().shape({\n    pushbulletAccessToken: Yup.string().when('types', {\n      is: (types: number) => !!types,\n      then: Yup.string()\n        .nullable()\n        .required(intl.formatMessage(messages.validationPushbulletAccessToken)),\n      otherwise: Yup.string().nullable(),\n    }),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        pushbulletAccessToken: data?.pushbulletAccessToken,\n        types: data?.notificationTypes.pushbullet ?? 0,\n      }}\n      validationSchema={UserNotificationsPushbulletSchema}\n      enableReinitialize\n      onSubmit={async (values) => {\n        try {\n          await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {\n            pgpKey: data?.pgpKey,\n            discordId: data?.discordId,\n            pushbulletAccessToken: values.pushbulletAccessToken,\n            pushoverApplicationToken: data?.pushoverApplicationToken,\n            pushoverUserKey: data?.pushoverUserKey,\n            telegramChatId: data?.telegramChatId,\n            telegramSendSilently: data?.telegramSendSilently,\n            notificationTypes: {\n              pushbullet: values.types,\n            },\n          });\n          addToast(intl.formatMessage(messages.pushbulletsettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.pushbulletsettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        isValid,\n        values,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"pushbulletAccessToken\" className=\"text-label\">\n                {intl.formatMessage(messages.pushbulletAccessToken)}\n                <span className=\"label-required\">*</span>\n                {data?.pushbulletAccessToken && (\n                  <span className=\"label-tip\">\n                    {intl.formatMessage(messages.pushbulletAccessTokenTip, {\n                      PushbulletSettingsLink: (msg: React.ReactNode) => (\n                        <a\n                          href=\"https://www.pushbullet.com/#settings/account\"\n                          className=\"text-white transition duration-300 hover:underline\"\n                          target=\"_blank\"\n                          rel=\"noreferrer\"\n                        >\n                          {msg}\n                        </a>\n                      ),\n                    })}\n                  </span>\n                )}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <SensitiveInput\n                    as=\"field\"\n                    id=\"pushbulletAccessToken\"\n                    name=\"pushbulletAccessToken\"\n                    type=\"text\"\n                  />\n                </div>\n                {errors.pushbulletAccessToken &&\n                  touched.pushbulletAccessToken && (\n                    <div className=\"error\">{errors.pushbulletAccessToken}</div>\n                  )}\n              </div>\n            </div>\n            <NotificationTypeSelector\n              user={user}\n              currentTypes={values.types}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n              }}\n              error={\n                errors.types && touched.types\n                  ? (errors.types as string)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={isSubmitting || !isValid}\n                  >\n                    {isSubmitting\n                      ? intl.formatMessage(globalMessages.saving)\n                      : intl.formatMessage(globalMessages.save)}\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default UserPushbulletSettings;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsPushover.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport useSettings from '@app/hooks/useSettings';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { PushoverSound } from '@server/api/pushover';\nimport type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserNotificationSettings',\n  {\n    pushoversettingssaved: 'Pushover notification settings saved successfully!',\n    pushoversettingsfailed: 'Pushover notification settings failed to save.',\n    pushoverApplicationToken: 'Application API Token',\n    pushoverApplicationTokenTip:\n      '<ApplicationRegistrationLink>Register an application</ApplicationRegistrationLink> for use with {applicationTitle}',\n    pushoverUserKey: 'User or Group Key',\n    pushoverUserKeyTip:\n      'Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>',\n    sound: 'Notification Sound',\n    deviceDefault: 'Device Default',\n    validationPushoverApplicationToken:\n      'You must provide a valid application token',\n    validationPushoverUserKey: 'You must provide a valid user or group key',\n  }\n);\n\nconst UserPushoverSettings = () => {\n  const intl = useIntl();\n  const settings = useSettings();\n  const { addToast } = useToasts();\n  const router = useRouter();\n  const { user } = useUser({ id: Number(router.query.userId) });\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<UserSettingsNotificationsResponse>(\n    user ? `/api/v1/user/${user?.id}/settings/notifications` : null\n  );\n  const { data: soundsData } = useSWR<PushoverSound[]>(\n    data?.pushoverApplicationToken\n      ? `/api/v1/settings/notifications/pushover/sounds?token=${data.pushoverApplicationToken}`\n      : null\n  );\n\n  const UserNotificationsPushoverSchema = Yup.object().shape({\n    pushoverApplicationToken: Yup.string()\n      .when('types', {\n        is: (types: number) => !!types,\n        then: Yup.string()\n          .nullable()\n          .required(\n            intl.formatMessage(messages.validationPushoverApplicationToken)\n          ),\n        otherwise: Yup.string().nullable(),\n      })\n      .matches(\n        /^[a-z\\d]{30}$/i,\n        intl.formatMessage(messages.validationPushoverApplicationToken)\n      ),\n    pushoverUserKey: Yup.string()\n      .when('types', {\n        is: (types: number) => !!types,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationPushoverUserKey)),\n        otherwise: Yup.string().nullable(),\n      })\n      .matches(\n        /^[a-z\\d]{30}$/i,\n        intl.formatMessage(messages.validationPushoverUserKey)\n      ),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        pushoverApplicationToken: data?.pushoverApplicationToken,\n        pushoverUserKey: data?.pushoverUserKey,\n        types: data?.notificationTypes.pushover ?? 0,\n      }}\n      validationSchema={UserNotificationsPushoverSchema}\n      enableReinitialize\n      onSubmit={async (values) => {\n        try {\n          await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {\n            pgpKey: data?.pgpKey,\n            discordId: data?.discordId,\n            pushbulletAccessToken: data?.pushbulletAccessToken,\n            pushoverApplicationToken: values.pushoverApplicationToken,\n            pushoverUserKey: values.pushoverUserKey,\n            telegramChatId: data?.telegramChatId,\n            telegramSendSilently: data?.telegramSendSilently,\n            notificationTypes: {\n              pushover: values.types,\n            },\n          });\n          addToast(intl.formatMessage(messages.pushoversettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.pushoversettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        isValid,\n        values,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"pushoverApplicationToken\" className=\"text-label\">\n                {intl.formatMessage(messages.pushoverApplicationToken)}\n                <span className=\"label-required\">*</span>\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.pushoverApplicationTokenTip, {\n                    ApplicationRegistrationLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://pushover.net/api#registration\"\n                        className=\"text-white transition duration-300 hover:underline\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                    applicationTitle: settings.currentSettings.applicationTitle,\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"pushoverApplicationToken\"\n                    name=\"pushoverApplicationToken\"\n                    type=\"text\"\n                  />\n                </div>\n                {errors.pushoverApplicationToken &&\n                  touched.pushoverApplicationToken && (\n                    <div className=\"error\">\n                      {errors.pushoverApplicationToken}\n                    </div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"pushoverUserKey\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.pushoverUserKey)}\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.pushoverUserKeyTip, {\n                    UsersGroupsLink: (msg: React.ReactNode) => (\n                      <a\n                        href=\"https://pushover.net/api#identifiers\"\n                        className=\"text-white transition duration-300 hover:underline\"\n                        target=\"_blank\"\n                        rel=\"noreferrer\"\n                      >\n                        {msg}\n                      </a>\n                    ),\n                  })}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"pushoverUserKey\"\n                    name=\"pushoverUserKey\"\n                    type=\"text\"\n                  />\n                </div>\n                {errors.pushoverUserKey &&\n                  touched.pushoverUserKey &&\n                  typeof errors.pushoverUserKey === 'string' && (\n                    <div className=\"error\">{errors.pushoverUserKey}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"sound\" className=\"text-label\">\n                {intl.formatMessage(messages.sound)}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    as=\"select\"\n                    id=\"sound\"\n                    name=\"sound\"\n                    disabled={!soundsData?.length}\n                  >\n                    <option value=\"\">\n                      {intl.formatMessage(messages.deviceDefault)}\n                    </option>\n                    {soundsData?.map((sound, index) => (\n                      <option key={`sound-${index}`} value={sound.name}>\n                        {sound.description}\n                      </option>\n                    ))}\n                  </Field>\n                </div>\n              </div>\n            </div>\n            <NotificationTypeSelector\n              user={user}\n              currentTypes={values.types}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n              }}\n              error={\n                errors.types && touched.types\n                  ? (errors.types as string)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={isSubmitting || !isValid}\n                  >\n                    {isSubmitting\n                      ? intl.formatMessage(globalMessages.saving)\n                      : intl.formatMessage(globalMessages.save)}\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default UserPushoverSettings;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsTelegram.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport NotificationTypeSelector from '@app/components/NotificationTypeSelector';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport axios from 'axios';\nimport { Field, Form, Formik } from 'formik';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserNotificationSettings',\n  {\n    telegramsettingssaved: 'Telegram notification settings saved successfully!',\n    telegramsettingsfailed: 'Telegram notification settings failed to save.',\n    telegramChatId: 'Chat ID',\n    telegramChatIdTipLong:\n      '<TelegramBotLink>Start a chat</TelegramBotLink>, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command',\n    telegramMessageThreadId: 'Thread/Topic ID',\n    telegramMessageThreadIdTip:\n      \"If your group-chat has topics enabled, you can specify a thread/topic's ID here\",\n    sendSilently: 'Send Silently',\n    sendSilentlyDescription: 'Send notifications with no sound',\n    validationTelegramChatId: 'You must provide a valid chat ID',\n    validationTelegramMessageThreadId:\n      'The thread/topic ID must be a positive whole number',\n  }\n);\n\nconst UserTelegramSettings = () => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const router = useRouter();\n  const { user } = useUser({ id: Number(router.query.userId) });\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<UserSettingsNotificationsResponse>(\n    user ? `/api/v1/user/${user?.id}/settings/notifications` : null\n  );\n\n  const UserNotificationsTelegramSchema = Yup.object().shape({\n    telegramChatId: Yup.string()\n      .when('types', {\n        is: (types: number) => !!types,\n        then: Yup.string()\n          .nullable()\n          .required(intl.formatMessage(messages.validationTelegramChatId)),\n        otherwise: Yup.string().nullable(),\n      })\n      .matches(\n        /^-?\\d+$/,\n        intl.formatMessage(messages.validationTelegramChatId)\n      ),\n    telegramMessageThreadId: Yup.string()\n      .when(['types'], {\n        is: (enabled: boolean, types: number) => enabled && !!types,\n        then: Yup.string()\n          .nullable()\n          .required(\n            intl.formatMessage(messages.validationTelegramMessageThreadId)\n          ),\n        otherwise: Yup.string().nullable(),\n      })\n      .matches(\n        /^\\d+$/,\n        intl.formatMessage(messages.validationTelegramMessageThreadId)\n      ),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <Formik\n      initialValues={{\n        telegramChatId: data?.telegramChatId,\n        telegramMessageThreadId: data?.telegramMessageThreadId,\n        telegramSendSilently: data?.telegramSendSilently,\n        types: data?.notificationTypes.telegram ?? 0,\n      }}\n      validationSchema={UserNotificationsTelegramSchema}\n      enableReinitialize\n      onSubmit={async (values) => {\n        try {\n          await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {\n            pgpKey: data?.pgpKey,\n            discordId: data?.discordId,\n            pushbulletAccessToken: data?.pushbulletAccessToken,\n            pushoverApplicationToken: data?.pushoverApplicationToken,\n            pushoverUserKey: data?.pushoverUserKey,\n            telegramChatId: values.telegramChatId,\n            telegramMessageThreadId: values.telegramMessageThreadId,\n            telegramSendSilently: values.telegramSendSilently,\n            notificationTypes: {\n              telegram: values.types,\n            },\n          });\n          addToast(intl.formatMessage(messages.telegramsettingssaved), {\n            appearance: 'success',\n            autoDismiss: true,\n          });\n        } catch {\n          addToast(intl.formatMessage(messages.telegramsettingsfailed), {\n            appearance: 'error',\n            autoDismiss: true,\n          });\n        } finally {\n          revalidate();\n        }\n      }}\n    >\n      {({\n        errors,\n        touched,\n        isSubmitting,\n        isValid,\n        values,\n        setFieldValue,\n        setFieldTouched,\n      }) => {\n        return (\n          <Form className=\"section\">\n            <div className=\"form-row\">\n              <label htmlFor=\"telegramChatId\" className=\"text-label\">\n                {intl.formatMessage(messages.telegramChatId)}\n                <span className=\"label-required\">*</span>\n                {data?.telegramBotUsername && (\n                  <span className=\"label-tip\">\n                    {intl.formatMessage(messages.telegramChatIdTipLong, {\n                      TelegramBotLink: (msg: React.ReactNode) => (\n                        <a\n                          href={`https://telegram.me/${data.telegramBotUsername}`}\n                          target=\"_blank\"\n                          rel=\"noreferrer\"\n                        >\n                          {msg}\n                        </a>\n                      ),\n                      GetIdBotLink: (msg: React.ReactNode) => (\n                        <a\n                          href=\"https://telegram.me/get_id_bot\"\n                          target=\"_blank\"\n                          rel=\"noreferrer\"\n                        >\n                          {msg}\n                        </a>\n                      ),\n                      code: (msg: React.ReactNode) => <code>{msg}</code>,\n                    })}\n                  </span>\n                )}\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"telegramChatId\"\n                    name=\"telegramChatId\"\n                    type=\"text\"\n                  />\n                </div>\n                {errors.telegramChatId &&\n                  touched.telegramChatId &&\n                  typeof errors.telegramChatId === 'string' && (\n                    <div className=\"error\">{errors.telegramChatId}</div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"telegramMessageThreadId\" className=\"text-label\">\n                {intl.formatMessage(messages.telegramMessageThreadId)}\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.telegramMessageThreadIdTip)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <div className=\"form-input-field\">\n                  <Field\n                    id=\"telegramMessageThreadId\"\n                    name=\"telegramMessageThreadId\"\n                    type=\"text\"\n                  />\n                </div>\n                {errors.telegramMessageThreadId &&\n                  touched.telegramMessageThreadId &&\n                  typeof errors.telegramMessageThreadId === 'string' && (\n                    <div className=\"error\">\n                      {errors.telegramMessageThreadId}\n                    </div>\n                  )}\n              </div>\n            </div>\n            <div className=\"form-row\">\n              <label htmlFor=\"telegramSendSilently\" className=\"checkbox-label\">\n                {intl.formatMessage(messages.sendSilently)}\n                <span className=\"label-tip\">\n                  {intl.formatMessage(messages.sendSilentlyDescription)}\n                </span>\n              </label>\n              <div className=\"form-input-area\">\n                <Field\n                  type=\"checkbox\"\n                  id=\"telegramSendSilently\"\n                  name=\"telegramSendSilently\"\n                />\n              </div>\n            </div>\n            <NotificationTypeSelector\n              user={user}\n              currentTypes={values.types}\n              onUpdate={(newTypes) => {\n                setFieldValue('types', newTypes);\n                setFieldTouched('types');\n              }}\n              error={\n                errors.types && touched.types\n                  ? (errors.types as string)\n                  : undefined\n              }\n            />\n            <div className=\"actions\">\n              <div className=\"flex justify-end\">\n                <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                  <Button\n                    buttonType=\"primary\"\n                    type=\"submit\"\n                    disabled={isSubmitting || !isValid}\n                  >\n                    <ArrowDownOnSquareIcon />\n                    <span>\n                      {isSubmitting\n                        ? intl.formatMessage(globalMessages.saving)\n                        : intl.formatMessage(globalMessages.save)}\n                    </span>\n                  </Button>\n                </span>\n              </div>\n            </div>\n          </Form>\n        );\n      }}\n    </Formik>\n  );\n};\n\nexport default UserTelegramSettings;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/DeviceItem.tsx",
    "content": "import Button from '@app/components/Common/Button';\nimport ConfirmButton from '@app/components/Common/ConfirmButton';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport {\n  ComputerDesktopIcon,\n  DevicePhoneMobileIcon,\n  LockClosedIcon,\n  TrashIcon,\n} from '@heroicons/react/24/solid';\nimport { useIntl } from 'react-intl';\nimport { UAParser } from 'ua-parser-js';\n\ninterface DeviceItemProps {\n  deletePushSubscriptionFromBackend: (endpoint: string) => void;\n  device: {\n    endpoint: string;\n    p256dh: string;\n    auth: string;\n    userAgent: string;\n    createdAt: Date;\n  };\n  subEndpoint: string | null;\n}\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush',\n  {\n    operatingsystem: 'Operating System',\n    browser: 'Browser',\n    engine: 'Engine',\n    deletesubscription: 'Delete Subscription',\n    unknown: 'Unknown',\n    activesubscription: 'Active Subscription',\n  }\n);\n\nconst DeviceItem = ({\n  deletePushSubscriptionFromBackend,\n  device,\n  subEndpoint,\n}: DeviceItemProps) => {\n  const intl = useIntl();\n  const parsedUserAgent = UAParser(device.userAgent);\n\n  return (\n    <div className=\"relative flex w-full flex-col justify-between overflow-hidden rounded-xl bg-gray-800 py-4 text-gray-400 shadow-md ring-1 ring-gray-700 xl:h-28 xl:flex-row\">\n      <div className=\"relative flex w-full flex-col justify-between overflow-hidden sm:flex-row\">\n        <div className=\"relative z-10 flex w-full items-center overflow-hidden pl-4 pr-4 sm:pr-0 xl:w-7/12 2xl:w-2/3\">\n          <div className=\"relative h-auto w-12 flex-shrink-0 scale-100 transform-gpu overflow-hidden rounded-md transition duration-300 hover:scale-105\">\n            {parsedUserAgent.device.type === 'mobile' ? (\n              <DevicePhoneMobileIcon />\n            ) : (\n              <ComputerDesktopIcon />\n            )}\n          </div>\n          <div className=\"flex flex-col justify-center overflow-hidden pl-2 xl:pl-4\">\n            <div className=\"pt-0.5 text-xs font-medium text-white sm:pt-1\">\n              {device.createdAt\n                ? intl.formatDate(device.createdAt, {\n                    year: 'numeric',\n                    month: 'long',\n                    day: 'numeric',\n                  })\n                : 'N/A'}\n            </div>\n            <div className=\"mr-2 min-w-0 truncate text-lg font-bold text-white hover:underline xl:text-xl\">\n              {device.userAgent && parsedUserAgent.device.model\n                ? parsedUserAgent.device.model\n                : intl.formatMessage(messages.unknown)}\n            </div>\n          </div>\n        </div>\n        <div className=\"z-10 ml-4 mt-4 flex w-full flex-col justify-center overflow-hidden pr-4 text-sm sm:ml-2 sm:mt-0 xl:flex-1 xl:pr-0\">\n          <div className=\"card-field\">\n            <span className=\"card-field-name\">\n              {intl.formatMessage(messages.operatingsystem)}\n            </span>\n            <span className=\"flex truncate text-sm text-gray-300\">\n              {device.userAgent ? parsedUserAgent.os.name : 'N/A'}\n            </span>\n          </div>\n          <div className=\"card-field\">\n            <span className=\"card-field-name\">\n              {intl.formatMessage(messages.browser)}\n            </span>\n            <span className=\"flex truncate text-sm text-gray-300\">\n              {device.userAgent ? parsedUserAgent.browser.name : 'N/A'}\n            </span>\n          </div>\n          <div className=\"card-field\">\n            <span className=\"card-field-name\">\n              {intl.formatMessage(messages.engine)}\n            </span>\n            <span className=\"flex truncate text-sm text-gray-300\">\n              {device.userAgent ? parsedUserAgent.engine.name : 'N/A'}\n            </span>\n          </div>\n        </div>\n      </div>\n      <div className=\"z-10 mt-4 flex w-full flex-col justify-center space-y-2 pl-4 pr-4 xl:mt-0 xl:w-96 xl:items-end xl:pl-0\">\n        {subEndpoint === device.endpoint ? (\n          <Button buttonType=\"primary\" className=\"w-full\" disabled>\n            <LockClosedIcon />{' '}\n            <span>{intl.formatMessage(messages.activesubscription)}</span>\n          </Button>\n        ) : (\n          <ConfirmButton\n            onClick={() => deletePushSubscriptionFromBackend(device.endpoint)}\n            confirmText={intl.formatMessage(globalMessages.areyousure)}\n            className=\"w-full\"\n          >\n            <TrashIcon />\n            <span>{intl.formatMessage(messages.deletesubscription)}</span>\n          </ConfirmButton>\n        )}\n      </div>\n    </div>\n  );\n};\n\nexport default DeviceItem;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/index.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport NotificationTypeSelector, {\n  ALL_NOTIFICATIONS,\n} from '@app/components/NotificationTypeSelector';\nimport DeviceItem from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/DeviceItem';\nimport useSettings from '@app/hooks/useSettings';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport defineMessages from '@app/utils/defineMessages';\nimport {\n  getPushSubscription,\n  subscribeToPushNotifications,\n  unsubscribeToPushNotifications,\n  verifyPushSubscription,\n} from '@app/utils/pushSubscriptionHelpers';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport {\n  CloudArrowDownIcon,\n  CloudArrowUpIcon,\n} from '@heroicons/react/24/solid';\nimport type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport axios from 'axios';\nimport { Form, Formik } from 'formik';\nimport { useRouter } from 'next/router';\nimport { useEffect, useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR, { mutate } from 'swr';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush',\n  {\n    webpushsettingssaved: 'Web push notification settings saved successfully!',\n    webpushsettingsfailed: 'Web push notification settings failed to save.',\n    enablewebpush: 'Enable web push',\n    disablewebpush: 'Disable web push',\n    managedevices: 'Manage Devices',\n    type: 'type',\n    created: 'Created',\n    device: 'Device',\n    subscriptiondeleted: 'Subscription deleted.',\n    subscriptiondeleteerror:\n      'Something went wrong while deleting the user subscription.',\n    nodevicestoshow: 'You have no web push subscriptions to show.',\n    webpushhasbeenenabled: 'Web push has been enabled.',\n    webpushhasbeendisabled: 'Web push has been disabled.',\n    enablingwebpusherror: 'Something went wrong while enabling web push.',\n    disablingwebpusherror: 'Something went wrong while disabling web push.',\n  }\n);\n\nconst UserWebPushSettings = () => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const router = useRouter();\n  const { user } = useUser({ id: Number(router.query.userId) });\n  const { currentSettings } = useSettings();\n  const [webPushEnabled, setWebPushEnabled] = useState(false);\n  const [subEndpoint, setSubEndpoint] = useState<string | null>(null);\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<UserSettingsNotificationsResponse>(\n    user ? `/api/v1/user/${user?.id}/settings/notifications` : null\n  );\n  const { data: dataDevices, mutate: revalidateDevices } = useSWR<\n    {\n      endpoint: string;\n      p256dh: string;\n      auth: string;\n      userAgent: string;\n      createdAt: Date;\n    }[]\n  >(`/api/v1/user/${user?.id}/pushSubscriptions`, { revalidateOnMount: true });\n\n  // Subscribes to the push manager\n  // Will only add to the database if subscribing for the first time\n  const enablePushNotifications = async () => {\n    try {\n      const isSubscribed = await subscribeToPushNotifications(\n        user?.id,\n        currentSettings\n      );\n\n      if (isSubscribed) {\n        localStorage.setItem('pushNotificationsEnabled', 'true');\n        setWebPushEnabled(true);\n        addToast(intl.formatMessage(messages.webpushhasbeenenabled), {\n          appearance: 'success',\n          autoDismiss: true,\n        });\n      } else {\n        throw new Error('Subscription failed');\n      }\n    } catch {\n      addToast(intl.formatMessage(messages.enablingwebpusherror), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n    } finally {\n      revalidateDevices();\n    }\n  };\n\n  // Unsubscribes from the push manager\n  // Deletes/disables corresponding push subscription from database\n  const disablePushNotifications = async (endpoint?: string) => {\n    try {\n      const unsubscribedEndpoint = await unsubscribeToPushNotifications(\n        user?.id,\n        endpoint\n      );\n\n      localStorage.setItem('pushNotificationsEnabled', 'false');\n      setWebPushEnabled(false);\n\n      // Only delete the current browser's subscription, not all devices\n      const endpointToDelete = unsubscribedEndpoint || subEndpoint || endpoint;\n      if (endpointToDelete) {\n        try {\n          await axios.delete(\n            `/api/v1/user/${user?.id}/pushSubscription/${encodeURIComponent(\n              endpointToDelete\n            )}`\n          );\n        } catch {\n          // Ignore deletion failures - backend cleanup is best effort\n        }\n      }\n\n      addToast(intl.formatMessage(messages.webpushhasbeendisabled), {\n        autoDismiss: true,\n        appearance: 'success',\n      });\n    } catch {\n      addToast(intl.formatMessage(messages.disablingwebpusherror), {\n        autoDismiss: true,\n        appearance: 'error',\n      });\n    } finally {\n      revalidateDevices();\n    }\n  };\n\n  const deletePushSubscriptionFromBackend = async (endpoint: string) => {\n    try {\n      await axios.delete(\n        `/api/v1/user/${user?.id}/pushSubscription/${encodeURIComponent(\n          endpoint\n        )}`\n      );\n\n      addToast(intl.formatMessage(messages.subscriptiondeleted), {\n        autoDismiss: true,\n        appearance: 'success',\n      });\n    } catch {\n      addToast(intl.formatMessage(messages.subscriptiondeleteerror), {\n        autoDismiss: true,\n        appearance: 'error',\n      });\n    } finally {\n      revalidateDevices();\n    }\n  };\n\n  useEffect(() => {\n    const verifyWebPush = async () => {\n      const enabled = await verifyPushSubscription(user?.id, currentSettings);\n      let isEnabled = enabled;\n\n      if (!enabled && 'serviceWorker' in navigator) {\n        const { subscription } = await getPushSubscription();\n        if (subscription) {\n          isEnabled = true;\n        }\n      }\n\n      if (!isEnabled && dataDevices && dataDevices.length > 0) {\n        const currentUserAgent = navigator.userAgent;\n        const hasMatchingDevice = dataDevices.some(\n          (device) => device.userAgent === currentUserAgent\n        );\n\n        if (hasMatchingDevice) {\n          isEnabled = true;\n        }\n      }\n\n      setWebPushEnabled(isEnabled);\n      if (localStorage.getItem('pushNotificationsEnabled') === null) {\n        localStorage.setItem(\n          'pushNotificationsEnabled',\n          isEnabled ? 'true' : 'false'\n        );\n      }\n    };\n\n    if (user?.id) {\n      verifyWebPush();\n    }\n  }, [user?.id, currentSettings, dataDevices]);\n\n  useEffect(() => {\n    const getSubscriptionEndpoint = async () => {\n      if ('serviceWorker' in navigator && 'PushManager' in window) {\n        const { subscription } = await getPushSubscription();\n\n        if (subscription) {\n          setSubEndpoint(subscription.endpoint);\n        } else {\n          setSubEndpoint(null);\n        }\n      }\n    };\n\n    getSubscriptionEndpoint();\n  }, [webPushEnabled]);\n\n  const sortedDevices = useMemo(() => {\n    if (!dataDevices || !subEndpoint) {\n      return dataDevices;\n    }\n\n    return [...dataDevices].sort((a, b) => {\n      if (a.endpoint === subEndpoint) {\n        return -1;\n      }\n      if (b.endpoint === subEndpoint) {\n        return 1;\n      }\n\n      const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n      const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n      return dateB - dateA;\n    });\n  }, [dataDevices, subEndpoint]);\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  return (\n    <>\n      <Formik\n        initialValues={{\n          types: data?.notificationTypes.webpush ?? ALL_NOTIFICATIONS,\n        }}\n        enableReinitialize\n        onSubmit={async (values) => {\n          try {\n            await axios.post(\n              `/api/v1/user/${user?.id}/settings/notifications`,\n              {\n                pgpKey: data?.pgpKey,\n                discordId: data?.discordId,\n                pushbulletAccessToken: data?.pushbulletAccessToken,\n                pushoverApplicationToken: data?.pushoverApplicationToken,\n                pushoverUserKey: data?.pushoverUserKey,\n                telegramChatId: data?.telegramChatId,\n                telegramSendSilently: data?.telegramSendSilently,\n                notificationTypes: {\n                  webpush: values.types,\n                },\n              }\n            );\n            mutate('/api/v1/settings/public');\n            addToast(intl.formatMessage(messages.webpushsettingssaved), {\n              appearance: 'success',\n              autoDismiss: true,\n            });\n          } catch {\n            addToast(intl.formatMessage(messages.webpushsettingsfailed), {\n              appearance: 'error',\n              autoDismiss: true,\n            });\n          } finally {\n            revalidate();\n          }\n        }}\n      >\n        {({\n          errors,\n          touched,\n          isSubmitting,\n          isValid,\n          values,\n          setFieldValue,\n          setFieldTouched,\n        }) => {\n          return (\n            <Form className=\"section\">\n              <NotificationTypeSelector\n                user={user}\n                currentTypes={values.types}\n                onUpdate={(newTypes) => {\n                  setFieldValue('types', newTypes);\n                  setFieldTouched('types');\n                }}\n                error={\n                  errors.types && touched.types\n                    ? (errors.types as string)\n                    : undefined\n                }\n              />\n              <div className=\"actions\">\n                <div className=\"flex justify-end\">\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType={`${webPushEnabled ? 'danger' : 'primary'}`}\n                      type=\"button\"\n                      onClick={() =>\n                        webPushEnabled\n                          ? disablePushNotifications()\n                          : enablePushNotifications()\n                      }\n                    >\n                      {webPushEnabled ? (\n                        <CloudArrowDownIcon />\n                      ) : (\n                        <CloudArrowUpIcon />\n                      )}\n                      <span>\n                        {webPushEnabled\n                          ? intl.formatMessage(messages.disablewebpush)\n                          : intl.formatMessage(messages.enablewebpush)}\n                      </span>\n                    </Button>\n                  </span>\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"primary\"\n                      type=\"submit\"\n                      disabled={isSubmitting || !isValid}\n                    >\n                      <ArrowDownOnSquareIcon />\n                      <span>\n                        {isSubmitting\n                          ? intl.formatMessage(globalMessages.saving)\n                          : intl.formatMessage(globalMessages.save)}\n                      </span>\n                    </Button>\n                  </span>\n                </div>\n              </div>\n            </Form>\n          );\n        }}\n      </Formik>\n      <div className=\"mb-6 mt-10\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.managedevices)}\n        </h3>\n        <div className=\"section\">\n          {sortedDevices?.length ? (\n            sortedDevices.map((device) => (\n              <div className=\"py-2\" key={`device-list-${device.endpoint}`}>\n                <DeviceItem\n                  deletePushSubscriptionFromBackend={\n                    deletePushSubscriptionFromBackend\n                  }\n                  device={device}\n                  subEndpoint={subEndpoint}\n                />\n              </div>\n            ))\n          ) : (\n            <>\n              <Alert\n                title={intl.formatMessage(messages.nodevicestoshow)}\n                type=\"info\"\n              />\n            </>\n          )}\n        </div>\n      </div>\n    </>\n  );\n};\n\nexport default UserWebPushSettings;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserNotificationSettings/index.tsx",
    "content": "import DiscordLogo from '@app/assets/extlogos/discord.svg';\nimport PushbulletLogo from '@app/assets/extlogos/pushbullet.svg';\nimport PushoverLogo from '@app/assets/extlogos/pushover.svg';\nimport TelegramLogo from '@app/assets/extlogos/telegram.svg';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport type { SettingsRoute } from '@app/components/Common/SettingsTabs';\nimport SettingsTabs from '@app/components/Common/SettingsTabs';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { CloudIcon, EnvelopeIcon } from '@heroicons/react/24/solid';\nimport type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserNotificationSettings',\n  {\n    notifications: 'Notifications',\n    notificationsettings: 'Notification Settings',\n    email: 'Email',\n    webpush: 'Web Push',\n  }\n);\n\ntype UserNotificationSettingsProps = {\n  children: React.ReactNode;\n};\n\nconst UserNotificationSettings = ({\n  children,\n}: UserNotificationSettingsProps) => {\n  const intl = useIntl();\n  const router = useRouter();\n  const { user } = useUser({ id: Number(router.query.userId) });\n  const { data, error } = useSWR<UserSettingsNotificationsResponse>(\n    user ? `/api/v1/user/${user?.id}/settings/notifications` : null\n  );\n\n  const settingsRoutes: SettingsRoute[] = [\n    {\n      text: intl.formatMessage(messages.email),\n      content: (\n        <span className=\"flex items-center\">\n          <EnvelopeIcon className=\"mr-2 h-4\" />\n          {intl.formatMessage(messages.email)}\n        </span>\n      ),\n      route: '/settings/notifications/email',\n      regex: /\\/settings\\/notifications\\/email/,\n      hidden: !data?.emailEnabled,\n    },\n    {\n      text: intl.formatMessage(messages.webpush),\n      content: (\n        <span className=\"flex items-center\">\n          <CloudIcon className=\"mr-2 h-4\" />\n          {intl.formatMessage(messages.webpush)}\n        </span>\n      ),\n      route: '/settings/notifications/webpush',\n      regex: /\\/settings\\/notifications\\/webpush/,\n      hidden: !data?.webPushEnabled,\n    },\n    {\n      text: 'Discord',\n      content: (\n        <span className=\"flex items-center\">\n          <DiscordLogo className=\"mr-2 h-4\" />\n          Discord\n        </span>\n      ),\n      route: '/settings/notifications/discord',\n      regex: /\\/settings\\/notifications\\/discord/,\n      hidden: !data?.discordEnabled,\n    },\n    {\n      text: 'Pushbullet',\n      content: (\n        <span className=\"flex items-center\">\n          <PushbulletLogo className=\"mr-2 h-4\" />\n          Pushbullet\n        </span>\n      ),\n      route: '/settings/notifications/pushbullet',\n      regex: /\\/settings\\/notifications\\/pushbullet/,\n    },\n    {\n      text: 'Pushover',\n      content: (\n        <span className=\"flex items-center\">\n          <PushoverLogo className=\"mr-2 h-4\" />\n          Pushover\n        </span>\n      ),\n      route: '/settings/notifications/pushover',\n      regex: /\\/settings\\/notifications\\/pushover/,\n    },\n    {\n      text: 'Telegram',\n      content: (\n        <span className=\"flex items-center\">\n          <TelegramLogo className=\"mr-2 h-4\" />\n          Telegram\n        </span>\n      ),\n      route: '/settings/notifications/telegram',\n      regex: /\\/settings\\/notifications\\/telegram/,\n      hidden: !data?.telegramEnabled || !data?.telegramBotUsername,\n    },\n  ];\n\n  settingsRoutes.forEach((settingsRoute) => {\n    settingsRoute.route = router.asPath.includes('/profile')\n      ? `/profile${settingsRoute.route}`\n      : `/users/${user?.id}${settingsRoute.route}`;\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.notifications),\n          intl.formatMessage(globalMessages.usersettings),\n          user?.displayName,\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">\n          {intl.formatMessage(messages.notificationsettings)}\n        </h3>\n      </div>\n      <SettingsTabs tabType=\"button\" settingsRoutes={settingsRoutes} />\n      <div className=\"section\">{children}</div>\n    </>\n  );\n};\n\nexport default UserNotificationSettings;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserPasswordChange/index.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport SensitiveInput from '@app/components/Common/SensitiveInput';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Form, Formik } from 'formik';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\nimport * as Yup from 'yup';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserPasswordChange',\n  {\n    password: 'Password',\n    currentpassword: 'Current Password',\n    newpassword: 'New Password',\n    confirmpassword: 'Confirm Password',\n    toastSettingsSuccess: 'Password saved successfully!',\n    toastSettingsFailure: 'Something went wrong while saving the password.',\n    toastSettingsFailureVerifyCurrent:\n      'Something went wrong while saving the password. Was your current password entered correctly?',\n    validationCurrentPassword: 'You must provide your current password',\n    validationNewPassword: 'You must provide a new password',\n    validationNewPasswordLength:\n      'Password is too short; should be a minimum of 8 characters',\n    validationConfirmPassword: 'You must confirm the new password',\n    validationConfirmPasswordSame: 'Passwords must match',\n    noPasswordSet:\n      '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.\"',\n    noPasswordSetOwnAccount:\n      '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.',\n    nopermissionDescription:\n      \"You do not have permission to modify this user's password.\",\n  }\n);\n\nconst UserPasswordChange = () => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const router = useRouter();\n  const { user: currentUser } = useUser();\n  const { user, hasPermission } = useUser({ id: Number(router.query.userId) });\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<{ hasPassword: boolean }>(\n    user ? `/api/v1/user/${user?.id}/settings/password` : null\n  );\n\n  const PasswordChangeSchema = Yup.object().shape({\n    currentPassword: Yup.lazy(() =>\n      data?.hasPassword && currentUser?.id === user?.id\n        ? Yup.string().required(\n            intl.formatMessage(messages.validationCurrentPassword)\n          )\n        : Yup.mixed().optional()\n    ),\n    newPassword: Yup.string()\n      .required(intl.formatMessage(messages.validationNewPassword))\n      .min(8, intl.formatMessage(messages.validationNewPasswordLength)),\n    confirmPassword: Yup.string()\n      .required(intl.formatMessage(messages.validationConfirmPassword))\n      .oneOf(\n        [Yup.ref('newPassword'), null],\n        intl.formatMessage(messages.validationConfirmPasswordSame)\n      ),\n  });\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  if (\n    currentUser?.id !== user?.id &&\n    hasPermission(Permission.ADMIN) &&\n    currentUser?.id !== 1\n  ) {\n    return (\n      <>\n        <div className=\"mb-6\">\n          <h3 className=\"heading\">{intl.formatMessage(messages.password)}</h3>\n        </div>\n        <Alert\n          title={intl.formatMessage(messages.nopermissionDescription)}\n          type=\"error\"\n        />\n      </>\n    );\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.password),\n          intl.formatMessage(globalMessages.usersettings),\n          user?.displayName,\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">{intl.formatMessage(messages.password)}</h3>\n      </div>\n      <Formik\n        initialValues={{\n          currentPassword: '',\n          newPassword: '',\n          confirmPassword: '',\n        }}\n        validationSchema={PasswordChangeSchema}\n        enableReinitialize\n        onSubmit={async (values, { resetForm }) => {\n          try {\n            await axios.post(`/api/v1/user/${user?.id}/settings/password`, {\n              currentPassword: values.currentPassword,\n              newPassword: values.newPassword,\n              confirmPassword: values.confirmPassword,\n            });\n\n            addToast(intl.formatMessage(messages.toastSettingsSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            addToast(\n              intl.formatMessage(\n                data.hasPassword && user?.id === currentUser?.id\n                  ? messages.toastSettingsFailureVerifyCurrent\n                  : messages.toastSettingsFailure\n              ),\n              {\n                autoDismiss: true,\n                appearance: 'error',\n              }\n            );\n          } finally {\n            revalidate();\n            resetForm();\n          }\n        }}\n      >\n        {({ errors, touched, isSubmitting, isValid }) => {\n          return (\n            <Form className=\"section\">\n              {!data.hasPassword && (\n                <Alert\n                  type=\"warning\"\n                  title={intl.formatMessage(\n                    user?.id === currentUser?.id\n                      ? messages.noPasswordSetOwnAccount\n                      : messages.noPasswordSet\n                  )}\n                />\n              )}\n              {data.hasPassword && user?.id === currentUser?.id && (\n                <div className=\"form-row pb-6\">\n                  <label htmlFor=\"currentPassword\" className=\"text-label\">\n                    {intl.formatMessage(messages.currentpassword)}\n                  </label>\n                  <div className=\"form-input-area\">\n                    <div className=\"form-input-field\">\n                      <SensitiveInput\n                        as=\"field\"\n                        id=\"currentPassword\"\n                        name=\"currentPassword\"\n                        type=\"password\"\n                        autoComplete=\"current-password\"\n                      />\n                    </div>\n                    {errors.currentPassword &&\n                      touched.currentPassword &&\n                      typeof errors.currentPassword === 'string' && (\n                        <div className=\"error\">{errors.currentPassword}</div>\n                      )}\n                  </div>\n                </div>\n              )}\n              <div className=\"form-row\">\n                <label htmlFor=\"newPassword\" className=\"text-label\">\n                  {intl.formatMessage(messages.newpassword)}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <SensitiveInput\n                      as=\"field\"\n                      id=\"newPassword\"\n                      name=\"newPassword\"\n                      type=\"password\"\n                      autoComplete=\"new-password\"\n                    />\n                  </div>\n                  {errors.newPassword &&\n                    touched.newPassword &&\n                    typeof errors.newPassword === 'string' && (\n                      <div className=\"error\">{errors.newPassword}</div>\n                    )}\n                </div>\n              </div>\n              <div className=\"form-row\">\n                <label htmlFor=\"confirmPassword\" className=\"text-label\">\n                  {intl.formatMessage(messages.confirmpassword)}\n                </label>\n                <div className=\"form-input-area\">\n                  <div className=\"form-input-field\">\n                    <SensitiveInput\n                      as=\"field\"\n                      id=\"confirmPassword\"\n                      name=\"confirmPassword\"\n                      type=\"password\"\n                      autoComplete=\"new-password\"\n                    />\n                  </div>\n                  {errors.confirmPassword &&\n                    touched.confirmPassword &&\n                    typeof errors.confirmPassword === 'string' && (\n                      <div className=\"error\">{errors.confirmPassword}</div>\n                    )}\n                </div>\n              </div>\n              <div className=\"actions\">\n                <div className=\"flex justify-end\">\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"primary\"\n                      type=\"submit\"\n                      disabled={isSubmitting || !isValid}\n                    >\n                      <ArrowDownOnSquareIcon />\n                      <span>\n                        {isSubmitting\n                          ? intl.formatMessage(globalMessages.saving)\n                          : intl.formatMessage(globalMessages.save)}\n                      </span>\n                    </Button>\n                  </span>\n                </div>\n              </div>\n            </Form>\n          );\n        }}\n      </Formik>\n    </>\n  );\n};\n\nexport default UserPasswordChange;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/UserPermissions/index.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport Button from '@app/components/Common/Button';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport PermissionEdit from '@app/components/PermissionEdit';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';\nimport axios from 'axios';\nimport { Form, Formik } from 'formik';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWR from 'swr';\n\nconst messages = defineMessages(\n  'components.UserProfile.UserSettings.UserPermissions',\n  {\n    toastSettingsSuccess: 'Permissions saved successfully!',\n    toastSettingsFailure: 'Something went wrong while saving settings.',\n    permissions: 'Permissions',\n    unauthorizedDescription: 'You cannot modify your own permissions.',\n  }\n);\n\nconst UserPermissions = () => {\n  const intl = useIntl();\n  const { addToast } = useToasts();\n  const router = useRouter();\n  const { user: currentUser } = useUser();\n  const { user, revalidate: revalidateUser } = useUser({\n    id: Number(router.query.userId),\n  });\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<{ permissions?: number }>(\n    user ? `/api/v1/user/${user?.id}/settings/permissions` : null\n  );\n\n  if (!data && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!data) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  if (currentUser?.id !== 1 && currentUser?.id === user?.id) {\n    return (\n      <>\n        <div className=\"mb-6\">\n          <h3 className=\"heading\">\n            {intl.formatMessage(messages.permissions)}\n          </h3>\n        </div>\n        <Alert\n          title={intl.formatMessage(messages.unauthorizedDescription)}\n          type=\"error\"\n        />\n      </>\n    );\n  }\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(messages.permissions),\n          intl.formatMessage(globalMessages.usersettings),\n          user?.displayName,\n        ]}\n      />\n      <div className=\"mb-6\">\n        <h3 className=\"heading\">{intl.formatMessage(messages.permissions)}</h3>\n      </div>\n      <Formik\n        initialValues={{\n          currentPermissions: data?.permissions,\n        }}\n        enableReinitialize\n        onSubmit={async (values) => {\n          try {\n            await axios.post(`/api/v1/user/${user?.id}/settings/permissions`, {\n              permissions: values.currentPermissions ?? 0,\n            });\n\n            addToast(intl.formatMessage(messages.toastSettingsSuccess), {\n              autoDismiss: true,\n              appearance: 'success',\n            });\n          } catch {\n            addToast(intl.formatMessage(messages.toastSettingsFailure), {\n              autoDismiss: true,\n              appearance: 'error',\n            });\n          } finally {\n            revalidate();\n            revalidateUser();\n          }\n        }}\n      >\n        {({ isSubmitting, setFieldValue, values }) => {\n          return (\n            <Form className=\"section\">\n              <div className=\"max-w-3xl\">\n                <PermissionEdit\n                  actingUser={currentUser}\n                  currentUser={user}\n                  currentPermission={values.currentPermissions ?? 0}\n                  onUpdate={(newPermission) =>\n                    setFieldValue('currentPermissions', newPermission)\n                  }\n                />\n              </div>\n              <div className=\"actions\">\n                <div className=\"flex justify-end\">\n                  <span className=\"ml-3 inline-flex rounded-md shadow-sm\">\n                    <Button\n                      buttonType=\"primary\"\n                      type=\"submit\"\n                      disabled={isSubmitting}\n                    >\n                      <ArrowDownOnSquareIcon />\n                      <span>\n                        {isSubmitting\n                          ? intl.formatMessage(globalMessages.saving)\n                          : intl.formatMessage(globalMessages.save)}\n                      </span>\n                    </Button>\n                  </span>\n                </div>\n              </div>\n            </Form>\n          );\n        }}\n      </Formik>\n    </>\n  );\n};\n\nexport default UserPermissions;\n"
  },
  {
    "path": "src/components/UserProfile/UserSettings/index.tsx",
    "content": "import Alert from '@app/components/Common/Alert';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport type { SettingsRoute } from '@app/components/Common/SettingsTabs';\nimport SettingsTabs from '@app/components/Common/SettingsTabs';\nimport ProfileHeader from '@app/components/UserProfile/ProfileHeader';\nimport useSettings from '@app/hooks/useSettings';\nimport { useUser } from '@app/hooks/useUser';\nimport globalMessages from '@app/i18n/globalMessages';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';\nimport { hasPermission, Permission } from '@server/lib/permissions';\nimport { useRouter } from 'next/router';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.UserProfile.UserSettings', {\n  menuGeneralSettings: 'General',\n  menuChangePass: 'Password',\n  menuLinkedAccounts: 'Linked Accounts',\n  menuNotifications: 'Notifications',\n  menuPermissions: 'Permissions',\n  unauthorizedDescription:\n    \"You do not have permission to modify this user's settings.\",\n});\n\ntype UserSettingsProps = {\n  children: React.ReactNode;\n};\n\nconst UserSettings = ({ children }: UserSettingsProps) => {\n  const router = useRouter();\n  const settings = useSettings();\n  const { user: currentUser } = useUser();\n  const { user, error } = useUser({ id: Number(router.query.userId) });\n  const intl = useIntl();\n  const { data } = useSWR<UserSettingsNotificationsResponse>(\n    user ? `/api/v1/user/${user?.id}/settings/notifications` : null\n  );\n\n  if (!user && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!user) {\n    return <ErrorPage statusCode={500} />;\n  }\n\n  const settingsRoutes: SettingsRoute[] = [\n    {\n      text: intl.formatMessage(messages.menuGeneralSettings),\n      route: '/settings/main',\n      regex: /\\/settings(\\/main)?$/,\n    },\n    {\n      text: intl.formatMessage(messages.menuChangePass),\n      route: '/settings/password',\n      regex: /\\/settings\\/password/,\n      hidden:\n        (!settings.currentSettings.localLogin &&\n          !hasPermission(Permission.ADMIN, currentUser?.permissions ?? 0)) ||\n        (currentUser?.id !== 1 &&\n          currentUser?.id !== user?.id &&\n          hasPermission(Permission.ADMIN, user?.permissions ?? 0)),\n    },\n    {\n      text: intl.formatMessage(messages.menuLinkedAccounts),\n      route: '/settings/linked-accounts',\n      regex: /\\/settings\\/linked-accounts/,\n    },\n    {\n      text: intl.formatMessage(messages.menuNotifications),\n      route: data?.emailEnabled\n        ? '/settings/notifications/email'\n        : data?.webPushEnabled\n          ? '/settings/notifications/webpush'\n          : data?.discordEnabled\n            ? '/settings/notifications/discord'\n            : '/settings/notifications/pushbullet',\n      regex: /\\/settings\\/notifications/,\n    },\n    {\n      text: intl.formatMessage(messages.menuPermissions),\n      route: '/settings/permissions',\n      regex: /\\/settings\\/permissions/,\n      requiredPermission: Permission.MANAGE_USERS,\n      hidden: currentUser?.id !== 1 && currentUser?.id === user.id,\n    },\n  ];\n\n  if (currentUser?.id !== 1 && user.id === 1) {\n    return (\n      <>\n        <PageTitle\n          title={[\n            intl.formatMessage(globalMessages.usersettings),\n            user.displayName,\n          ]}\n        />\n        <ProfileHeader user={user} isSettingsPage />\n        <div className=\"mt-6\">\n          <Alert\n            title={intl.formatMessage(messages.unauthorizedDescription)}\n            type=\"error\"\n          />\n        </div>\n      </>\n    );\n  }\n\n  settingsRoutes.forEach((settingsRoute) => {\n    settingsRoute.route = router.asPath.includes('/profile')\n      ? `/profile${settingsRoute.route}`\n      : `/users/${user.id}${settingsRoute.route}`;\n  });\n\n  return (\n    <>\n      <PageTitle\n        title={[\n          intl.formatMessage(globalMessages.usersettings),\n          user.displayName,\n        ]}\n      />\n      <ProfileHeader user={user} isSettingsPage />\n      <div className=\"mt-6\">\n        <SettingsTabs settingsRoutes={settingsRoutes} />\n      </div>\n      <div className=\"mt-10 text-white\">{children}</div>\n    </>\n  );\n};\n\nexport default UserSettings;\n"
  },
  {
    "path": "src/components/UserProfile/index.tsx",
    "content": "import ImageFader from '@app/components/Common/ImageFader';\nimport LoadingSpinner from '@app/components/Common/LoadingSpinner';\nimport PageTitle from '@app/components/Common/PageTitle';\nimport ProgressCircle from '@app/components/Common/ProgressCircle';\nimport RequestCard from '@app/components/RequestCard';\nimport Slider from '@app/components/Slider';\nimport TmdbTitleCard from '@app/components/TitleCard/TmdbTitleCard';\nimport ProfileHeader from '@app/components/UserProfile/ProfileHeader';\nimport { Permission, UserType, useUser } from '@app/hooks/useUser';\nimport ErrorPage from '@app/pages/_error';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowRightCircleIcon } from '@heroicons/react/24/outline';\nimport type { WatchlistResponse } from '@server/interfaces/api/discoverInterfaces';\nimport type {\n  QuotaResponse,\n  UserRequestsResponse,\n  UserWatchDataResponse,\n} from '@server/interfaces/api/userInterfaces';\nimport type { MovieDetails } from '@server/models/Movie';\nimport type { TvDetails } from '@server/models/Tv';\nimport Link from 'next/link';\nimport { useRouter } from 'next/router';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport useSWR from 'swr';\n\nconst messages = defineMessages('components.UserProfile', {\n  recentrequests: 'Recent Requests',\n  limit: '{remaining} of {limit}',\n  requestsperdays: '{limit} remaining',\n  unlimited: 'Unlimited',\n  totalrequests: 'Total Requests',\n  pastdays: '{type} (past {days} days)',\n  movierequests: 'Movie Requests',\n  seriesrequest: 'Series Requests',\n  recentlywatched: 'Recently Watched',\n  plexwatchlist: 'Plex Watchlist',\n  localWatchlist: \"{username}'s Watchlist\",\n  emptywatchlist:\n    'Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.',\n});\n\ntype MediaTitle = MovieDetails | TvDetails;\n\nconst UserProfile = () => {\n  const intl = useIntl();\n  const router = useRouter();\n  const { user, error } = useUser({\n    id: Number(router.query.userId),\n  });\n  const { user: currentUser, hasPermission: currentHasPermission } = useUser();\n  const [availableTitles, setAvailableTitles] = useState<\n    Record<number, MediaTitle>\n  >({});\n\n  const { data: requests, error: requestError } = useSWR<UserRequestsResponse>(\n    user &&\n      (user.id === currentUser?.id ||\n        currentHasPermission(\n          [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n          { type: 'or' }\n        ))\n      ? `/api/v1/user/${user?.id}/requests?take=10&skip=0`\n      : null\n  );\n  const { data: quota } = useSWR<QuotaResponse>(\n    user &&\n      (user.id === currentUser?.id ||\n        currentHasPermission(\n          [Permission.MANAGE_USERS, Permission.MANAGE_REQUESTS],\n          { type: 'and' }\n        ))\n      ? `/api/v1/user/${user.id}/quota`\n      : null\n  );\n  const { data: watchData, error: watchDataError } =\n    useSWR<UserWatchDataResponse>(\n      user?.userType === UserType.PLEX &&\n        (user.id === currentUser?.id || currentHasPermission(Permission.ADMIN))\n        ? `/api/v1/user/${user.id}/watch_data`\n        : null\n    );\n\n  const { data: watchlistItems, error: watchlistError } =\n    useSWR<WatchlistResponse>(\n      user?.id === currentUser?.id ||\n        currentHasPermission(\n          [Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],\n          {\n            type: 'or',\n          }\n        )\n        ? `/api/v1/user/${user?.id}/watchlist`\n        : null,\n      {\n        revalidateOnMount: true,\n      }\n    );\n\n  const updateAvailableTitles = useCallback(\n    (requestId: number, mediaTitle: MediaTitle) => {\n      setAvailableTitles((titles) => ({\n        ...titles,\n        [requestId]: mediaTitle,\n      }));\n    },\n    []\n  );\n\n  useEffect(() => {\n    setAvailableTitles({});\n  }, [user?.id]);\n\n  if (!user && !error) {\n    return <LoadingSpinner />;\n  }\n\n  if (!user) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  const watchlistSliderTitle = intl.formatMessage(\n    user.userType === UserType.PLEX\n      ? messages.plexwatchlist\n      : messages.localWatchlist,\n    { username: user.displayName }\n  );\n\n  return (\n    <>\n      <PageTitle title={user.displayName} />\n      {Object.keys(availableTitles).length > 0 && (\n        <div className=\"absolute -top-16 left-0 right-0 z-0 h-96\">\n          <ImageFader\n            key={user.id}\n            isDarker\n            backgroundImages={Object.values(availableTitles)\n              .filter((media) => media.backdropPath)\n              .map(\n                (media) =>\n                  `https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${media.backdropPath}`\n              )\n              .slice(0, 6)}\n          />\n        </div>\n      )}\n      <ProfileHeader user={user} />\n      {quota &&\n        (user.id === currentUser?.id ||\n          currentHasPermission(\n            [Permission.MANAGE_USERS, Permission.MANAGE_REQUESTS],\n            { type: 'and' }\n          )) && (\n          <div className=\"relative z-40\">\n            <dl className=\"mt-5 grid grid-cols-1 gap-5 lg:grid-cols-3\">\n              <div className=\"overflow-hidden rounded-lg bg-gray-800/50 px-4 py-5 shadow ring-1 ring-gray-700 sm:p-6\">\n                <dt className=\"truncate text-sm font-bold text-gray-300\">\n                  {intl.formatMessage(messages.totalrequests)}\n                </dt>\n                <dd className=\"mt-1 text-3xl font-semibold text-white\">\n                  <Link\n                    href={\n                      currentHasPermission(\n                        [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n                        { type: 'or' }\n                      )\n                        ? `/users/${user?.id}/requests?filter=all`\n                        : '/requests'\n                    }\n                  >\n                    {intl.formatNumber(user.requestCount)}\n                  </Link>\n                </dd>\n              </div>\n              <div\n                className={`overflow-hidden rounded-lg bg-gray-800/50 px-4 py-5 shadow ring-1 ${\n                  quota.movie.restricted\n                    ? 'bg-gradient-to-t from-red-900 to-transparent ring-red-500'\n                    : 'ring-gray-700'\n                } sm:p-6`}\n              >\n                <dt\n                  className={`truncate text-sm font-bold ${\n                    quota.movie.restricted ? 'text-red-500' : 'text-gray-300'\n                  }`}\n                >\n                  {quota.movie.limit\n                    ? intl.formatMessage(messages.pastdays, {\n                        type: intl.formatMessage(messages.movierequests),\n                        days: quota?.movie.days,\n                      })\n                    : intl.formatMessage(messages.movierequests)}\n                </dt>\n                <dd\n                  className={`mt-1 flex items-center text-sm ${\n                    quota.movie.restricted ? 'text-red-500' : 'text-white'\n                  }`}\n                >\n                  {quota.movie.limit ? (\n                    <>\n                      <ProgressCircle\n                        progress={Math.round(\n                          ((quota?.movie.remaining ?? 0) /\n                            (quota?.movie.limit ?? 1)) *\n                            100\n                        )}\n                        useHeatLevel\n                        className=\"mr-2 h-8 w-8\"\n                      />\n                      <div>\n                        {intl.formatMessage(messages.requestsperdays, {\n                          limit: (\n                            <span className=\"text-3xl font-semibold\">\n                              {intl.formatMessage(messages.limit, {\n                                remaining: quota.movie.remaining,\n                                limit: quota.movie.limit,\n                              })}\n                            </span>\n                          ),\n                        })}\n                      </div>\n                    </>\n                  ) : (\n                    <span className=\"text-3xl font-semibold\">\n                      {intl.formatMessage(messages.unlimited)}\n                    </span>\n                  )}\n                </dd>\n              </div>\n              <div\n                className={`overflow-hidden rounded-lg bg-gray-800/50 px-4 py-5 shadow ring-1 ${\n                  quota.tv.restricted\n                    ? 'bg-gradient-to-t from-red-900 to-transparent ring-red-500'\n                    : 'ring-gray-700'\n                } sm:p-6`}\n              >\n                <dt\n                  className={`truncate text-sm font-bold ${\n                    quota.tv.restricted ? 'text-red-500' : 'text-gray-300'\n                  }`}\n                >\n                  {quota.tv.limit\n                    ? intl.formatMessage(messages.pastdays, {\n                        type: intl.formatMessage(messages.seriesrequest),\n                        days: quota?.tv.days,\n                      })\n                    : intl.formatMessage(messages.seriesrequest)}\n                </dt>\n                <dd\n                  className={`mt-1 flex items-center text-sm ${\n                    quota.tv.restricted ? 'text-red-500' : 'text-white'\n                  }`}\n                >\n                  {quota.tv.limit ? (\n                    <>\n                      <ProgressCircle\n                        progress={Math.round(\n                          ((quota?.tv.remaining ?? 0) /\n                            (quota?.tv.limit ?? 1)) *\n                            100\n                        )}\n                        useHeatLevel\n                        className=\"mr-2 h-8 w-8\"\n                      />\n                      <div>\n                        {intl.formatMessage(messages.requestsperdays, {\n                          limit: (\n                            <span className=\"text-3xl font-semibold\">\n                              {intl.formatMessage(messages.limit, {\n                                remaining: quota.tv.remaining,\n                                limit: quota.tv.limit,\n                              })}\n                            </span>\n                          ),\n                        })}\n                      </div>\n                    </>\n                  ) : (\n                    <span className=\"text-3xl font-semibold\">\n                      {intl.formatMessage(messages.unlimited)}\n                    </span>\n                  )}\n                </dd>\n              </div>\n            </dl>\n          </div>\n        )}\n      {(user.id === currentUser?.id ||\n        currentHasPermission(\n          [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n          { type: 'or' }\n        )) &&\n        (!requests || !!requests.results.length) &&\n        !requestError && (\n          <>\n            <div className=\"slider-header\">\n              <Link\n                href={\n                  currentHasPermission(\n                    [Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],\n                    { type: 'or' }\n                  )\n                    ? `/users/${user?.id}/requests?filter=all`\n                    : '/requests'\n                }\n                className=\"slider-title\"\n              >\n                <span>{intl.formatMessage(messages.recentrequests)}</span>\n                <ArrowRightCircleIcon />\n              </Link>\n            </div>\n            <Slider\n              sliderKey=\"requests\"\n              isLoading={!requests}\n              items={(requests?.results ?? []).map((request) => (\n                <RequestCard\n                  key={`request-slider-item-${request.id}`}\n                  request={request}\n                  onTitleData={updateAvailableTitles}\n                />\n              ))}\n              placeholder={<RequestCard.Placeholder />}\n            />\n          </>\n        )}\n      {(user.id === currentUser?.id ||\n        currentHasPermission(\n          [Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW],\n          { type: 'or' }\n        )) &&\n        (!watchlistItems ||\n          !!watchlistItems.results.length ||\n          (user.id === currentUser?.id &&\n            (user.settings?.watchlistSyncMovies ||\n              user.settings?.watchlistSyncTv))) &&\n        !watchlistError && (\n          <>\n            <div className=\"slider-header\">\n              <Link\n                href={\n                  user.id === currentUser?.id\n                    ? '/profile/watchlist'\n                    : `/users/${user.id}/watchlist`\n                }\n                className=\"slider-title\"\n              >\n                <span>{watchlistSliderTitle}</span>\n                <ArrowRightCircleIcon />\n              </Link>\n            </div>\n            <Slider\n              sliderKey=\"watchlist\"\n              isLoading={!watchlistItems}\n              isEmpty={!!watchlistItems && watchlistItems.results.length === 0}\n              emptyMessage={intl.formatMessage(messages.emptywatchlist, {\n                PlexWatchlistSupportLink: (msg: React.ReactNode) => (\n                  <a\n                    href=\"https://support.plex.tv/articles/universal-watchlist/\"\n                    className=\"text-white transition duration-300 hover:underline\"\n                    target=\"_blank\"\n                    rel=\"noreferrer\"\n                  >\n                    {msg}\n                  </a>\n                ),\n              })}\n              items={watchlistItems?.results.map((item) => (\n                <TmdbTitleCard\n                  id={item.tmdbId}\n                  key={`watchlist-slider-item-${item.ratingKey}`}\n                  tmdbId={item.tmdbId}\n                  type={item.mediaType}\n                />\n              ))}\n            />\n          </>\n        )}\n      {user.userType === UserType.PLEX &&\n        (user.id === currentUser?.id ||\n          currentHasPermission(Permission.ADMIN)) &&\n        (!watchData || !!watchData.recentlyWatched?.length) &&\n        !watchDataError && (\n          <>\n            <div className=\"slider-header\">\n              <div className=\"slider-title\">\n                <span>{intl.formatMessage(messages.recentlywatched)}</span>\n              </div>\n            </div>\n            <Slider\n              sliderKey=\"media\"\n              isLoading={!watchData}\n              items={watchData?.recentlyWatched?.map((item) => (\n                <TmdbTitleCard\n                  key={`media-slider-item-${item.id}`}\n                  id={item.id}\n                  tmdbId={item.tmdbId}\n                  tvdbId={item.tvdbId}\n                  type={item.mediaType}\n                />\n              ))}\n            />\n          </>\n        )}\n    </>\n  );\n};\n\nexport default UserProfile;\n"
  },
  {
    "path": "src/context/InteractionContext.tsx",
    "content": "import useInteraction from '@app/hooks/useInteraction';\nimport React from 'react';\n\ninterface InteractionContextProps {\n  isTouch?: boolean;\n  children?: React.ReactNode;\n}\n\nexport const InteractionContext = React.createContext<InteractionContextProps>({\n  isTouch: false,\n});\n\nexport const InteractionProvider = ({ children }: InteractionContextProps) => {\n  const isTouch = useInteraction();\n\n  return (\n    <InteractionContext.Provider value={{ isTouch }}>\n      {children}\n    </InteractionContext.Provider>\n  );\n};\n"
  },
  {
    "path": "src/context/LanguageContext.tsx",
    "content": "import { type AvailableLocale } from '@server/types/languages';\nimport React from 'react';\n\ntype AvailableLanguageObject = Record<\n  string,\n  { code: AvailableLocale; display: string }\n>;\n\nexport const availableLanguages: AvailableLanguageObject = {\n  bg: {\n    code: 'bg',\n    display: 'Bulgarian',\n  },\n  ca: {\n    code: 'ca',\n    display: 'Català',\n  },\n  cs: {\n    code: 'cs',\n    display: 'Čeština',\n  },\n  da: {\n    code: 'da',\n    display: 'Dansk',\n  },\n  de: {\n    code: 'de',\n    display: 'Deutsch',\n  },\n  en: {\n    code: 'en',\n    display: 'English',\n  },\n  es: {\n    code: 'es',\n    display: 'Español',\n  },\n  'es-MX': {\n    code: 'es-MX',\n    display: 'Español (Latinoamérica)',\n  },\n  fi: {\n    code: 'fi',\n    display: 'Finnish',\n  },\n  fr: {\n    code: 'fr',\n    display: 'Français',\n  },\n  he: {\n    code: 'he',\n    display: 'Hebrew',\n  },\n  hi: {\n    code: 'hi',\n    display: 'Hindi',\n  },\n  hr: {\n    code: 'hr',\n    display: 'Hrvatski',\n  },\n  it: {\n    code: 'it',\n    display: 'Italiano',\n  },\n  lb: {\n    code: 'lb',\n    display: 'Lëtzebuergesch',\n  },\n  lt: {\n    code: 'lt',\n    display: 'Lietuvių',\n  },\n  hu: {\n    code: 'hu',\n    display: 'Magyar',\n  },\n  nl: {\n    code: 'nl',\n    display: 'Nederlands',\n  },\n  'nb-NO': {\n    code: 'nb-NO',\n    display: 'Norsk Bokmål',\n  },\n  pl: {\n    code: 'pl',\n    display: 'Polski',\n  },\n  'pt-BR': {\n    code: 'pt-BR',\n    display: 'Português (Brasil)',\n  },\n  'pt-PT': {\n    code: 'pt-PT',\n    display: 'Português (Portugal)',\n  },\n  sq: {\n    code: 'sq',\n    display: 'Shqip',\n  },\n  sv: {\n    code: 'sv',\n    display: 'Svenska',\n  },\n  el: {\n    code: 'el',\n    display: 'Ελληνικά',\n  },\n  ro: {\n    code: 'ro',\n    display: 'Romanian',\n  },\n  ru: {\n    code: 'ru',\n    display: 'pусский',\n  },\n  sr: {\n    code: 'sr',\n    display: 'српски језик',\n  },\n  tr: {\n    code: 'tr',\n    display: 'Türkçe',\n  },\n  ar: {\n    code: 'ar',\n    display: 'العربية',\n  },\n  ja: {\n    code: 'ja',\n    display: '日本語',\n  },\n  ko: {\n    code: 'ko',\n    display: '한국어',\n  },\n  uk: {\n    code: 'uk',\n    display: 'українська мова',\n  },\n  vi: {\n    code: 'vi',\n    display: 'Tiếng Việt',\n  },\n  'zh-TW': {\n    code: 'zh-TW',\n    display: '繁體中文',\n  },\n  'zh-CN': {\n    code: 'zh-CN',\n    display: '简体中文',\n  },\n};\n\nexport interface LanguageContextProps {\n  locale: AvailableLocale;\n  children: (locale: string) => React.ReactNode;\n  setLocale?: React.Dispatch<React.SetStateAction<AvailableLocale>>;\n}\n\nexport const LanguageContext = React.createContext<\n  Omit<LanguageContextProps, 'children'>\n>({\n  locale: 'en',\n});\n"
  },
  {
    "path": "src/context/SettingsContext.tsx",
    "content": "import { MediaServerType } from '@server/constants/server';\nimport type { PublicSettingsResponse } from '@server/interfaces/api/settingsInterfaces';\nimport React from 'react';\nimport useSWR from 'swr';\n\nexport interface SettingsContextProps {\n  currentSettings: PublicSettingsResponse;\n  children?: React.ReactNode;\n}\n\nconst defaultSettings = {\n  initialized: false,\n  applicationTitle: 'Seerr',\n  applicationUrl: '',\n  hideAvailable: false,\n  hideBlocklisted: false,\n  localLogin: true,\n  mediaServerLogin: true,\n  movie4kEnabled: false,\n  series4kEnabled: false,\n  discoverRegion: '',\n  streamingRegion: '',\n  originalLanguage: '',\n  mediaServerType: MediaServerType.NOT_CONFIGURED,\n  partialRequestsEnabled: true,\n  enableSpecialEpisodes: false,\n  cacheImages: false,\n  vapidPublic: '',\n  enablePushRegistration: false,\n  locale: 'en',\n  emailEnabled: false,\n  newPlexLogin: true,\n  youtubeUrl: '',\n};\n\nexport const SettingsContext = React.createContext<SettingsContextProps>({\n  currentSettings: defaultSettings,\n});\n\nexport const SettingsProvider = ({\n  children,\n  currentSettings,\n}: SettingsContextProps) => {\n  const { data, error } = useSWR<PublicSettingsResponse>(\n    '/api/v1/settings/public',\n    { fallbackData: currentSettings }\n  );\n\n  let newSettings = defaultSettings;\n\n  if (data && !error) {\n    newSettings = data;\n  }\n\n  return (\n    <SettingsContext.Provider value={{ currentSettings: newSettings }}>\n      {children}\n    </SettingsContext.Provider>\n  );\n};\n"
  },
  {
    "path": "src/context/UserContext.tsx",
    "content": "import type { User } from '@app/hooks/useUser';\nimport { useUser } from '@app/hooks/useUser';\nimport { useRouter } from 'next/dist/client/router';\nimport { useEffect, useRef } from 'react';\n\ninterface UserContextProps {\n  initialUser: User;\n  children?: React.ReactNode;\n}\n\n/**\n * This UserContext serves the purpose of just preparing the useUser hooks\n * cache on server side render. It also will handle redirecting the user to\n * the login page if their session ever becomes invalid.\n */\nexport const UserContext = ({ initialUser, children }: UserContextProps) => {\n  const { user, error, revalidate } = useUser({ initialData: initialUser });\n  const router = useRouter();\n  const routing = useRef(false);\n\n  useEffect(() => {\n    revalidate();\n  }, [router.pathname, revalidate]);\n\n  useEffect(() => {\n    if (\n      !router.pathname.match(/(setup|login|resetpassword)/) &&\n      (!user || error) &&\n      !routing.current\n    ) {\n      routing.current = true;\n      location.href = '/login';\n    }\n  }, [router, user, error]);\n\n  return <>{children}</>;\n};\n"
  },
  {
    "path": "src/hooks/useClickOutside.ts",
    "content": "import { useEffect } from 'react';\n\n/**\n * useClickOutside\n *\n * Simple hook to add an event listener to the body and allow a callback to\n * be triggered when clicking outside of the target ref\n *\n * @param ref Any HTML Element ref\n * @param callback Callback triggered when clicking outside of ref element\n */\nconst useClickOutside = (\n  ref: React.RefObject<HTMLElement>,\n  callback: (e: MouseEvent) => void\n): void => {\n  useEffect(() => {\n    const handleBodyClick = (e: MouseEvent) => {\n      if (ref.current && !ref.current.contains(e.target as Node)) {\n        callback(e);\n      }\n    };\n    document.body.addEventListener('click', handleBodyClick, { capture: true });\n\n    return () => {\n      document.body.removeEventListener('click', handleBodyClick);\n    };\n  }, [ref, callback]);\n};\n\nexport default useClickOutside;\n"
  },
  {
    "path": "src/hooks/useDebouncedState.ts",
    "content": "import type { Dispatch, SetStateAction } from 'react';\nimport { useEffect, useState } from 'react';\n\n/**\n * A hook to help with debouncing state\n *\n * This hook basically acts the same as useState except it is also\n * returning a deobuncedValue that can be used for things like\n * debouncing input into a search field\n *\n * @param initialValue Initial state value\n * @param debounceTime Debounce time in ms\n */\nconst useDebouncedState = <S>(\n  initialValue: S,\n  debounceTime = 300\n): [S, S, Dispatch<SetStateAction<S>>] => {\n  const [value, setValue] = useState(initialValue);\n  const [finalValue, setFinalValue] = useState(initialValue);\n\n  useEffect(() => {\n    const timeout = setTimeout(() => {\n      setFinalValue(value);\n    }, debounceTime);\n\n    return () => {\n      clearTimeout(timeout);\n    };\n  }, [value, debounceTime]);\n\n  return [value, finalValue, setValue];\n};\n\nexport default useDebouncedState;\n"
  },
  {
    "path": "src/hooks/useDeepLinks.ts",
    "content": "import useSettings from '@app/hooks/useSettings';\nimport { MediaServerType } from '@server/constants/server';\nimport { useEffect, useState } from 'react';\n\ninterface useDeepLinksProps {\n  mediaUrl?: string;\n  mediaUrl4k?: string;\n  iOSPlexUrl?: string;\n  iOSPlexUrl4k?: string;\n}\n\nconst useDeepLinks = ({\n  mediaUrl,\n  mediaUrl4k,\n  iOSPlexUrl,\n  iOSPlexUrl4k,\n}: useDeepLinksProps) => {\n  const [returnedMediaUrl, setReturnedMediaUrl] = useState(mediaUrl);\n  const [returnedMediaUrl4k, setReturnedMediaUrl4k] = useState(mediaUrl4k);\n  const settings = useSettings();\n\n  useEffect(() => {\n    if (\n      settings.currentSettings.mediaServerType === MediaServerType.PLEX &&\n      (/iPad|iPhone|iPod/.test(navigator.userAgent) ||\n        (navigator.userAgent.includes('Mac') && navigator.maxTouchPoints > 1))\n    ) {\n      setReturnedMediaUrl(iOSPlexUrl);\n      setReturnedMediaUrl4k(iOSPlexUrl4k);\n    } else {\n      setReturnedMediaUrl(mediaUrl);\n      setReturnedMediaUrl4k(mediaUrl4k);\n    }\n  }, [\n    iOSPlexUrl,\n    iOSPlexUrl4k,\n    mediaUrl,\n    mediaUrl4k,\n    settings.currentSettings.mediaServerType,\n  ]);\n\n  return { mediaUrl: returnedMediaUrl, mediaUrl4k: returnedMediaUrl4k };\n};\n\nexport default useDeepLinks;\n"
  },
  {
    "path": "src/hooks/useDiscover.ts",
    "content": "import globalMessages from '@app/i18n/globalMessages';\nimport { MediaStatus } from '@server/constants/media';\nimport { useEffect } from 'react';\nimport { useIntl } from 'react-intl';\nimport { useToasts } from 'react-toast-notifications';\nimport useSWRInfinite from 'swr/infinite';\nimport useSettings from './useSettings';\nimport { Permission, useUser } from './useUser';\n\nexport interface BaseSearchResult<T> {\n  page: number;\n  totalResults: number;\n  totalPages: number;\n  results: T[];\n}\n\ninterface BaseMedia {\n  id: number;\n  mediaType: string;\n  mediaInfo?: {\n    status: MediaStatus;\n  };\n}\n\ninterface DiscoverResult<T, S> {\n  isLoadingInitialData: boolean;\n  isLoadingMore: boolean;\n  fetchMore: () => void;\n  isEmpty: boolean;\n  isReachingEnd: boolean;\n  error: unknown;\n  titles: T[];\n  firstResultData?: BaseSearchResult<T> & S;\n  mutate?: () => void;\n}\n\nconst extraEncodes: [RegExp, string][] = [\n  [/\\(/g, '%28'],\n  [/\\)/g, '%29'],\n  [/!/g, '%21'],\n  [/\\*/g, '%2A'],\n];\n\nexport const encodeURIExtraParams = (string: string): string => {\n  let finalString = encodeURIComponent(string);\n\n  extraEncodes.forEach((encode) => {\n    finalString = finalString.replace(encode[0], encode[1]);\n  });\n\n  return finalString;\n};\n\nconst useDiscover = <\n  T extends BaseMedia,\n  S = Record<string, never>,\n  O = Record<string, unknown>,\n>(\n  endpoint: string,\n  options?: O,\n  { hideAvailable = true, hideBlocklisted = true } = {}\n): DiscoverResult<T, S> => {\n  const settings = useSettings();\n  const { hasPermission } = useUser();\n  const { addToast } = useToasts();\n  const intl = useIntl();\n  const { data, error, size, setSize, isValidating, mutate } = useSWRInfinite<\n    BaseSearchResult<T> & S\n  >(\n    (pageIndex: number, previousPageData) => {\n      if (previousPageData && pageIndex + 1 > previousPageData.totalPages) {\n        return null;\n      }\n\n      const params: Record<string, unknown> = {\n        page: pageIndex + 1,\n        ...options,\n      };\n\n      const finalQueryString = Object.keys(params)\n        .map(\n          (paramKey) =>\n            `${paramKey}=${encodeURIExtraParams(params[paramKey] as string)}`\n        )\n        .join('&');\n\n      return `${endpoint}?${finalQueryString}`;\n    },\n    {\n      initialSize: 3,\n      revalidateFirstPage: false,\n      dedupingInterval: 30000,\n      revalidateOnFocus: false,\n    }\n  );\n\n  const resultIds: Set<number> = new Set<number>();\n\n  const isLoadingInitialData = !data && !error;\n  const isLoadingMore =\n    isLoadingInitialData ||\n    (size > 0 &&\n      !!data &&\n      typeof data[size - 1] === 'undefined' &&\n      isValidating);\n\n  const fetchMore = () => {\n    setSize(size + 1);\n  };\n\n  let titles = (data ?? []).reduce((a, v) => {\n    const results: T[] = [];\n\n    for (const result of v.results) {\n      if (!resultIds.has(result.id)) {\n        resultIds.add(result.id);\n        results.push(result);\n      }\n    }\n\n    return [...a, ...results];\n  }, [] as T[]);\n\n  if (settings.currentSettings.hideAvailable && hideAvailable) {\n    titles = titles.filter(\n      (i) =>\n        (i.mediaType === 'movie' || i.mediaType === 'tv') &&\n        i.mediaInfo?.status !== MediaStatus.AVAILABLE &&\n        i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE\n    );\n  }\n\n  if (\n    settings.currentSettings.hideBlocklisted &&\n    hideBlocklisted &&\n    hasPermission(Permission.MANAGE_BLOCKLIST)\n  ) {\n    titles = titles.filter(\n      (i) =>\n        (i.mediaType === 'movie' || i.mediaType === 'tv') &&\n        i.mediaInfo?.status !== MediaStatus.BLOCKLISTED\n    );\n  }\n\n  const isEmpty = !isLoadingInitialData && titles?.length === 0;\n  const isReachingEnd =\n    isEmpty ||\n    (!!data && (data[data?.length - 1]?.results.length ?? 0) < 20) ||\n    (!!data && (data[data?.length - 1]?.totalResults ?? 0) <= size * 20) ||\n    (!!data && (data[data?.length - 1]?.totalResults ?? 0) < 41);\n\n  useEffect(() => {\n    if (error && titles.length) {\n      addToast(intl.formatMessage(globalMessages.error), {\n        appearance: 'error',\n        autoDismiss: true,\n      });\n      console.error('Error while fetching discover titles:', error);\n    }\n  }, [data, error, addToast, intl, titles.length]);\n\n  return {\n    isLoadingInitialData,\n    isLoadingMore,\n    fetchMore,\n    isEmpty,\n    isReachingEnd,\n    error: error && titles.length ? null : error,\n    titles,\n    firstResultData: data?.[0],\n    mutate,\n  };\n};\n\nexport default useDiscover;\n"
  },
  {
    "path": "src/hooks/useInteraction.ts",
    "content": "import { useEffect, useState } from 'react';\n\nexport const INTERACTION_TYPE = {\n  MOUSE: 'mouse',\n  PEN: 'pen',\n  TOUCH: 'touch',\n};\n\nconst UPDATE_INTERVAL = 1000; // Throttle updates to the type to prevent flip flopping\n\nconst useInteraction = (): boolean => {\n  const [isTouch, setIsTouch] = useState(false);\n\n  useEffect(() => {\n    const hasTapEvent = 'ontouchstart' in window;\n    setIsTouch(hasTapEvent);\n\n    let localTouch = hasTapEvent;\n    let lastTouchUpdate = Date.now();\n\n    const shouldUpdate = (): boolean =>\n      lastTouchUpdate + UPDATE_INTERVAL < Date.now();\n\n    const onMouseMove = (): void => {\n      if (localTouch && shouldUpdate()) {\n        setTimeout(() => {\n          if (shouldUpdate()) {\n            setIsTouch(false);\n            localTouch = false;\n          }\n        }, UPDATE_INTERVAL);\n      }\n    };\n\n    const onTouchStart = (): void => {\n      lastTouchUpdate = Date.now();\n\n      if (!localTouch) {\n        setIsTouch(true);\n        localTouch = true;\n      }\n    };\n\n    const onPointerMove = (e: PointerEvent): void => {\n      const { pointerType } = e;\n\n      switch (pointerType) {\n        case INTERACTION_TYPE.TOUCH:\n        case INTERACTION_TYPE.PEN:\n          return onTouchStart();\n        default:\n          return onMouseMove();\n      }\n    };\n\n    if (hasTapEvent) {\n      window.addEventListener('mousemove', onMouseMove);\n      window.addEventListener('touchstart', onTouchStart);\n    } else {\n      window.addEventListener('pointerdown', onPointerMove);\n      window.addEventListener('pointermove', onPointerMove);\n    }\n\n    return () => {\n      if (hasTapEvent) {\n        window.removeEventListener('mousemove', onMouseMove);\n        window.removeEventListener('touchstart', onTouchStart);\n      } else {\n        window.removeEventListener('pointerdown', onPointerMove);\n        window.removeEventListener('pointermove', onPointerMove);\n      }\n    };\n  }, []);\n\n  return isTouch;\n};\n\nexport default useInteraction;\n"
  },
  {
    "path": "src/hooks/useIsTouch.ts",
    "content": "import { InteractionContext } from '@app/context/InteractionContext';\nimport { useContext } from 'react';\n\nexport const useIsTouch = (): boolean => {\n  const { isTouch } = useContext(InteractionContext);\n  return isTouch ?? false;\n};\n"
  },
  {
    "path": "src/hooks/useLocale.ts",
    "content": "import type { LanguageContextProps } from '@app/context/LanguageContext';\nimport { LanguageContext } from '@app/context/LanguageContext';\nimport { useContext } from 'react';\n\nconst useLocale = (): Omit<LanguageContextProps, 'children'> => {\n  const languageContext = useContext(LanguageContext);\n\n  return languageContext;\n};\n\nexport default useLocale;\n"
  },
  {
    "path": "src/hooks/useLockBodyScroll.ts",
    "content": "import { useEffect } from 'react';\n\n/**\n * Hook to lock the body scroll whenever a component is mounted or\n * whenever isLocked is set to true.\n *\n * You can pass in true always to cause a lock on mount/dismount of the component\n * using this hook.\n *\n * @param isLocked Toggle the scroll lock\n * @param disabled Disables the entire hook (allows conditional skipping of the lock)\n */\nexport const useLockBodyScroll = (\n  isLocked: boolean,\n  disabled?: boolean\n): void => {\n  useEffect(() => {\n    const originalOverflowStyle = window.getComputedStyle(\n      document.body\n    ).overflow;\n    const originalTouchActionStyle = window.getComputedStyle(\n      document.body\n    ).touchAction;\n    if (isLocked && !disabled) {\n      document.body.style.overflow = 'hidden';\n      document.body.style.touchAction = 'none';\n    }\n    return () => {\n      if (!disabled) {\n        document.body.style.overflow = originalOverflowStyle;\n        document.body.style.touchAction = originalTouchActionStyle;\n      }\n    };\n  }, [isLocked, disabled]);\n};\n"
  },
  {
    "path": "src/hooks/usePlexLogin.ts",
    "content": "import PlexOAuth from '@app/utils/plex';\nimport { useState } from 'react';\n\nconst plexOAuth = new PlexOAuth();\n\nfunction usePlexLogin({\n  onAuthToken,\n  onError,\n}: {\n  onAuthToken: (authToken: string) => void;\n  onError?: (err: string) => void;\n}) {\n  const [loading, setLoading] = useState(false);\n\n  const getPlexLogin = async () => {\n    setLoading(true);\n    try {\n      const authToken = await plexOAuth.login();\n      setLoading(false);\n      onAuthToken(authToken);\n    } catch (e) {\n      if (onError) {\n        onError(e.message);\n      }\n      setLoading(false);\n    }\n  };\n\n  const login = () => {\n    plexOAuth.preparePopup();\n    setTimeout(() => getPlexLogin(), 1500);\n  };\n\n  return { loading, login };\n}\n\nexport default usePlexLogin;\n"
  },
  {
    "path": "src/hooks/useRequestOverride.ts",
    "content": "import type { MediaRequest } from '@server/entity/MediaRequest';\nimport type {\n  ServiceCommonServer,\n  ServiceCommonServerWithDetails,\n} from '@server/interfaces/api/serviceInterfaces';\nimport useSWR from 'swr';\n\ninterface OverrideStatus {\n  server?: string;\n  profile?: string;\n  rootFolder?: string;\n  languageProfile?: string;\n}\n\nconst useRequestOverride = (request: MediaRequest): OverrideStatus => {\n  const { data: allServers } = useSWR<ServiceCommonServer[]>(\n    `/api/v1/service/${request.type === 'movie' ? 'radarr' : 'sonarr'}`\n  );\n\n  const { data } = useSWR<ServiceCommonServerWithDetails>(\n    `/api/v1/service/${request.type === 'movie' ? 'radarr' : 'sonarr'}/${\n      request.serverId\n    }`\n  );\n\n  if (!data || !allServers) {\n    return {};\n  }\n\n  const defaultServer = allServers.find(\n    (server) => server.is4k === request.is4k && server.isDefault\n  );\n\n  const activeServer = allServers.find(\n    (server) => server.id === request.serverId\n  );\n\n  return {\n    server:\n      activeServer && request.serverId !== defaultServer?.id\n        ? activeServer.name\n        : undefined,\n    profile:\n      defaultServer?.activeProfileId !== request.profileId\n        ? data.profiles.find((profile) => profile.id === request.profileId)\n            ?.name\n        : undefined,\n    rootFolder:\n      defaultServer?.activeDirectory !== request.rootFolder\n        ? request.rootFolder\n        : undefined,\n    languageProfile:\n      request.type === 'tv' &&\n      defaultServer?.activeLanguageProfileId !== request.languageProfileId\n        ? data.languageProfiles?.find(\n            (profile) => profile.id === request.languageProfileId\n          )?.name\n        : undefined,\n  };\n};\n\nexport default useRequestOverride;\n"
  },
  {
    "path": "src/hooks/useRouteGuard.ts",
    "content": "import { useRouter } from 'next/router';\nimport { useEffect } from 'react';\nimport type { Permission, PermissionCheckOptions } from './useUser';\nimport { useUser } from './useUser';\n\nconst useRouteGuard = (\n  permission: Permission | Permission[],\n  options?: PermissionCheckOptions\n): void => {\n  const router = useRouter();\n  const { user, hasPermission } = useUser();\n\n  useEffect(() => {\n    if (user && !hasPermission(permission, options)) {\n      router.push('/');\n    }\n  }, [user, permission, router, hasPermission, options]);\n};\n\nexport default useRouteGuard;\n"
  },
  {
    "path": "src/hooks/useSearchInput.ts",
    "content": "/* eslint-disable react-hooks/exhaustive-deps */\nimport type { Nullable } from '@app/utils/typeHelpers';\nimport { useRouter } from 'next/router';\nimport type { Dispatch, SetStateAction } from 'react';\nimport { useEffect, useState } from 'react';\nimport type { UrlObject } from 'url';\nimport useDebouncedState from './useDebouncedState';\n\ntype Url = string | UrlObject;\n\ninterface SearchObject {\n  searchValue: string;\n  searchOpen: boolean;\n  setIsOpen: Dispatch<SetStateAction<boolean>>;\n  setSearchValue: Dispatch<SetStateAction<string>>;\n  clear: () => void;\n}\n\nconst useSearchInput = (): SearchObject => {\n  const router = useRouter();\n  const [searchOpen, setIsOpen] = useState(false);\n  const [lastRoute, setLastRoute] = useState<Nullable<Url>>(null);\n  const [searchValue, debouncedValue, setSearchValue] = useDebouncedState(\n    (router.query.query as string) ?? ''\n  );\n\n  /**\n   * This effect handles routing when the debounced search input\n   * value changes.\n   *\n   * If we are not already on the /search route, then we push\n   * in a new route. If we are, then we only replace the history.\n   */\n  useEffect(() => {\n    if (debouncedValue !== '' && searchOpen) {\n      if (router.pathname.startsWith('/search')) {\n        router.replace({\n          pathname: router.pathname,\n          query: {\n            ...router.query,\n            query: debouncedValue,\n          },\n        });\n      } else {\n        setLastRoute(router.asPath);\n        router\n          .push({\n            pathname: '/search',\n            query: { query: debouncedValue },\n          })\n          .then(() => window.scrollTo(0, 0));\n      }\n    }\n  }, [debouncedValue]);\n\n  /**\n   * This effect is handling behavior when the search input is closed.\n   *\n   * If we have a lastRoute, we will route back to it. If we don't\n   * (in the case of a deeplink) we take the user back to the index route\n   */\n  useEffect(() => {\n    if (\n      searchValue === '' &&\n      router.pathname.startsWith('/search') &&\n      !searchOpen\n    ) {\n      if (lastRoute) {\n        router.push(lastRoute).then(() => window.scrollTo(0, 0));\n      } else {\n        router.replace('/').then(() => window.scrollTo(0, 0));\n      }\n    }\n  }, [searchOpen]);\n\n  /**\n   * This effect handles behavior for when the route is changed.\n   *\n   * If after a route change, the new debounced value is not the same\n   * as the query value then we will update the searchValue to either the\n   * new query or to an empty string (in the case of null). This makes sure\n   * that the value in the searchbox is whatever the user last entered regardless\n   * of routing to something like a detail page.\n   *\n   * If the new route is not /search and query is null, then we will close the\n   * search if it is open.\n   *\n   * In the final case, we want the search to always be open in the case the user\n   * is on /search\n   */\n  useEffect(() => {\n    if (router.query.query !== debouncedValue) {\n      setSearchValue(\n        router.query.query\n          ? decodeURIComponent(router.query.query as string)\n          : ''\n      );\n\n      if (!router.pathname.startsWith('/search') && !router.query.query) {\n        setIsOpen(false);\n      }\n    }\n\n    if (router.pathname.startsWith('/search')) {\n      setIsOpen(true);\n    }\n  }, [router, setSearchValue]);\n\n  const clear = () => {\n    setIsOpen(false);\n    setSearchValue('');\n  };\n\n  return {\n    searchValue,\n    searchOpen,\n    setIsOpen,\n    setSearchValue,\n    clear,\n  };\n};\n\nexport default useSearchInput;\n"
  },
  {
    "path": "src/hooks/useSettings.ts",
    "content": "import type { SettingsContextProps } from '@app/context/SettingsContext';\nimport { SettingsContext } from '@app/context/SettingsContext';\nimport { useContext } from 'react';\n\nconst useSettings = (): SettingsContextProps => {\n  const settings = useContext(SettingsContext);\n\n  return settings;\n};\n\nexport default useSettings;\n"
  },
  {
    "path": "src/hooks/useUpdateQueryParams.ts",
    "content": "import type { NextRouter } from 'next/router';\nimport { useRouter } from 'next/router';\nimport type { ParsedUrlQuery } from 'querystring';\nimport { useCallback } from 'react';\n\ntype UseQueryParamReturnedFunction = (\n  query: ParsedUrlQuery,\n  routerAction?: 'push' | 'replace'\n) => void;\n\ninterface MergedQueryString {\n  pathname: string;\n  path: string;\n}\n\n/**\n * Returns a filtered object containing only key/value pairs that don't exist in the current\n * router path.\n *\n * @param router Nextjs router instance\n * @param filters Object containing key value pairs for filter items that should be cleaned\n */\nexport const filterQueryString = (\n  router: NextRouter,\n  filters: ParsedUrlQuery\n): ParsedUrlQuery => {\n  const cleanedFilters: ParsedUrlQuery = {};\n\n  Object.keys(filters).forEach((key) => {\n    if (!router.pathname.match(new RegExp(`${key}`))) {\n      cleanedFilters[key] = filters[key];\n    }\n  });\n\n  return cleanedFilters;\n};\n\n/**\n * Takes a query paramter object and returns a new pathname and path\n * with the new values appended.\n *\n * - If the value already exists, it is updated.\n * - If a key with the value of null is passed, it will be removed from\n *   the current query paramters\n *\n * ## Example usage:\n *\n * If the current URL is `/foo?bar=test` and you want to add a new query parameter, you\n * can do the following:\n *\n * ```\n * const newRoute = mergeQueryString(router, { newParam: 'value' });\n * ```\n * NewRoute will become\n *\n * ```\n * {\n *  pathName: '/foo?bar=test&newParam=value',\n *   path: '/foo?bar=test&newParam=value'\n * }\n * ```\n *\n * @param router Nextjs router instance\n * @param query Key/value pair object containing query paramters\n */\nexport const mergeQueryString = (\n  router: NextRouter,\n  query: ParsedUrlQuery\n): MergedQueryString => {\n  const cleanedQuery = filterQueryString(router, router.query);\n\n  const mergedQuery = Object.assign({}, cleanedQuery, query);\n\n  const queryArray: string[] = [];\n\n  Object.keys(mergedQuery).map((key) => {\n    if (mergedQuery[key]) {\n      queryArray.push(`${key}=${mergedQuery[key]}`);\n    }\n  });\n\n  const pathWithoutQuery = router.asPath.match(/(.*)\\?.*/);\n  const asPath = pathWithoutQuery ? pathWithoutQuery[1] : router.asPath;\n\n  const pathname = `${router.pathname}${\n    queryArray.length > 0 ? `?${queryArray.join('&')}` : ''\n  }`;\n  const path = `${asPath}${\n    queryArray.length > 0 ? `?${queryArray.join('&')}` : ''\n  }`;\n\n  return { pathname, path };\n};\n\n/**\n * useQueryParams hook is used just to provide a callback with a nextjs\n * router instance attached to it. The returned method can be called with\n * an object of key/value pairs to route the user with the new query paramters\n */\nexport const useQueryParams = (): UseQueryParamReturnedFunction => {\n  const router = useRouter();\n\n  return useCallback(\n    (query: ParsedUrlQuery, routerAction: 'push' | 'replace' = 'push') => {\n      const newRoute = mergeQueryString(router, query);\n\n      if (newRoute.path !== router.asPath) {\n        if (routerAction === 'replace') {\n          router.replace(newRoute.pathname, newRoute.path);\n        } else {\n          router.push(newRoute.pathname, newRoute.path);\n        }\n      }\n    },\n    [router]\n  );\n};\n\nexport const useUpdateQueryParams = (\n  filter: ParsedUrlQuery\n): ((key: string, value?: string) => void) => {\n  const updateQueryParams = useQueryParams();\n\n  return useCallback(\n    (key: string, value?: string) => {\n      const query = {\n        ...filter,\n        [key]: value,\n      };\n      updateQueryParams(query, 'replace');\n    },\n    [filter, updateQueryParams]\n  );\n};\n\nexport const useBatchUpdateQueryParams = (\n  filter: ParsedUrlQuery\n): ((items: Record<string, string | undefined>) => void) => {\n  const updateQueryParams = useQueryParams();\n\n  return useCallback(\n    (items: Record<string, string | undefined>) => {\n      const query = {\n        ...filter,\n        ...items,\n      };\n      updateQueryParams(query, 'replace');\n    },\n    [filter, updateQueryParams]\n  );\n};\n"
  },
  {
    "path": "src/hooks/useUser.ts",
    "content": "import { UserType } from '@server/constants/user';\nimport type { PermissionCheckOptions } from '@server/lib/permissions';\nimport { hasPermission, Permission } from '@server/lib/permissions';\nimport type { NotificationAgentKey } from '@server/lib/settings';\nimport { useRouter } from 'next/router';\nimport type { MutatorCallback } from 'swr';\nimport useSWR from 'swr';\n\nexport { Permission, UserType };\nexport type { PermissionCheckOptions };\n\nexport interface User {\n  id: number;\n  warnings: string[];\n  plexUsername?: string | null;\n  jellyfinUsername?: string | null;\n  username?: string;\n  displayName: string;\n  email: string;\n  avatar: string;\n  permissions: number;\n  userType: number;\n  createdAt: Date;\n  updatedAt: Date;\n  requestCount: number;\n  settings?: UserSettings;\n}\n\ntype NotificationAgentTypes = Record<NotificationAgentKey, number>;\n\nexport interface UserSettings {\n  discordId?: string;\n  discoverRegion?: string;\n  streamingRegion?: string;\n  originalLanguage?: string;\n  locale?: string;\n  notificationTypes: Partial<NotificationAgentTypes>;\n  watchlistSyncMovies?: boolean;\n  watchlistSyncTv?: boolean;\n}\n\ninterface UserHookResponse {\n  user?: User;\n  loading: boolean;\n  error: string;\n  revalidate: (\n    data?: User | Promise<User> | MutatorCallback<User> | undefined,\n    shouldRevalidate?: boolean | undefined\n  ) => Promise<User | undefined>;\n  hasPermission: (\n    permission: Permission | Permission[],\n    options?: PermissionCheckOptions\n  ) => boolean;\n}\n\nexport const useUser = ({\n  id,\n  initialData,\n}: { id?: number; initialData?: User } = {}): UserHookResponse => {\n  const router = useRouter();\n  const isAuthPage = /^\\/(login|setup|resetpassword(?:\\/|$))/.test(\n    router.pathname\n  );\n\n  const {\n    data,\n    error,\n    mutate: revalidate,\n  } = useSWR<User>(id ? `/api/v1/user/${id}` : `/api/v1/auth/me`, {\n    fallbackData: initialData,\n    refreshInterval: !isAuthPage ? 30000 : 0,\n    revalidateOnFocus: !isAuthPage,\n    revalidateOnMount: !isAuthPage,\n    revalidateOnReconnect: !isAuthPage,\n    errorRetryInterval: 30000,\n    shouldRetryOnError: false,\n  });\n\n  const checkPermission = (\n    permission: Permission | Permission[],\n    options?: PermissionCheckOptions\n  ): boolean => {\n    return hasPermission(permission, data?.permissions ?? 0, options);\n  };\n\n  return {\n    user: data,\n    loading: !data && !error,\n    error,\n    hasPermission: checkPermission,\n    revalidate,\n  };\n};\n"
  },
  {
    "path": "src/hooks/useVerticalScroll.ts",
    "content": "import { debounce } from 'lodash';\nimport type { MutableRefObject } from 'react';\nimport { useEffect, useRef, useState } from 'react';\n\nconst IS_SCROLLING_CHECK_THROTTLE = 200;\nconst BUFFER_HEIGHT = 200;\n\n/**\n * useVerticalScroll is a custom hook to handle infinite scrolling\n *\n * @param callback Callback is executed when page reaches bottom\n * @param shouldFetch Disables callback if true\n */\nconst useVerticalScroll = (\n  callback: () => void,\n  shouldFetch: boolean\n): boolean => {\n  const [isScrolling, setScrolling] = useState(false);\n\n  type SetTimeoutReturnType = ReturnType<typeof setTimeout>;\n  const scrollingTimer: MutableRefObject<SetTimeoutReturnType | undefined> =\n    useRef();\n\n  const runCallback = () => {\n    if (shouldFetch) {\n      const scrollTop = Math.max(\n        window.pageYOffset,\n        document.documentElement.scrollTop,\n        document.body.scrollTop\n      );\n      if (\n        window.innerHeight + scrollTop >=\n        document.documentElement.offsetHeight - BUFFER_HEIGHT\n      ) {\n        callback();\n      }\n    }\n  };\n\n  const debouncedCallback = debounce(runCallback, 50);\n\n  useEffect(() => {\n    runCallback();\n  });\n\n  useEffect(() => {\n    const onScroll = () => {\n      if (scrollingTimer.current !== undefined) {\n        clearTimeout(scrollingTimer.current);\n      }\n      if (!isScrolling) {\n        setScrolling(true);\n      }\n\n      scrollingTimer.current = setTimeout(() => {\n        setScrolling(false);\n      }, IS_SCROLLING_CHECK_THROTTLE);\n      debouncedCallback();\n    };\n\n    const onResize = () => {\n      debouncedCallback();\n    };\n    window.addEventListener('scroll', onScroll, { passive: true });\n    window.addEventListener('resize', onResize, { passive: true });\n\n    return () => {\n      window.removeEventListener('scroll', onScroll);\n      window.removeEventListener('resize', onResize);\n\n      if (scrollingTimer.current !== undefined) {\n        clearTimeout(scrollingTimer.current);\n      }\n    };\n  });\n\n  return isScrolling;\n};\n\nexport default useVerticalScroll;\n"
  },
  {
    "path": "src/i18n/extractMessages.ts",
    "content": "import { promises as fs } from 'fs';\nimport { join } from 'path';\n\n// get all file content recursively\nasync function getFiles(dir: string): Promise<string[]> {\n  const dirents = await fs.readdir(dir, { withFileTypes: true });\n  const files = await Promise.all(\n    dirents.map((dirent) => {\n      const res = join(dir, dirent.name);\n      return dirent.isDirectory() ? getFiles(res) : res;\n    })\n  );\n  return Array.prototype.concat(...files);\n}\n\n// extract the i18n messages from the file\nasync function extractMessages(\n  filePath: string\n): Promise<{ namespace: string; messages: Record<string, string> } | null> {\n  const content = await fs.readFile(filePath, 'utf8');\n  const regex = /defineMessages\\(\\n?\\s*'(.+?)',\\n?\\s*\\{([\\s\\S]+?)\\}\\n?\\);/;\n  const match = content.match(regex);\n  if (match) {\n    const [, namespace, messages] = match;\n    try {\n      const formattedMessages = messages\n        .trim()\n        .replace(/^\\s*(['\"])?([a-zA-Z0-9_-]+)(['\"])?:[\\s\\n]*/gm, '\"$2\":')\n        .replace(/^\"[a-zA-Z0-9_-]+\":'.*',?$/gm, (match) => {\n          const parts = /^(\"[a-zA-Z0-9_-]+\":)'(.*)',?$/.exec(match);\n          if (!parts) return match;\n          return `${parts[1]}\"${parts[2]\n            .replace(/\\\\/g, '\\\\\\\\')\n            .replace(/\"/g, '\\\\\"')}\",`;\n        })\n        .replace(/,$/, '');\n      const messagesJson = JSON.parse(`{${formattedMessages}}`);\n      return { namespace: namespace.trim(), messages: messagesJson };\n    } catch {\n      return null;\n    }\n  }\n  return null;\n}\n\nasync function processMessages(dir: string): Promise<string> {\n  // get messages from all files and sort them by namespace\n  const files = await getFiles(dir);\n  const extractedMessagesGroups = await Promise.all(files.map(extractMessages));\n\n  // group messages by namespace\n  const messagesByNamespace: {\n    namespace: string;\n    messages: Record<string, string>;\n  }[] = [];\n  const namespaces = [\n    ...new Set(extractedMessagesGroups.map((msg) => msg?.namespace)),\n  ];\n  for (const namespace of namespaces) {\n    if (!namespace) continue;\n    const filteredMessagesGroups = extractedMessagesGroups\n      .filter((msg) => msg?.namespace === namespace)\n      .map((msg) => msg?.messages);\n    for (const extractedMessages of filteredMessagesGroups) {\n      if (!extractedMessages) continue;\n      const previousNamespaceMessages = messagesByNamespace.find(\n        (msg) => msg.namespace === namespace\n      );\n      if (previousNamespaceMessages) {\n        Object.assign(previousNamespaceMessages.messages, extractedMessages);\n      } else {\n        messagesByNamespace.push({ namespace, messages: extractedMessages });\n      }\n    }\n  }\n\n  messagesByNamespace.sort((a, b) => {\n    if (!a || !b) return 0;\n    if (\n      a.namespace.startsWith(b.namespace) ||\n      b.namespace.startsWith(a.namespace)\n    ) {\n      const aLevel = a.namespace.match(/\\./g)?.length || 0;\n      const bLevel = b.namespace.match(/\\./g)?.length || 0;\n      return bLevel - aLevel;\n    }\n    return a.namespace.localeCompare(b.namespace);\n  });\n\n  // add every messages from every namespace to an object\n  const result: Record<string, string> = {};\n  for (const extractedMessages of messagesByNamespace) {\n    const { namespace, messages } = extractedMessages;\n    for (const key of Object.keys(messages).sort()) {\n      result[`${namespace}.${key}`] = messages[key];\n    }\n  }\n\n  return JSON.stringify(result, null, '  ') + '\\n';\n}\n\nasync function saveMessages() {\n  const directoryPath = './src/';\n  const resultPath = './src/i18n/locale/en.json';\n\n  const result = await processMessages(directoryPath);\n  await fs.writeFile(resultPath, result);\n}\n\nsaveMessages();\n\nexport {};\n"
  },
  {
    "path": "src/i18n/globalMessages.ts",
    "content": "import defineMessages from '@app/utils/defineMessages';\n\nconst globalMessages = defineMessages('i18n', {\n  available: 'Available',\n  partiallyavailable: 'Partially Available',\n  deleted: 'Deleted',\n  processing: 'Processing',\n  unavailable: 'Unavailable',\n  notrequested: 'Not Requested',\n  requested: 'Requested',\n  requesting: 'Requesting…',\n  request: 'Request',\n  request4k: 'Request in 4K',\n  failed: 'Failed',\n  pending: 'Pending',\n  declined: 'Declined',\n  approved: 'Approved',\n  completed: 'Completed',\n  movie: 'Movie',\n  movies: 'Movies',\n  collection: 'Collection',\n  tvshow: 'Series',\n  tvshows: 'Series',\n  cancel: 'Cancel',\n  canceling: 'Canceling…',\n  approve: 'Approve',\n  decline: 'Decline',\n  delete: 'Delete',\n  retry: 'Retry',\n  retrying: 'Retrying…',\n  view: 'View',\n  deleting: 'Deleting…',\n  test: 'Test',\n  testing: 'Testing…',\n  save: 'Save Changes',\n  saving: 'Saving…',\n  import: 'Import',\n  importing: 'Importing…',\n  close: 'Close',\n  edit: 'Edit',\n  areyousure: 'Are you sure?',\n  back: 'Back',\n  next: 'Next',\n  previous: 'Previous',\n  status: 'Status',\n  all: 'All',\n  experimental: 'Experimental',\n  advanced: 'Advanced',\n  restartRequired: 'Restart Required',\n  loading: 'Loading…',\n  settings: 'Settings',\n  usersettings: 'User Settings',\n  delimitedlist: '{a}, {b}',\n  error: 'Something went wrong. Please try again.',\n  showingresults:\n    'Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results',\n  resultsperpage: 'Display {pageSize} results per page',\n  noresults: 'No results.',\n  open: 'Open',\n  resolved: 'Resolved',\n  blocklist: 'Blocklist',\n  blocklisted: 'Blocklisted',\n  blocklistSuccess: '<strong>{title}</strong> was successfully blocklisted.',\n  blocklistError: 'Something went wrong. Please try again.',\n  blocklistDuplicateError:\n    '<strong>{title}</strong> has already been blocklisted.',\n  removeFromBlocklistSuccess:\n    '<strong>{title}</strong> was successfully removed from the Blocklist.',\n  addToBlocklist: 'Add to Blocklist',\n  removefromBlocklist: 'Remove from Blocklist',\n  specials: 'Specials',\n});\n\nexport default globalMessages;\n"
  },
  {
    "path": "src/i18n/locale/ar.json",
    "content": "{\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code>مجلد التثبيت لم يتم إعداده بشكل صحيح سيتم تنظيف جميع البيانات عند إيقاف او إعادة تشغيل حاوي التطبيق.\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"إرسال تنبيهات في حالة وصول طلبات جديدة تتطلب الموافقة.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"أنواع التنبيهات\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"تلقي تنبيهات عندما يتم الموافقة على طلبات المحتوى.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"تلقي تنبيهات عندما يتم رفض الطلبات.\",\n  \"components.PermissionEdit.createissuesDescription\": \"إعطاء صلاحية للإبلاغ عن مشاكل.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"إعطاء صلاحية بإدارة الطلبات. كل الطلبات المقدمة من قبل مستخدم يحمل هذا الإذن سيتم الموافقة عليها بشكل تلقائي.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"موافقة تلقائية لكل طلبات المحتوى باستثناء جودة الفور كي.\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"إعطاء صلاحيّة بطلب أفلام بجودة فور كي.\",\n  \"components.PermissionEdit.requestDescription\": \"إعطاء اصلاحية بطلب محتوى ليس بجودة فور كي.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"تم إستهلاك الحد الأقصى المسموح لك بطلب المواسم\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"إختار علامات التعريف\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"علامات التعريف\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"يمكنك الإطلاع على ملخص الحد الأقصى لطلباتك في <ProfileLink>صفحة ملف التعريف</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"تحتاج على الأقل ان تملك <strong>{seasons}</strong> {seasons, plural, one {طلب موسم} other {طلبات مواسم}} متبقية/متبقّي من حدك الأقصى لتتمكن من طلب هذا المسلسل.\",\n  \"components.Discover.NetworkSlider.networks\": \"شبكات البث\",\n  \"components.Discover.upcomingmovies\": \"أفلام قادمة\",\n  \"components.Discover.upcomingtv\": \"مسلسلات قادمة\",\n  \"components.IssueDetails.season\": \"موسم {seasonNumber}\",\n  \"components.IssueModal.issueVideo\": \"الفديو\",\n  \"components.ManageSlideOver.manageModalMedia\": \"المحتوى\",\n  \"components.Login.loginerror\": \"حدث خطأ ما أثناء محاولة تسجيل الدخول.\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"لا يوجد طلبات.\",\n  \"components.Layout.VersionStatus.streamstable\": \"نسخة مستقرة من \\\"أوفرسيرر\\\"\",\n  \"components.Login.forgotpassword\": \"نسيت كلمة السر؟\",\n  \"components.Login.signingin\": \"جاري تسجيل الدخول…\",\n  \"components.Login.signinheader\": \"سجل دخول للمتابعة\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"نسخة التطوير من \\\"أوفرسيرر\\\"\",\n  \"components.Login.password\": \"كلمة السر\",\n  \"components.Login.signin\": \"تسجيل دخول\",\n  \"components.Login.signinwithplex\": \"إستخدم حساب بليكس\",\n  \"components.Login.signinwithoverseerr\": \"إستخدم حسابك في {applicationTitle}\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"محو البيانات\",\n  \"components.Login.validationemailrequired\": \"يجب عليك تزويد بريد إلكتروني صحيح\",\n  \"components.Login.validationpasswordrequired\": \"يجب عليك إدخال كلمة سر\",\n  \"components.ManageSlideOver.alltime\": \"جميع الأوقات\",\n  \"components.ManageSlideOver.downloadstatus\": \"التنزيلات\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"متقدم\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* سيتم حذف جميع البيانات بشكل نهائي لـ {mediaType},متضمنا جميع الطلبات.إذا كان هذا المحتوى متوفر في مكتبة {mediaServerName}، سيتم إعادة تفاصيل المحتوى في عملية الفحص القادمة.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"الطلبات\",\n  \"components.ManageSlideOver.manageModalTitle\": \"إدارة {mediaType}\",\n  \"components.ManageSlideOver.manageModalIssues\": \"المشاكل المفتوحة\",\n  \"components.MovieDetails.budget\": \"الميزانية\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"محتوى جودة الفور كي\",\n  \"components.ManageSlideOver.playedby\": \"تم تشغيله بواسطة\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {تشغيل} other {تشغيل}}\",\n  \"components.ManageSlideOver.tvshow\": \"مسلسل\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"رؤية المزيد\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"طاقم التمثيل\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"طاقم العمل\",\n  \"components.MovieDetails.cast\": \"الطاقم\",\n  \"components.NotificationTypeSelector.mediarequested\": \"الطلب معلق للموافقة\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"إرسال تنبيهات عند طلب المستخدمين لمحتوى تمت الموافقة عليه بشكل تلقائي.\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"إرسال تنبيهات في حالة رفض الطلبات.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} أفلام\",\n  \"components.CollectionDetails.overview\": \"نظرة عامة\",\n  \"components.CollectionDetails.requestcollection\": \"طلب تجميعة\",\n  \"components.CollectionDetails.requestcollection4k\": \"طلب تجميعة بجودة فور كي\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} أفلام\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} أفلام\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} مسلسلات\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} أفلام\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} مسلسلات\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} مسلسلات\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"أنواع الأفلام\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"أنواع الأفلام\",\n  \"components.Discover.StudioSlider.studios\": \"إستديوهات الإنتاج\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"أنواع المسلسلات\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"أنواع المسلسلات\",\n  \"components.Discover.discover\": \"إكتشف\",\n  \"components.Discover.popularmovies\": \"أفلام ذات شعبية\",\n  \"components.Discover.populartv\": \"مسلسلات ذات شعبية\",\n  \"components.Discover.recentlyAdded\": \"أضيف مؤخرا\",\n  \"components.Discover.recentrequests\": \"الطلبات الحديثة\",\n  \"components.Discover.trending\": \"الأكثر شيوعاً\",\n  \"components.Discover.upcoming\": \"أفلام قادمة\",\n  \"components.DownloadBlock.estimatedtime\": \"الزمن المتوقّع {time}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"هل أنت متأكد من حذف هذا التعليق ؟\",\n  \"components.IssueDetails.IssueComment.delete\": \"حذف التعليق\",\n  \"components.IssueDetails.IssueComment.edit\": \"تعديل التعليق\",\n  \"components.IssueDetails.IssueComment.postedby\": \"علّق {relativeTime} بواسطة {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"علّق {relativeTime} بواسطة {username} (تم تعديله)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"يجب عليك كتابه رسالة\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"مسح المشكلة\",\n  \"components.IssueDetails.IssueDescription.description\": \"الوصف\",\n  \"components.IssueDetails.IssueDescription.edit\": \"تعديل الوصف\",\n  \"components.IssueDetails.allepisodes\": \"جميع الحلقات\",\n  \"components.IssueDetails.allseasons\": \"جميع المواسم\",\n  \"components.IssueDetails.closeissue\": \"إغلاق المشكلة\",\n  \"components.IssueDetails.closeissueandcomment\": \"إغلاق مع كتابة تعليق\",\n  \"components.IssueDetails.commentplaceholder\": \"إضافة تعليق…\",\n  \"components.IssueDetails.comments\": \"تعليقات\",\n  \"components.IssueDetails.deleteissue\": \"حذف المشكلة\",\n  \"components.IssueDetails.deleteissueconfirm\": \"هل أنت متأكد من حذف هذه المشكلة ؟\",\n  \"components.IssueDetails.episode\": \"حلقة {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"مشكلة\",\n  \"components.IssueDetails.issuetype\": \"النوع\",\n  \"components.IssueDetails.lastupdated\": \"أخر تحديث\",\n  \"components.IssueDetails.leavecomment\": \"تعليق\",\n  \"components.IssueDetails.nocomments\": \"لا تعليقات.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} تم فتح {relativeTime} من قبل {username}\",\n  \"components.IssueDetails.openin4karr\": \"فتح بجودة فور كي في {arr}\",\n  \"components.IssueDetails.openinarr\": \"فتح في {arr}\",\n  \"components.IssueDetails.play4konplex\": \"تشغيل بجودة فور كي في بليكس\",\n  \"components.IssueDetails.playonplex\": \"تشغيل في بليكس\",\n  \"components.IssueDetails.problemepisode\": \"الحلقة المعنيّة\",\n  \"components.IssueDetails.problemseason\": \"الموسم المعني\",\n  \"components.IssueDetails.reopenissue\": \"إعادة فتح المشكلة\",\n  \"components.IssueDetails.reopenissueandcomment\": \"إعادة فتح مع ترك تعليق\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"حدث خطأ ما أثناء تعديل وصف المشكلة.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"تم تعديل وصف المشكلة بنجاح!\",\n  \"components.IssueDetails.toaststatusupdated\": \"تم تعديل حالة المشكلة بنجاح!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"حدث خطأ ما أثناء تحديث حالة المشكلة.\",\n  \"components.IssueDetails.unknownissuetype\": \"غير معروف\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {حلقة} other {حلقات}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"الحالة\",\n  \"components.IssueList.IssueItem.issuetype\": \"النوع\",\n  \"components.IssueList.IssueItem.opened\": \"مفتوحة\",\n  \"components.IssueDetails.toastissuedeleted\": \"تم حذف المشكلة بنجاح!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"حدث خطأ أثناء حذف المشكلة.\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} بواسطة {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"الحلقة المعنيّة\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {موسم} other {مواسم}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"غير معروف\",\n  \"components.IssueList.IssueItem.viewissue\": \"الإطلاع على المشكلة\",\n  \"components.IssueList.issues\": \"المشاكل\",\n  \"components.IssueList.showallissues\": \"رؤية جميع المشاكل\",\n  \"components.IssueList.sortAdded\": \"الأحدث\",\n  \"components.IssueList.sortModified\": \"أخر تعديل\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"جميع الحلقات\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"جميع المواسم\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"حلقة {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"الإضافات\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"الحلقة المعنيّة\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"الموسم المعني\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"رجاءا قم بتزويد شرح مفصل للمشكلة التي صادفتها.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"الإبلاغ عن مشكلةْ\",\n  \"components.IssueModal.CreateIssueModal.season\": \"موسم {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"تأكيد المشكلة\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"حدث خطأ ما أثناء تأكيد المشكلة.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"تقرير المشكلة عن <strong>{title}</strong> تم تأكيده بنجاح!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"رؤية المشكلة\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"يجب عليك ذكر وصف\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"ماهي المشكلة؟\",\n  \"components.IssueModal.issueAudio\": \"الصوت\",\n  \"components.IssueModal.issueOther\": \"أخرى\",\n  \"components.IssueModal.issueSubtitles\": \"الترجمة\",\n  \"components.LanguageSelector.languageServerDefault\": \"الإفتراضي ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"كل اللغات\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"لغة العرض\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"بحث عن فيلم أو مسلسل\",\n  \"components.Layout.Sidebar.dashboard\": \"إكتشف\",\n  \"components.Layout.Sidebar.issues\": \"المشاكل\",\n  \"components.Layout.Sidebar.requests\": \"الطلبات\",\n  \"components.Layout.Sidebar.settings\": \"الإعدادات\",\n  \"components.Layout.Sidebar.users\": \"المستخدمين\",\n  \"components.Layout.UserDropdown.myprofile\": \"ملف التعريف\",\n  \"components.Layout.UserDropdown.settings\": \"الإعدادات\",\n  \"components.Layout.UserDropdown.signout\": \"تسجيل خروج\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {تأكيد} other {تأكيد}} behind\",\n  \"components.Layout.VersionStatus.outofdate\": \"غير محدّث\",\n  \"components.Login.email\": \"عنوان البريد الإلكتروني\",\n  \"components.ManageSlideOver.markavailable\": \"الإشارة بتوفر هذا المحتوى\",\n  \"components.ManageSlideOver.movie\": \"فيلْم\",\n  \"components.ManageSlideOver.openarr\": \"فتح في {arr}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"الإشارة بتوفّره بجودة فور كي\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"الإشارة بأن كل المواسم متوفرة بجودة فور كي\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"الإشارة بتوفر جميع المواسم\",\n  \"components.ManageSlideOver.openarr4k\": \"فتح بجودة فور كي في {arr}\",\n  \"components.ManageSlideOver.opentautulli\": \"فتح في تطبيق تاتولي (Tautulli)\",\n  \"components.ManageSlideOver.pastdays\": \"مضى من الأيام {days, number}\",\n  \"components.MovieDetails.mark4kavailable\": \"الإشارة بأنه متوفر بجودة فور كي\",\n  \"components.MovieDetails.markavailable\": \"الإشارة بتوفر هذا المحتوى\",\n  \"components.MovieDetails.originallanguage\": \"اللغة الأصلية\",\n  \"components.MovieDetails.originaltitle\": \"الإسم الأصلي\",\n  \"components.MovieDetails.overviewunavailable\": \"النظرة العامة غير متوفرة.\",\n  \"components.MovieDetails.productioncountries\": \"إنتاج {countryCount, plural, one {الدولة} other {الدول}}\",\n  \"components.MovieDetails.recommendations\": \"توصيات\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {تاريخ الاصدار other {تواريخ الاصدار}}\",\n  \"components.MovieDetails.revenue\": \"العائد / الربح\",\n  \"components.MovieDetails.runtime\": \"{minutes} دقيقة\",\n  \"components.MovieDetails.showless\": \"رؤية تفاصيل أقل\",\n  \"components.MovieDetails.showmore\": \"رؤية المزيد\",\n  \"components.MovieDetails.similar\": \"عناوين مشابهه\",\n  \"components.MovieDetails.overview\": \"نظرة عامة\",\n  \"components.MovieDetails.streamingproviders\": \"يعرض حاليا على\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {إستديو الإنتاج} other {إستديوهات الإنتاج}}\",\n  \"components.MovieDetails.viewfullcrew\": \"رؤية طاقم العمل\",\n  \"components.MovieDetails.watchtrailer\": \"شاهد الإعلان\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"الحصول على تنبيهات عند تعليق المستخدمين على المشاكل.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"الحصول على تنبيهات عند إعادة فتح المشاكل من قبل المستخدمين.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"الحصول على تنبيهات في حالة حل المشاكل من قبل المستخدمين.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"تعليق على المشكلة\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"إرسال تنبيهات في حالة وجود تعليقات جديدة على المشاكل.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"تم التبليغ عن المشكلة\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"إرسال تنبيهات في حالة التبليغ عن مشاكل.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"تم إعادة فتح المشكلة\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"إرسال تنبيهات عند إعادة فتح المشاكل.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"تم حل المشكلة\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"إرسال تنبيهات عند حل المشاكل.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"تم الموافقة على الطلب بشكل تلقائي\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"تمت الموافقة على الطلب\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"إرسال تنبيهات عند الموافقة على الطلبات بشكل يدوي.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"الطلب متاح\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"إرسال تنبيهات عندما يتوفر المحتوى المطلوب.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"تم رفض الطلب\",\n  \"components.NotificationTypeSelector.mediafailed\": \"فشل إنشاء الطلب\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"تلقي تنبيهات في حالة فشل إرسال الطلبات الى رادار أو سونار.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"تلقي تنبيهات في حالة وصول تعليقات جديدة على مشاكل تم فتحها بواسطتك.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"تلقي تنبيهات في حالة قيام المستخدمين بالتبليغ عن مشاكل.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"تلقي تنبيهات عندما يتم إعادة فتح مشكلة تم الإبلاغ عنها بواسطتك.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"تلقي تنبيهات في حالة الإشارة بحل مشكلة تم الابلاغ عنها بواسطتك.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"تلقي تنبيهات في حالة الموافقة بشكل تلقائي على طلب محتوى جديد من قبل المستخدمين.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"تلقي تنبيهات عندما تصبح الطلبات متوفرة.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"تلقي تنبيهات في حالة فشل إرسال الطلبات الى رادار أو سونار.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"تلقي تنبيهات عندما يتم طلب محتوى جديد يتطلب الموافقة عليه.\",\n  \"components.PermissionEdit.admin\": \"مسؤول\",\n  \"components.PermissionEdit.adminDescription\": \"ولوج إداري كامل لا يتطلب أي أذونات.\",\n  \"components.PermissionEdit.advancedrequest\": \"طلبات متقدمة\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"إعطاء صلاحية تعديل الخيارات المتقدمة لطلب المحتوى.\",\n  \"components.PermissionEdit.autoapprove\": \"موافقة تلقائية\",\n  \"components.PermissionEdit.autoapprove4k\": \"موافقة تلقائية لجودة الفور كي\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"إعطاء موافقة تلقائية لكل طلبات المحتوى بجودة الفور كي.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"موافقة تلقائية للأفلام بجودة فور كي\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"إعطاء موافقة تلقائية لكل طلبات الأفلام بجودة فور كي.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"موافقة تلقائية للمسلسلات بجودة فور كي\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"موافقة تلقائية لطلبات المسلسلات بجودة فور كي.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"موافقة تلقائية للأفلام\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"موافقة تلقائية لكل طلبات الأفلام باستثناء جودة الفور كي.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"موافقة تلقائية للمسلسلات\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"موافقة تلقائية لكل طلبات المسلسلات باستثناء جودة الفور كي.\",\n  \"components.PermissionEdit.createissues\": \"الإبلاغ عن وجود مشاكل\",\n  \"components.PermissionEdit.manageissues\": \"إدارة المشاكل\",\n  \"components.PermissionEdit.manageissuesDescription\": \"إعطاء صلاحية بإدارة المشاكل.\",\n  \"components.PermissionEdit.managerequests\": \"إدارة الطلبات\",\n  \"components.PermissionEdit.request\": \"طلب\",\n  \"components.PermissionEdit.request4k\": \"طلب بجودة فور كيّ\",\n  \"components.PermissionEdit.request4kDescription\": \"اعطاء صلاحية بطلب محتوى بجودة فور كي.\",\n  \"components.PermissionEdit.request4kMovies\": \"طلب أفلام بجودة فور كي\",\n  \"components.PermissionEdit.request4kTv\": \"طلب مسلسلات بجودة فور كي\",\n  \"components.PermissionEdit.request4kTvDescription\": \"إعطاء صلاحية بطلب مسلسلات بجودة فور كي.\",\n  \"components.PermissionEdit.requestMovies\": \"طلب أفلام\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"إعطاء صلاحية بطلب أفلام ليست بجودة فور كي.\",\n  \"components.PermissionEdit.requestTv\": \"طلب مسلسلات\",\n  \"components.PermissionEdit.requestTvDescription\": \"إعطاء إذن بطلب مسلسلات ليست بجودة ٤ك.\",\n  \"components.PermissionEdit.users\": \"إدارة المستخدمين\",\n  \"components.PermissionEdit.usersDescription\": \"إعطاء الإذن بإدارة المستخدمين. الذين يملكون هذه الصلاحية لا يستطيعون تعديل أي مستخدم مسؤول أو إعطاء صلاحية مسوؤل.\",\n  \"components.PermissionEdit.viewissues\": \"الإطلاع على المشاكل\",\n  \"components.PermissionEdit.viewissuesDescription\": \"إعطاء صلاحية برؤية كل المشاكل المبلغ عنها من قبل المستخدمين.\",\n  \"components.PermissionEdit.viewrequests\": \"الإطلاع على الطلبات\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"إعطاء صلاحية بالإطلاع على جميع الطلبات المقدمة من قبل المستخدمين.\",\n  \"components.PersonDetails.alsoknownas\": \"أيضا يُعرف بإسم: {names}\",\n  \"components.PersonDetails.appearsin\": \"الظهور\",\n  \"components.PersonDetails.ascharacter\": \"{character} شارك بِدوْر\",\n  \"components.PersonDetails.birthdate\": \"ولد في {birthdate}\",\n  \"components.PersonDetails.crewmember\": \"عضو\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} - {deathdate}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {يوم} other {أيام}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} كل {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {فيلم} other {أفلام}}\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {موسم} other {مواسم}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} كل {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.unlimited\": \"غير محدود\",\n  \"components.RegionSelector.regionDefault\": \"كل المناطق\",\n  \"components.RegionSelector.regionServerDefault\": \"الإفتراضي ({region})\",\n  \"components.RequestBlock.profilechanged\": \"ملف تعريف الجودة\",\n  \"components.RequestBlock.requestoverrides\": \"تغيير اعدادات الطلب الافتراضية\",\n  \"components.RequestBlock.rootfolder\": \"مجلّد الحفظ\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {موسم} other {مواسم}}\",\n  \"components.RequestBlock.server\": \"وجهه السيرفر\",\n  \"components.RequestButton.approve4krequests\": \"الموافقة على {requestCount, plural, one {طلب فور كي} other {{requestCount} طلبات فور كي}}\",\n  \"components.RequestButton.approverequest\": \"الموافقة على الطلب\",\n  \"components.RequestButton.approverequest4k\": \"الموافقة على طلب فور كي\",\n  \"components.RequestButton.approverequests\": \"الموافقة على {requestCount, plural, one {طلب} other {{requestCount} طلبات}}\",\n  \"components.RequestButton.decline4krequests\": \"رفض {requestCount, plural, one {طلب الفور كي} other {{requestCount} طلبات الفور كي}}\",\n  \"components.RequestButton.declinerequest\": \"رفض الطلب\",\n  \"components.RequestButton.declinerequest4k\": \"رفض طلب الفور كي\",\n  \"components.RequestButton.declinerequests\": \"رفض {requestCount, plural, one {طلب} other {{requestCount} طلبات}}\",\n  \"components.RequestButton.requestmore\": \"طلب المزيد\",\n  \"components.RequestButton.requestmore4k\": \"طلب المزيد بجودة فور كي\",\n  \"components.RequestButton.viewrequest\": \"رؤية تفاصيل الطلب\",\n  \"components.RequestButton.viewrequest4k\": \"رؤية تفاصيل طلب الفور كي\",\n  \"components.RequestCard.deleterequest\": \"حذف الطلب\",\n  \"components.RequestCard.failedretry\": \"حدث خطأ ما أثناء محاولة إعادة الطلب.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} غير موجود\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {موسم} other {مواسم}}\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"إلغاء الطلب\",\n  \"components.RequestList.RequestItem.deleterequest\": \"حذف الطلب\",\n  \"components.RequestList.RequestItem.editrequest\": \"تعديل الطلب\",\n  \"components.RequestList.RequestItem.failedretry\": \"حدث خطأ ما أثناء محاولة إعادة الطلب.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} غير موجود\",\n  \"components.RequestList.RequestItem.modified\": \"تم تعديله\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} من قبل {user}\",\n  \"components.RequestList.RequestItem.requested\": \"تم طلبه\",\n  \"components.RequestList.RequestItem.requesteddate\": \"تم طلبه\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {موسم} other {مواسم}}\",\n  \"components.RequestList.requests\": \"الطلبات\",\n  \"components.RequestList.showallrequests\": \"رؤية جميع الطلبات\",\n  \"components.RequestList.sortAdded\": \"الأحدث\",\n  \"components.RequestList.sortModified\": \"أخر تعديل\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"متقدم\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"*هذا المحتوى بتصنيف \\\" إنمي \\\".\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (إفتراضي)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"وجهه السيرفر\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})'\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"ملف تعريف اللغة\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"لا يوجد علامات تعريف.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"ملف تعريف الجودة\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"تقديم الطلب بإسم\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"مجلد الحفظ\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"مسموح لك بطلب <strong>{limit}</strong> {type} كل <strong>{days}</strong> أيام.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"هذا المستخدم مسموح له بطلب <strong>{limit}</strong> {type} كل <strong>{days}</strong> أيام.\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"فِيلم\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {فيلم} other {أفلام}}\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"يمكنك الإطلاع على ملخص الحد الاقصى لطلبات هذا المستخدم في <ProfileLink>صفحة ملف التعريف</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{متبقي, plural, =0 {No} other {<strong>#</strong>}} {type} {متبقي, plural, one {طلب} other {طلبات}} متبقية\",\n  \"components.RequestModal.QuotaDisplay.season\": \"موسم\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {موسم} other {مواسم}}\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"هذا المستخدم يحتاج أن يملك على الاقل <strong>{seasons}</strong> {seasons, plural, one {طلب موسم} other {طلبات مواسم}} متبقية/متبقي ليتمكن من طلب هذا المسلسل.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"لم نتمكن من مطابقة هذا المسلسل بشكل تلقائي. الرجاء مطابقة المسلسل الصحيح من القائمة بالإسفل.\",\n  \"components.RequestModal.alreadyrequested\": \"تم طلبه مُسبقاً\",\n  \"components.RequestModal.approve\": \"الموافقة على الطلب\",\n  \"components.RequestModal.autoapproval\": \"موافقة تلقائية\",\n  \"components.RequestModal.cancel\": \"إلغاء الطلب\",\n  \"components.RequestModal.edit\": \"تعديل الطلب\",\n  \"components.RequestModal.errorediting\": \"حدث خطأ ما أثناء محاولة تعديل الطلب.\",\n  \"components.RequestModal.numberofepisodes\": \"# حلقات\",\n  \"components.RequestModal.pending4krequest\": \"طلب فور كي مُعلّق\",\n  \"components.RequestModal.pendingapproval\": \"طلبك معلق بانتظار الموافقة.\",\n  \"components.RequestModal.pendingrequest\": \"طلب مُعلّق\",\n  \"components.ResetPassword.validationpasswordmatch\": \"يجب مطابقة كلمة السر مع تأكيدها\",\n  \"components.RequestModal.requestmovies\": \"طلب {count} {count, plural, one {فيلم} other {أفلام}}\",\n  \"components.ResetPassword.email\": \"عنوان البريد الإلكتروني\",\n  \"components.RequestModal.requestseasons4k\": \"طلب {seasonCount} {seasonCount, plural, one {موسم} other {مواسم}} بجودة فور كي\",\n  \"components.ResetPassword.emailresetlink\": \"رابط إستعادة البريد الإلكتروني\",\n  \"components.ResetPassword.passwordreset\": \"إعادة تعيين كلمة السر\",\n  \"components.ResetPassword.password\": \"كلمة السر\",\n  \"components.ResetPassword.validationemailrequired\": \"يجب عليك تزويد بريد إلكتروني صحيح\",\n  \"components.RequestModal.requestApproved\": \"طلبك لـ <strong>{title}</strong> تمت الموافقة عليه!\",\n  \"components.RequestModal.requestCancel\": \"طلبك لـ <strong>{title}</strong> تم إلغاءه.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> تم الطلب بنجاح!\",\n  \"components.RequestModal.requestadmin\": \"هذا الطلب سيتم الموافقة عليه بشكل تلقائي.\",\n  \"components.RequestModal.requestcancelled\": \"الطلب لـ <strong>{title}</strong> تم إلغاءه.\",\n  \"components.RequestModal.requestedited\": \"الطلب لـ <strong>{title}</strong> تم تعديله بنجاح!\",\n  \"components.RequestModal.requesterror\": \"حدث خطأ ما أثناء تأكيد الطلب.\",\n  \"components.RequestModal.requestfrom\": \"{username} طلب هذا المستخدم معلق بانتظار الموافقة.\",\n  \"components.RequestModal.requestmovies4k\": \"طلب {count} {count, plural, one {فيلم} other {أفلام}} بجودة فور كي\",\n  \"components.RequestModal.requestseasons\": \"طلب {seasonCount} {seasonCount, plural, one {موسم} other {مواسم}}\",\n  \"components.RequestModal.season\": \"موسم\",\n  \"components.RequestModal.seasonnumber\": \"موسم {number}\",\n  \"components.RequestModal.selectmovies\": \"إختيار فيلم /أفلام\",\n  \"components.RequestModal.selectseason\": \"إختيار موسم/مواسم\",\n  \"components.ResetPassword.confirmpassword\": \"تأكيد كلمة السر\",\n  \"components.ResetPassword.gobacklogin\": \"العودة لصفحة تسجيل الدخول\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"رابط إستعادة كلمة السر سيتم إرساله للبريد الإلكتروني المذكور إذا كان مرتبطا بمستخدم صحيح.\",\n  \"components.ResetPassword.resetpassword\": \"إعادة تعيين كلمة السر\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"تم تغيير كلمة السر بنجاح!\",\n  \"components.ResetPassword.validationpasswordminchars\": \"كلمة السر قصيرة جدا؛ الحد الأدنى ثمانية خانات\",\n  \"components.ResetPassword.validationpasswordrequired\": \"يجب عليك كتابة كلمة سر\",\n  \"components.Search.search\": \"بحث\",\n  \"components.Search.searchresults\": \"نتائج البحث\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"تفعيل الخدمة\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"فشل حفظ إعدادات تنبيه خدمه قونتفاي.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"تم حفظ اعدادات خدمة تنبيه قونتفاي بنجاح!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"فشل إرسال تنبيه تجريبي لخدمة قونتفاي.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"إرسال تنبيه تجريبي لقونتفاي…\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"مفتاح التطبيق (Token)\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"عنوان السيرفر\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"يجب عليك كتابة مفتاح التطبيق\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"يجب عليك إختيار نوع تنبيه واحد على الأقل\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"تم إرسال تنبيه تجريبي لقونتفاي!\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"يجب عليك كتابة رابط صحيح\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"الرابط يجب أن لا ينتهي بعلامة السلاش /\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"مفتاح الدخول Token\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"جاري ارسال التنبيه…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"فشل إرسال تنبيه تجريبي Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"تم إرسال تنبيه إختبار Pushbullet!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"يجب إختيار نوع تنبيه واحد على الأقل\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"تم إرسال تنبيه إختبار Pushover!\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"يجب ذكر application Token صحيح\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"يجب ذكر Access Token\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"الثلاثين خانة الخاصة بـ <UsersGroupsLink>بمعرف المستخدم او المجموعة </UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"اعادة تعيين\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"تم ارسال تنبيه تجريبي بنجاح!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"فشل حفظ إعدادات تنبيه webkook.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"تم حفظ الاعدادات!\",\n  \"components.Settings.Notifications.agentenabled\": \"تفعيل الخدمة\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"عمل مفتاح من <PushbulletSettingsLink>اعدادات الحساب</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"تفعيل الخدمة\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"علامة القناة\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"فشل حفظ إعدادات تنبيه Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"تم حفظ إعدادات تنبيه pushb6 بنجاح!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"جاري الإرسال…\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"مفتاح التطبيق API\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>تسجيل تطبيق</ApplicationRegistrationLink> لاستخدامه مع اوفرسيرر\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"تفعيل الخدمة\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"فشل حفظ إعدادات تنبيه Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"تم حفظ إعدادات تنبيه Pushover!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"فشل إرسال تنبيه تجريبي.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"جاري الإرسال…\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"مفتاح مستخدم أو مجموعة\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"يجب عليك اختيار نوع تنبيه واحد على الاقل\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"يجب ذكر مفتاح مستخدم أو مجموعة صحيح\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"تفعيل الخدمة\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"فشل حفظ إعدادات تنبيه Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"تم حفظ الاعدادات بنجاح!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"فشل ارسال تنبيه تجريبي.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"جاري ارسال تنبيه Slack تجريبي…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"تم ارسال تنبيه تجريبي!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"يجب عليك اختيار نوع تنبيه\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"الرجاء تزويد رابط صحيح\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"رابط webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"إنشاء <WebhookLink>Incoming Webhook</WebhookLink> integration\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"تفعيل الخدمة\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"لاستقبال تنبيهات بواسطة push , اوفرسيرر يجب ان يكون يعمل من خلال HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"فشل ارسال التنبيه.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"تم الارسال!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"فشل حفظ إعدادات تنبيه web push.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"تم حفظ الاعدادات بنجاح!\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"تفعيل الخدمة\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"صلاحيات Header\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON Payload جيسون\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"تم اعادة تعيين JSON payload بنجاح!\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"\\\"Template Variable Help\\\"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"فشل ارسال تنبيه تجريبي.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"جاري ارسال تنبيه webhook تجريبي…\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"يجب عليك كتابة رابط صحيح\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"يجب عليك اختيار نوع تنبيه واحد على الاقل\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"يجب عليك كتابة رابط صحيح\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"رابط \\\"Webhook URL\",\n  \"components.Settings.Notifications.allowselfsigned\": \"السماح بالشهادة الشخصية الموقعة\",\n  \"components.Settings.Notifications.authPass\": \"SMTP كلمة سر\",\n  \"components.Settings.Notifications.authUser\": \"اسم مستخدم SMPT\",\n  \"components.Settings.Notifications.botAPI\": \"مفتاح تصريح البوت token\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>انشاء بوت</CreateBotLink> لاستخدامه مع اوفرسيرر\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"رابط صورة البوت\",\n  \"components.Settings.Notifications.botUsername\": \"اسم البوت\",\n  \"components.Settings.Notifications.botUsernameTip\": \"اسمح للمستخدمين ببدء محادثة مع بوتك الخاص وضبط اعدادات التنبيه الخاصة بهم\",\n  \"components.Settings.Notifications.chatId\": \"عنوان المحادثة\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"تم حفظ الاعدادات بنجاح!\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"تم حفظ اعدادات تنبيه الايميل بنجاح!\",\n  \"components.Settings.Notifications.encryptionDefault\": \"استخدم STARTTLS اذا كان متاحا\",\n  \"components.Settings.Notifications.chatIdTip\": \"ابدأ محادثة مع البوت، أضف<GetIdBotLink>@get_id_bot</GetIdBotLink>, and و أعط <code>/my_id</code> الأمر\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"فشل حفظ اعدادات تنبيه الديسكورد.\",\n  \"components.Settings.Notifications.emailsender\": \"عنوان المرسل\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"فشل حفظ اعدادات تنبيه الايميل.\",\n  \"components.Settings.Notifications.enableMentions\": \"تفعيل التخصيص \\\"Mention\\\"\",\n  \"components.Settings.Notifications.encryption\": \"وضع التشفير\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"استخدم STARTTLS دائما\",\n  \"components.Settings.Notifications.encryptionTip\": \"في معظم الحالات، يستخدم Implicit TLS منفذ 465 و STARTTLS يستخدم منفذ 587\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"سجل رسائل الايميل المشفرة باستخدام<OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.sendSilently\": \"أرسل بشكل صامت\",\n  \"components.Settings.Notifications.senderName\": \"اسم المرسل\",\n  \"components.Settings.Notifications.pgpPassword\": \"كلمة سر PGP\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"رمز PGP الخاص\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"أرسل التنبيهات بدون صوت\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"سجل رسائل الايميل المشفرة باستخدام<OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.smtpPort\": \"منفذ SMTP\",\n  \"components.Settings.Notifications.smtpHost\": \"مضيف SMPT\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"فشل حفظ اعدادات تنبيه التليقرام.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"تم حفظ إعدادات التليقرام بنجاح!\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"فشل ارسال تنبيه الديسكورد التجريبي.\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"فشل ارسال التنبيه التجريبي للتليقرام.\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"تم ارسال التنبيه!\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"جاري ارسال تنبيه تجريبي للديسكورد…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"تم ارسال التنبيه!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"فشل ارسال تنبيه تجريبي للإيميل.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"جاري ارسال تنبيه تجريبي للايميل…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"تم ارسال التنبيه!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"جاري ارسال تنبيه تجريبي للتليقرام…\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"يجب عليك ذكر مفتاح تصريح البوت \\\"Token\\\"\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"يجب عليك ذكر عنوان دردشة صحيح\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"يجب عليك كتابة كلمة سر PGP\",\n  \"components.Settings.Notifications.validationEmail\": \"يجب عليك كتابة عنوان بريد صحيح\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"يجب ذكر عنوان مضيف أو أي بي صحيح\",\n  \"components.Settings.Notifications.validationTypes\": \"يجب اختيار نوع تنبيه واحد على الأقل\",\n  \"components.Settings.Notifications.webhookUrl\": \"رابط WEbhook\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"يجب عليك كتابة المفتاح الخاص الصحيح ب PGP\",\n  \"components.Settings.RadarrModal.add\": \"إضافة سيرفر\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"يجب ذكر رقم منفذ صحيح\",\n  \"components.Settings.Notifications.validationUrl\": \"يجب ذكر عنوان URL صحيح\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"إنشاء <DiscordWebhookLink>webhook integration</DiscordWebhookLink> للسيرفر الخاص بك\",\n  \"components.Settings.RadarrModal.announced\": \"تم الإعلان عنه\",\n  \"components.Settings.RadarrModal.apiKey\": \"مفتاح API\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"استخدم Implicit TLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"غير محدد\",\n  \"components.Settings.RadarrModal.defaultserver\": \"السيرفر الافتراضي\",\n  \"components.Settings.RadarrModal.enableSearch\": \"تفعيل البحث التلقائي\",\n  \"components.Settings.RadarrModal.externalUrl\": \"عنوان الارتباط الخارجي\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"ملف تعريف الجودة\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"جاري تحميل مجلدات الحفظ…\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"إختار مجلد الحفظ\",\n  \"components.Settings.RadarrModal.baseUrl\": \"عنوان الارتباط \\\"URL \\\"\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"إضافة سيرفر رادار جديد \\\"خاص بالفور كي\\\"\",\n  \"components.Settings.RadarrModal.createradarr\": \"إضافة سيرفر رادار جديد\",\n  \"components.Settings.RadarrModal.default4kserver\": \"سيرفر الفور كي الافتراضي\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"تعديل سيرفر رادار الخاص بالفور كي\",\n  \"components.Settings.RadarrModal.editradarr\": \"تعديل سيرفر رادار\",\n  \"components.Settings.RadarrModal.hostname\": \"عنوان المضيف أو رقم الأي بي\",\n  \"components.Settings.RadarrModal.inCinemas\": \"متوفر بالسينما\",\n  \"components.Settings.RadarrModal.loadingTags\": \"جاري تحميل علامات التعريف…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"جاري تحميل ملفات تعريف الجودة…\",\n  \"components.Settings.RadarrModal.notagoptions\": \"لا يوجد علامات تعريف.\",\n  \"components.Settings.RadarrModal.port\": \"المنفذ\",\n  \"components.Settings.RadarrModal.released\": \"تم إصداره\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"الحالة الأدنى للتوفر\",\n  \"components.Settings.RadarrModal.rootfolder\": \"مجلد الحفظ\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"إختار الحالة الأدنى للتوفر\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"إختار ملف تعريف الجودة\",\n  \"components.Settings.RadarrModal.selecttags\": \"إختار علامات التعريف\",\n  \"components.Settings.RadarrModal.server4k\": \"سيرفر جودة الفور كي\",\n  \"components.Settings.RadarrModal.servername\": \"اسم السيرفر\",\n  \"components.Settings.RadarrModal.ssl\": \"استخدم SSL\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"يجب اختيار ملف تعريف للجودة\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"يجب اختيار مجلد الحفظ\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"الحالي\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"الأحدث\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"بيانات الاصدار غير متوفرة حاليا.\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"إصدارات\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"تفعيل البحث\",\n  \"components.Settings.RadarrModal.tags\": \"علامات التعريف\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"اختبار الاتصال لتحميل ملفات تعريف الجودة\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"اختبار الاتصال لتحميل مجلدات الحفظ\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"اختبار الاتصال لتحميل العلامات\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"فشل الاتصال برادار.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"تم انشاء الاتصال برادار بنجاح!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"يجب عليك كتابة مفتاح API صحيح\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"يجب عليك كتابة عنوان ارتباط صحيح\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"عنوان الارتباط يجب لا ينتهي بعلامة السلاش /\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"يجب لا ينتهي عنوان الارتباط الاساسي بعلامة السلاش\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"عنوان الارتباط الاساسي يجب ان يحتوي على علامة سلاش توضيحية \\\"غالبا بمنتصف كلمتين او بالبداية\\\"\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"يجب كتابة عنوان مضيف أو رقم اي بي صحيح\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"يجب اختيار المستوى الادنى للتوفر\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"يجب اختيار اسم سيرفر\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"يجب كتابة رقم منفذ صحيح\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} سجل التحسينات\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"الاطلاع على سجل التحسينات\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"رؤية المحتوى على GitHub\",\n  \"components.Settings.SettingsAbout.about\": \"حول\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"مكان تخزين البيانات\",\n  \"components.Settings.SettingsAbout.documentation\": \"الوثائق\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"الحصول على دعم\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"نقاشات GitHub\",\n  \"components.Settings.SettingsAbout.outofdate\": \"غير محدث\",\n  \"components.Settings.SettingsJobsCache.cache\": \"الملفات المؤقتة\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"المجموع الكلي للمحتوى\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"مجموع الطلبات\",\n  \"components.Settings.SettingsAbout.version\": \"النسخة\",\n  \"components.Settings.SettingsAbout.uptodate\": \"مُحدّث\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"أوفرسيرر يخزن ملفات مؤقته متعلقه بالمفاتيح الخارجية API لتحسين الاداء وتفادي ارسال طلبات اتصال متكررة.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"تم محو الملف المخزّن.\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"مجموع المفاتيح\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"الغاء الطلب\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"اسم ملفات التخزين\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"الحجم الكلي\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"انت تستخدم نسخة تجريبية <code>develop</code> branch of Seerr, النسخة مستحسنه فقط للمساهمين بتطوير التطبيق او المساعدين باختبار النسخ التجريبية.\",\n  \"components.Settings.SettingsAbout.timezone\": \"المنطقة الزمنية\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Hits،\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"حجم المفاتيح\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"مفقودات\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"السماح لمستخدمين بليكس بتسجيل الدخول دون الحاجة لدمجهم في أوفرسيرر\",\n  \"components.Settings.SonarrModal.animeTags\": \"علامات تعريف الإنمي\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"كل {jobScheduleMinutes, plural, one {دقيقة} other {{jobScheduleMinutes} دقائق}}\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"حدث خطأ ما اثناء حفظ المهمة.\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"أوفرسيرر يعمل على جدولة بعض مهام الصيانة بشكل دوري ولكن بالإمكان عمل هذه المهام بشكل يدوي من القائمة بالإسفل. عمل اي مهمة بشكل يدوي لن يأثر على جدولتها التلقائية.\",\n  \"components.Settings.SettingsLogs.message\": \"الرسائل\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"مهمة غير معروفه\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"استئناف\",\n  \"components.Settings.SettingsLogs.showall\": \"إظهار كل السجلات\",\n  \"components.Settings.SettingsLogs.logs\": \"السجلات\",\n  \"components.Settings.SonarrModal.baseUrl\": \"عنوان الارتباط URL BASE\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"إضافة سيرفر سونارر لجودة الفور كي\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"جاري تحميل ملفات تعريف اللغة…\",\n  \"components.Settings.SonarrModal.loadingTags\": \"جاري تحميل علامات التعريف…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"جاري تحميل ملفات تعريف الجودة…\",\n  \"components.Settings.SettingsJobsCache.command\": \"أمر\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"تحميل الدمج\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"تحميل إعادة تعيين الدمج\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"تعديل المهمة\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"مّعدل جديد\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"كل {jobScheduleHours, plural, one {ساعة} other {{jobScheduleHours} ساعات}}\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"محو الملفات المؤقتة\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"تم تعديل المهمة بنجاح!\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} تم إلغاء هذه المهمة.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"إسم المهمة\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"المهام\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"المهام والملفات المؤقته\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} بدأ عمل هذه المهمة.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"النوع\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"وقت التنفيذ التالي\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"الفحص الكلي لمكتبة بليكس\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"فحص المحتويات المضافة مؤخرا على بليكس\",\n  \"components.Settings.SettingsJobsCache.process\": \"تنفيذ\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"فحص رادار\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"تنفيذ \\\" الآن \\\"\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"فحص سونار\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"نسخ رسائل السجل.\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"نسخ\",\n  \"components.Settings.SettingsLogs.extraData\": \"بيانات إضافية\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"متابعة عميقة \\\" Debug \\\"\",\n  \"components.Settings.SettingsLogs.filterError\": \"خطأ\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"معلومات\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"تحذير\",\n  \"components.Settings.SettingsLogs.label\": \"ملصق\",\n  \"components.Settings.SettingsLogs.level\": \"الحدة\",\n  \"components.Settings.SettingsLogs.logDetails\": \"تفاصيل السجلات\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"تستطيع الإطلاع على هذه السجلات ايضا من خلال <code>stdout</code>, أو في <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"ايقاف مؤقت\",\n  \"components.Settings.SettingsLogs.time\": \"الختم الزمني\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"الاذونات الافتراضية\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"الإذونات الأساسية للمستخدمين الجدد\",\n  \"components.Settings.SettingsUsers.localLogin\": \"تفعيل تسجيل الدخول محليا\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"السماح للمستخدمين بتسجيل الدخول بإستخدام البريد الإلكتروني وكلمة السر بدل التصادق مع بليكس\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"الحد الأعلى لطلبات الأفلام ( تعيين عام )\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"تفعيل تسجيل الدخول لمستخدمين بليكس الجدد\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"حدث خطأ ما أثناء حفظ الإعدادات.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"تم حفظ إعدادات المستخدم بنجاح!\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"الحد الأعلى لطلبات المسلسلات \\\"تعيين عام\\\"\",\n  \"components.Settings.SettingsUsers.userSettings\": \"إعدادات المستخدم\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"ضبط إعدادت المستخدم العامة والإفتراضية.\",\n  \"components.Settings.SettingsUsers.users\": \"المستخدمين\",\n  \"components.Settings.SonarrModal.add\": \"إضافة سيرفر\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"ملف تعريف اللغة للإنمي\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"ملف تعريف الجودة للإنمي\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"مجلد حفظ الإنمي\",\n  \"components.Settings.SonarrModal.apiKey\": \"مفتاح API\",\n  \"components.Settings.SonarrModal.createsonarr\": \"إضافة سيرفر سونار جديد\",\n  \"components.Settings.SonarrModal.default4kserver\": \"سيرفر الفور كي الافتراضي\",\n  \"components.Settings.SonarrModal.defaultserver\": \"السيرفر الافتراضي\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"تعديل سيرفر سونارر لجودة الفور كي\",\n  \"components.Settings.SonarrModal.editsonarr\": \"تعديل سيرفر سونار\",\n  \"components.Settings.SonarrModal.enableSearch\": \"تفعيل البحث التلقائي\",\n  \"components.Settings.SonarrModal.externalUrl\": \"عنوان الارتباط الخارجي\",\n  \"components.Settings.SonarrModal.hostname\": \"إسم المضيف أو رقم الأي بي\",\n  \"components.Settings.SonarrModal.languageprofile\": \"ملف تعريف اللغة\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"جاري تحميل مجلدات الحفظ…\",\n  \"components.Settings.SonarrModal.notagoptions\": \"لا يوجد علامات تعريف.\",\n  \"components.Settings.SonarrModal.port\": \"المنفذ\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"ملفات تعريف الجودة\",\n  \"components.Settings.SonarrModal.rootfolder\": \"مجلد الحفظ\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"مجلدات المواسم\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"إختار ملف تعريف اللغة\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"إختار ملف تعريف الجودة\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"إختار مجلد الحفظ\",\n  \"components.Settings.SonarrModal.selecttags\": \"إختار علامات التعريف\",\n  \"components.Settings.menuGeneralSettings\": \"عام\",\n  \"components.Settings.manualscanDescription\": \"عادةً٫ سيتم عمل هذا الفحص مرة واحدة كل 24 ساعة. أوفرسيرر سيفحص المحتوى المضاف مؤخرا في مكتبة بليكس بشكل مكثف. إذا كانت هذه المرة الأولى التي تقوم بها بإعداد بليكس يستحسن أن تقوم بعمل فحص يدوي كامل لمرة واحدة!\",\n  \"components.Settings.menuAbout\": \"حول\",\n  \"components.Settings.plex\": \"بليكس\",\n  \"components.Settings.plexlibraries\": \"مكتبات بليكس\",\n  \"components.Settings.noDefaultServer\": \"على الأقل {serverType} سيرفر واحد يجب أن يكون معدا كإفتراضي لإتاحة تنفيذ طلبات الـ {mediaType}.\",\n  \"components.Settings.plexsettings\": \"إعدادات بليكس\",\n  \"components.Settings.serviceSettingsDescription\": \"قم بإعداد {serverType} بالإسفل.تستطيع الاتصال بأكثر من سيرفر {serverType} ,ولكن إثنان فقط يمكن إعدادهما كإفتراضيين (واحد لجودة الفور كي والأخر لغير جودة الفور كي). أصحاب الصلاحيات الإدارية بإمكانهم تجاوز السيرفر المستخدم قبل تأكيدهم لأي طلب محتوى جديد.\",\n  \"components.Settings.serverpresetManualMessage\": \"ضبط يدوي\",\n  \"components.Settings.sonarrsettings\": \"إعدادات سونار\",\n  \"components.Settings.tautulliSettingsDescription\": \"بشكل إختياري أضبط إعدادات سيرفرك الخاص بـ Tautulli.أوفرسيرر سيقوم بجلب بيانات سجل المشاهدة لمحتوى بليكس من Tautulli.\",\n  \"components.Settings.webhook\": \"ويب هوك Webhook\",\n  \"components.Settings.webpush\": \"ويب بوش Web Push\",\n  \"components.Settings.SonarrModal.server4k\": \"سيرفر جودة الفور كي\",\n  \"components.Settings.SonarrModal.servername\": \"إسم السيرفر\",\n  \"components.Settings.SonarrModal.ssl\": \"إستخدم SSL\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"تفعيل الفحص\",\n  \"components.Settings.SonarrModal.tags\": \"علامات التعريف\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"إختبار الإتصال لتحميل ملفات تعريف اللغة\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"إختبار الإتصال لتحميل ملفات تعريف الجودة\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"إختبار الإتصال لتحميل مجلدات الحفظ\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"إختبار الإتصال لتحميل العلامات\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"فشل الإتصال بـ سونار.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"تم الإتصال بـ سونار بنجاح!\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"يجب ذكر مفتاح API\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"يجب ذكر عنوان إرتباط صحيح\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"أساس عنوان الإرتباط يجب أن يحتوي على علامة السلاش\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"أساس عنوان الإرتباط يجب أن لا يُختتم بعلامة السلاش\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"عنوان الإرتباط يجب أن لا يخُتتم بعلامة السلاش\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"يجب كتابة عنوان مضيف أو رقم أي بي صحيح\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"يجب إختيار ملف تعريف جودة\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"يجب كتابة إسم السيرفر\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"يجب ذكر رقم منفذ صحيح\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"يجب إختيار ملف تعريف جودة\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"يجب إختيار مجلد حفظ\",\n  \"components.Settings.activeProfile\": \"ملف تعريف نشِط\",\n  \"components.Settings.addradarr\": \"إضافة سيرفر رادار\",\n  \"components.Settings.address\": \"العناوين\",\n  \"components.Settings.addsonarr\": \"إضافة سيرفر سونار\",\n  \"components.Settings.cancelscan\": \"إلغاء الفحص\",\n  \"components.Settings.currentlibrary\": \"المكتبة الحالية: {name}\",\n  \"components.Settings.default\": \"الإفتراضي\",\n  \"components.Settings.default4k\": \"فور كي الإفتراضي\",\n  \"components.Settings.deleteserverconfirm\": \"هل أنت متأكد من حذف هذا السيرفر؟\",\n  \"components.Settings.email\": \"البريد الإلكترونيّ\",\n  \"components.Settings.enablessl\": \"إستخدم SSL\",\n  \"components.Settings.externalUrl\": \"عنوان الإرتباط الخارجي\",\n  \"components.Settings.hostname\": \"عنوان المضيف أو رقم الأي بي\",\n  \"components.Settings.is4k\": \"فور كي\",\n  \"components.Settings.librariesRemaining\": \"المكتبات المتبقية: {count}\",\n  \"components.Settings.manualscan\": \"فحص يدوي للمكتبة\",\n  \"components.Settings.mediaTypeMovie\": \"فِيلم\",\n  \"components.Settings.mediaTypeSeries\": \"مسلسل\",\n  \"components.Settings.menuJobs\": \"المهام والملفات المؤقتة\",\n  \"components.Settings.menuLogs\": \"السجلات\",\n  \"components.Settings.menuNotifications\": \"التنبيهات\",\n  \"components.Settings.menuPlexSettings\": \"بليكس\",\n  \"components.Settings.menuServices\": \"الخدمات\",\n  \"components.Settings.menuUsers\": \"المستخدمين\",\n  \"components.Settings.noDefault4kServer\": \"سيرفر {serverType} مخصص للفور كي يجب أن يكون معدا كإفتراضي لتمكين المستخدمين من طلب محتويات الفور كي لـ {mediaType}.\",\n  \"components.Settings.noDefaultNon4kServer\": \"إذا لم يكن لديك سوى سيرفر واحد {serverType} مخصص لكل المحتوى الفور كي وغير الفور كي (أو أنك لا تقوم بتحميل سوى محتوى الفور كي), سيرفرك {serverType} يجب <strong>أن لا</strong> يكون معدا بشكل مخصص لمحتوى الفور كي.\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"ضبط وتفعيل خدمات التنبيهات.\",\n  \"components.Settings.notifications\": \"التنبيهات\",\n  \"components.Settings.notificationsettings\": \"اعدادات التنبيهات\",\n  \"components.Settings.notrunning\": \"لا يعمل\",\n  \"components.Settings.plexlibrariesDescription\": \"المكتبات التي سيقوم أوفرسيرر بفحصها. قم بإعداد وحفظ إعدادات الإتصال ببليكس ثم قم بالضغط على الزر بالإسفل اذا لم تظهر مكتبات بليكس بالقائمة.\",\n  \"components.Settings.plexsettingsDescription\": \"ضبط إعدادات سيرفر بليكس. أوفرسيرر سيفحص مكتبات بليكس للتأكد من توفر المحتوى من عدمه.\",\n  \"components.Settings.port\": \"المنفذ\",\n  \"components.Settings.radarrsettings\": \"إعدادات رادار\",\n  \"components.Settings.scan\": \"دمج المكتبات\",\n  \"components.Settings.scanning\": \"جاري الدمج…\",\n  \"components.Settings.serverLocal\": \"محلي\",\n  \"components.Settings.serverRemote\": \"عن بعد\",\n  \"components.Settings.serverSecure\": \"أمن\",\n  \"components.Settings.serverpreset\": \"سيرفر\",\n  \"components.Settings.serverpresetLoad\": \"اضغط على الزر لتحميل السيرفرات المتاحة\",\n  \"components.Settings.serverpresetRefreshing\": \"جاري جلب السيرفرات…\",\n  \"components.Settings.services\": \"الخدمات\",\n  \"components.Settings.settingUpPlexDescription\": \"لإعداد بليكس٫ تستطيع كتابة التفاصيل بشكل يدوي أو إختيار السيرفر جلب السيرفر منretrieved from <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. إضغط على الزر يمين القائمة المنسدلة لجلب قائمة السيرفرات المتاحة.\",\n  \"components.Settings.ssl\": \"إتصال SSL\",\n  \"components.Settings.startscan\": \"إبدأ الفحص\",\n  \"components.Settings.tautulliApiKey\": \"مفتاح API\",\n  \"components.Settings.tautulliSettings\": \"إعدادات Tautulli\",\n  \"components.Settings.toastPlexConnecting\": \"جاري محاولة الإتصال ببليكس…\",\n  \"components.Settings.toastPlexConnectingFailure\": \"فشل الإتصال ببليكس.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"تم الإتصال ببليكس بنجاح!\",\n  \"components.Settings.toastPlexRefresh\": \"جاري جلب قائمة السيرفرات من بليكس…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"فشل جلب قائمة السيرفرات.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"تم جلب قائمة السيرفرات من بليكس بنجاح!\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"حدث خطأ ما أثناء حفظ إعدادات Tautulli.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"تم حفظ إعدادات Tautulli بنجاح !\",\n  \"components.Settings.urlBase\": \"عنوان الإرتباط الأساسي\",\n  \"components.Settings.validationApiKey\": \"يجب كتابة مفتاح API\",\n  \"components.Settings.validationHostnameRequired\": \"يجب كتابة إسم مضيف أو رقم أي بي صحيح\",\n  \"components.Settings.validationPortRequired\": \"يجب كتابة رقم منفذ صحيح\",\n  \"components.Settings.validationUrl\": \"يجب كتابة عنوان ارتباط صحيح\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"عنوان الارتباط الأساسي يجب أن يحتوي على علامة السلاش\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"عنوان الإرتباط الأساسي يجب أن لا ينتهي بعلامة السلاش\",\n  \"components.Settings.validationUrlTrailingSlash\": \"عنوان الإرتباط يجب أن لا ينتهي بعلامة السلاش\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Web App</WebAppLink> عنوان الارتباط\",\n  \"components.Settings.webAppUrlTip\": \"بشكل إختياري توجيه المستخدمين لصفحة ويب التطبيق في سيرفرك بدل صفحة ويب التطبيق المستضاف\",\n  \"components.Setup.configureservices\": \"إعداد الخدمات\",\n  \"components.Setup.continue\": \"إستمرار\",\n  \"components.Setup.finish\": \"إنهاء الإعداد\",\n  \"components.Setup.finishing\": \"جاري الإنهاء…\",\n  \"components.UserList.userdeleted\": \"تم حذف المستخدم بنجاح!\",\n  \"components.UserList.users\": \"المستخدمين\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# موسم} other {# مواسم}}\",\n  \"components.TvDetails.showtype\": \"نوُع المسلسل\",\n  \"components.UserList.accounttype\": \"نوع العضويّة\",\n  \"components.UserList.admin\": \"مسؤول\",\n  \"components.TvDetails.cast\": \"الطاقم\",\n  \"components.TvDetails.streamingproviders\": \"يعرض حاليا على\",\n  \"components.UserList.deleteuser\": \"حذف المستخدم\",\n  \"components.UserList.importfromplex\": \"جلب مستخدمين بليكس\",\n  \"components.UserList.localuser\": \"مستخدم محلي\",\n  \"components.UserList.newplexsigninenabled\": \"<strong>خاصية تفعيل تسجيل دخول مستخدم جديد من بليكس</strong>مفعلة حاليا. مستخدمين بليكس الذين لديهم صلاحية الإطلاع على مكتبة بليكس لا يحتاجون لان يتم جلبهم ليتمكنوا من تسجيل الدخول.\",\n  \"components.UserProfile.ProfileHeader.settings\": \"تعديل الإعدادات\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"نوع الحساب\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"مسؤول\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"لغة العرض\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"تصفية المحتوى بحسب توفره بالمنطقة\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"يجب ذكر رقم مستخدم ديسكورد صحيح\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"تم حفظ إعدادات تنيه الديسكورد بنجاح!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"إعدادات التنبيه\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"فشل حفظ إعدادات تنبيه Pushbullet.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>تسجيل تطبيق application</ApplicationRegistrationLink> للإستخدام مع {applicationTitle}\",\n  \"i18n.approve\": \"موافقة\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"يجب ذكر مفتاح عام PGP صحيح\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"كلمة سر جديد\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"لا تستطيع تعديل صلاحياتك المُعطاة.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"حساب هذا المستخدم بدون كلمة سر حاليا. قم بإعداد كلمة سر بالإسفل لإتاحة هذا الحساب من تسجيل الدخول \\\"كمستخدم محلي.\\\"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"تم حفظ كلمة السر بنجاح!\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"لا تملك الصلاحية لتعديل إعدادات هذا المستخدم.\",\n  \"components.UserProfile.totalrequests\": \"مجموع الطلبات\",\n  \"i18n.deleting\": \"جاري الحذف…\",\n  \"i18n.delete\": \"حذف\",\n  \"i18n.requesting\": \"جاري الطلب…\",\n  \"pages.somethingwentwrong\": \"حدث خطأ ما\",\n  \"components.Setup.setup\": \"الإعداد\",\n  \"components.Setup.signinMessage\": \"إبدأ من خلال تسجيل دخولك بحساب بليكس\",\n  \"components.Setup.welcome\": \"مرحبا بك في أوفرسيرر\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.StatusBadge.status4k\": \"فور كي {status}\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"طاقم عمل المسلسل\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"طاقم فريق المسلسل\",\n  \"components.TvDetails.anime\": \"إنمي\",\n  \"components.TvDetails.episodeRuntime\": \"مدة عرض الحلقة\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} دقيقة\",\n  \"components.TvDetails.firstAirDate\": \"تاريخ العرض الأول\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {شبكة البث} other {شبكات البث}}\",\n  \"components.TvDetails.nextAirDate\": \"تاريخ العرض التالي\",\n  \"components.TvDetails.originallanguage\": \"اللغة الأصلية\",\n  \"components.TvDetails.originaltitle\": \"العنوان الأصلي\",\n  \"components.TvDetails.overview\": \"نظرة عامة\",\n  \"components.TvDetails.overviewunavailable\": \"النظرة العامة غير متاحة.\",\n  \"components.TvDetails.productioncountries\": \"إنتاج {countryCount, plural, one {الدولة} other {الدول}}\",\n  \"components.TvDetails.recommendations\": \"التوصيات\",\n  \"components.TvDetails.similar\": \"مسلسلات مشابهه\",\n  \"components.TvDetails.viewfullcrew\": \"رؤية طاقم العمل\",\n  \"components.TvDetails.watchtrailer\": \"شاهد الإعلان\",\n  \"components.UserList.autogeneratepassword\": \"إنشاء كلمة سر بشكل تلقائي\",\n  \"components.UserList.autogeneratepasswordTip\": \"أرسل كلمة السر المنشئة الى إيميل المستخدم\",\n  \"components.UserList.bulkedit\": \"تعديل شامل ( للمحدد )\",\n  \"components.UserList.create\": \"إنشاء\",\n  \"components.UserList.created\": \"تاريخ الإنضمامْ\",\n  \"components.UserList.createlocaluser\": \"إنشاء مستخدم محلي\",\n  \"components.UserList.creating\": \"جاري الإنشاء…\",\n  \"components.UserList.deleteconfirm\": \"هل أنت متأكد من حذف هذا المستخدم؟ كل الطلبات التي تم إنشاءها من خلاله سيتم حذفها بشكل نهائي.\",\n  \"components.UserList.edituser\": \"تعديل صلاحيات المستخدم\",\n  \"components.UserList.email\": \"عنوان البريد الإلكتروني\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {مستخدم} other {مستخدمين}} تم جلبهم بنجاح!\",\n  \"components.UserList.importfromplexerror\": \"حدث خطأ ما أثناء محاولة جلب المستخدمين.\",\n  \"components.UserList.localLoginDisabled\": \"<strong>خاصية تفعيل تسجيل الدخول المحلي</strong> معطلة حاليا.\",\n  \"components.UserList.nouserstoimport\": \"لا يوجد مستخدمين بليكس ليتم جلبهم.\",\n  \"components.UserList.owner\": \"المالك\",\n  \"components.UserList.password\": \"كلمة السر\",\n  \"components.UserList.passwordinfodescription\": \"ضبط عنوان إرتباط التطبيق وتفعيل تنبيهات الإيميل للسماح بإنشاء كلمات سر تلقائية.\",\n  \"components.UserList.plexuser\": \"مستخدم بليكس\",\n  \"components.UserList.role\": \"صلاحيّات الحساب\",\n  \"components.UserList.sortCreated\": \"تاريخ الإنضمام\",\n  \"components.UserList.sortDisplayName\": \"إسم العرض\",\n  \"components.UserList.sortRequests\": \"عدد الطلبات\",\n  \"components.UserList.totalrequests\": \"الطلبات\",\n  \"components.UserList.user\": \"مُستخدم/عضو\",\n  \"components.UserList.usercreatedfailed\": \"حدث خطأ ما أثناء إنشاء المستخدم.\",\n  \"components.UserList.usercreatedfailedexisting\": \"عنوان البريد الإلكتروني المزوّد مستعمل من قبل مستخدم أخر.\",\n  \"components.UserList.usercreatedsuccess\": \"تم إنشاء المستخدم بنجاح!\",\n  \"components.UserList.userdeleteerror\": \"حدث خطأ ما أثناء حذف المستخدم.\",\n  \"components.UserList.userfail\": \"حدث خطأ ما أثناء حفظ صلاحيات المستخدم.\",\n  \"components.UserList.userlist\": \"قائمة المستخدمين\",\n  \"components.UserList.userssaved\": \"تم حفظ صلاحيات المستخدم بنجاح!\",\n  \"components.UserList.validationEmail\": \"يجب عليك ذكر عنوان بريد إلكتروني صحيح\",\n  \"components.UserList.validationpasswordminchars\": \"كلمة السر قصيرة جدا؛ الحد الأدنى 8 خانات\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"منضم {joindate}\",\n  \"components.UserProfile.ProfileHeader.profile\": \"رؤية ملف التعريف\",\n  \"components.UserProfile.ProfileHeader.userid\": \"رقم المستخدم: {userid}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"رقم ديسكورد المستخدم\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"<FindDiscordIdLink>رقم متعدد الخانات</FindDiscordIdLink> مرتبط بحساب عضوية الديسكورد\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"إسم العرض\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"تجاوز الحد العام\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"عام\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"الإعدادات العامة\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"الإفتراضي ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"مستخدم محلي\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"الحد الأقصى لطلبات الأفلام\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"لغة العرض الخاصة بـ إكتشف محتوى جديد\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"تصفية المحتوى بحسب اللغة الأصلية\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"المالك\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"مستخدم بليكس\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"المنطقة لـ إكتشف محتوى جديد\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"صلاحيّات الحساب\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"الحد الأقصى لطلبات المسلسلات\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"حدث خطأ ما أثناء حفظ الإعدادات.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"تم حفظ الإعدادات بنجاح!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"مستخدم\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"رقم عضوية المستخدم\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"ة <FindDiscordIdLink>رقم متعدد الخانات</FindDiscordIdLink> مرتبط بحساب المستخدم\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"فشل حفظ إعدادات تنبيه الديسكورد.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"البريد الإلكترونيّ\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"فشل حفظ إعدادات تنبيه الإيميل.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"تم حفظ إعدادات تنبيه الإيميل بنجاح!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"التنبيهات\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"مفتاح PGP العام\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"رسائل إيميل مشفرة باستخدام <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"مفتاح الدخول Token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"إنشاء Token من <PushbulletSettingsLink>إعدادات الحساب </PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"تم حفظ إعدادات تنبيه Pushbullet بنجاح!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"مفتاح التطبيق API Token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"مستخدم أو مفتاح مجموعة\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"الثلاثين خانة الخاصةبـ <UsersGroupsLink>بمعرف المستخدم أو المجموعة </UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"فشل حفظ إعدادات تنبيه Pushover.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"تم حفظ إعدادات تنبيه Pushover بنجاح!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"رقم عضوية المحادثة\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>إبدأ محادثة مع</TelegramBotLink>, قم بإضافة <GetIdBotLink>@get_id_bot</GetIdBotLink>, قم بإرسال الأمر <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"فشل حفظ إعدادات تنبيه التليقرام.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"تم حفظ إعدادات تنبيه التليقرام بنجاح!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"يجب ذكر رقم عضوية مستخدم صحيحة\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"أرسل بصمت\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"ارسال التنبيهات بدون صوت\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"يجب ذكر Access Token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"يجب ذكر Access Token صحيح\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"يجب ذكر مفتاح مستخدم او مجموعة صحيح\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"يجب ذكر رقم هوية محادثة صحيحة\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"ويب بوش Web Push\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"تأكيد كلمة السر\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"كلمة السر الحالية\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"حسابك حاليا بدون كلمة سر. قم بإعداد كلمة سر بالأسفل لإتاحة تسجيل الدخول كـ\\\"مستخدم محلي\\\" بإستخدام البريد الإلكتروني.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"ليس لديك الصلاحية لتعديل كلمة سر هذا المستخدم.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"كلمة السر\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"حدث خطأ ما أثناء حفظ كلمة السر.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"حدث خطأ ما أثناء حفظ كلمة السر. هل كان إدخالك لكلمة السر صحيحا؟\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"يجب تأكيد كلمة السر الجديدة\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"كلمات السر المُدخله يجب أن تتطابق\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"يجب كتابة كلمة السر الحالية\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"يجب كتابة كلمة سر جديدة\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"كلمة السر قصيرة جدا؛ الحد الأدنى ثمانية خانات\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"الصلاحيات\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"حدث خطأ ما أثناء حفظ الإعدادات.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"تم حفظ إعدادات الصلاحيات بنجاح!\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"كلمة السر\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"عام\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"التنبيهات\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"الصلاحيات\",\n  \"components.UserProfile.limit\": \"{remaining} من {limit}\",\n  \"components.UserProfile.movierequests\": \"طلبات الأفلام\",\n  \"components.UserProfile.pastdays\": \"{type} (كل {days} أيام/يوم)\",\n  \"components.UserProfile.recentlywatched\": \"تم مشاهدتها موخرا\",\n  \"components.UserProfile.recentrequests\": \"الطلبات الحديثة\",\n  \"components.UserProfile.requestsperdays\": \"{limit} متبقي\",\n  \"components.UserProfile.seriesrequest\": \"طلبات المسلسلات\",\n  \"components.UserProfile.unlimited\": \"غير محدود\",\n  \"i18n.advanced\": \"متقدم\",\n  \"i18n.all\": \"الكل\",\n  \"i18n.approved\": \"تمت الموافقة عليه\",\n  \"i18n.areyousure\": \"هل أنت متأكد؟\",\n  \"i18n.available\": \"متوفر\",\n  \"i18n.back\": \"عودة\",\n  \"i18n.cancel\": \"إلغاء\",\n  \"i18n.canceling\": \"جاري الإلغاء…\",\n  \"i18n.close\": \"إغلاق\",\n  \"i18n.decline\": \"رفض\",\n  \"i18n.declined\": \"تم رفضه\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.edit\": \"تعديل\",\n  \"i18n.experimental\": \"تحت التجربة\",\n  \"i18n.failed\": \"فشل\",\n  \"i18n.import\": \"إستيراد/جلب\",\n  \"i18n.importing\": \"جاري الإستيراد…\",\n  \"i18n.loading\": \"جاري التحميل…\",\n  \"i18n.movie\": \"فيلِم\",\n  \"i18n.movies\": \"أفلام\",\n  \"i18n.next\": \"التالي\",\n  \"i18n.noresults\": \"لا يوجد نتائج.\",\n  \"i18n.notrequested\": \"لم يتم طلبه\",\n  \"i18n.open\": \"مفتوح\",\n  \"i18n.partiallyavailable\": \"متوفر بشكل جزئي\",\n  \"i18n.pending\": \"معلّق\",\n  \"i18n.previous\": \"السابق\",\n  \"i18n.processing\": \"قيد التنفيذ\",\n  \"i18n.request\": \"طلب\",\n  \"i18n.request4k\": \"طلب بجودة فور كي\",\n  \"i18n.requested\": \"تم طلبه\",\n  \"i18n.resolved\": \"تم الحل\",\n  \"i18n.resultsperpage\": \"عرض {pageSize} نتائج بالصفحة الواحدة\",\n  \"i18n.retry\": \"إعادة محاولة\",\n  \"i18n.retrying\": \"جاري إعادة المحاولة…\",\n  \"i18n.save\": \"حفظ التغييرات\",\n  \"i18n.saving\": \"جاري الحفظ…\",\n  \"i18n.settings\": \"إعدادات\",\n  \"i18n.showingresults\": \"عرض <strong>{from}</strong> الى <strong>{to}</strong> من <strong>{total}</strong> نتائج\",\n  \"i18n.status\": \"الحالة\",\n  \"i18n.test\": \"إختبار\",\n  \"i18n.testing\": \"جاري الإختبار…\",\n  \"i18n.tvshow\": \"مسلسلْ\",\n  \"i18n.tvshows\": \"مسلسلات\",\n  \"i18n.unavailable\": \"غير متاح\",\n  \"i18n.usersettings\": \"إعدادات المستخدم\",\n  \"i18n.view\": \"عرض\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"خطأ سيرفر داخلي\",\n  \"pages.oops\": \"أوبسس\",\n  \"pages.pagenotfound\": \"الصفحة غير متاحة\",\n  \"pages.returnHome\": \"عودة للقائمة الرئيسية\",\n  \"pages.serviceunavailable\": \"الخدمة غير متاحة\",\n  \"components.RequestBlock.languageprofile\": \"لغة ملف التعريف\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"عدد المقيّمين\",\n  \"components.Discover.FilterSlideover.voteCount\": \"عدد المقيمين بين {minValue} و {maxValue}\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"قائمتك الخاصة برغبات بليكس\",\n  \"components.Discover.resetfailed\": \"حدث خطأ ما خلال إعادة ضبط إعدادت (إكتشف) المخصّصة.\",\n  \"components.Discover.resetwarning\": \"إعادة ضبط شرائط المحتوى لوضعها الإفتراضي. سيؤدي هذا أيضًا إلى حذف أي أشرطة محتوى مخصصة!\",\n  \"components.Discover.stopediting\": \"إلغاء التعديل\",\n  \"components.Discover.tmdbmoviekeyword\": \"كلمات بحث رئيسية للأفلام من (TMDB)\",\n  \"components.Discover.studios\": \"إستديوهات الإنتاج\",\n  \"components.Discover.updatesuccess\": \"تم تحديث إعدادات التخصيص لصفحة إكتشف.\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"طلبات الأفلام\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"طلبات المسلسلات\",\n  \"components.MovieDetails.digitalrelease\": \"الإصدار الرقمي\",\n  \"components.MovieDetails.reportissue\": \"قم بالإبلاغ عن مشكلة\",\n  \"components.MovieDetails.rtaudiencescore\": \"تقييم الجمهور من موقع (Rotten Tomatoes)\",\n  \"components.MovieDetails.rtcriticsscore\": \"تقييم النقاد من موقع Rotten Tomatoes\",\n  \"components.RequestCard.declinerequest\": \"رفض الطلب\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"عنوان غير معروف\",\n  \"components.RequestModal.requestseriestitle\": \"طلب مسلسل\",\n  \"components.Selector.searchStudios\": \"بحث بالإستديوهات…\",\n  \"components.Selector.showmore\": \"إظهار المزيد\",\n  \"components.Selector.showless\": \"رؤية تفاصيل أقل\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"دمج توفر المحتويات\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"إسم التطبيق\",\n  \"components.StatusBadge.managemedia\": \"إدارة {mediaType}\",\n  \"i18n.restartRequired\": \"يتطلب إعادة التشغيل\",\n  \"components.TvDetails.rtcriticsscore\": \"تقييم النقاد من موقع Rotten Tomatoes\",\n  \"components.Settings.RadarrModal.tagRequests\": \"رموز تعريف الطلبات\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"بشكل تلقائي إضافة رمز تعريف يحتوي على معرّف المستخدم وإسم العرض الخاص بمقدّم الطلب\",\n  \"components.Settings.SettingsMain.apikey\": \"مفتاح API\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"يجب تقديم عنوان للتطبيق\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"الرابط يجب لا أن ينتهي بعلامة سلاش\",\n  \"components.Settings.SonarrModal.tagRequests\": \"علامات تعريف الطلبات\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"بشكل تلقائي إضافة علامة تعريف مع معرّف المستخدم وإسم العرض الخاص بمقدّم الطلب\",\n  \"components.Settings.restartrequiredTooltip\": \"يجب إعادة تشغيل أوفرسيرر لتفعيل هذه التغييرات\",\n  \"components.TitleCard.tvdbid\": \"معّرف موقع TVDB\",\n  \"components.TvDetails.manageseries\": \"إدارة المسلسل\",\n  \"components.TvDetails.tmdbuserscore\": \"تقييم المستخدمين من موقع TMDB\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"تقديم تلقائي لطلبات المسلسلات\",\n  \"i18n.collection\": \"تجميعة\",\n  \"components.RequestBlock.approve\": \"الموافقة على الطلب\",\n  \"components.RequestBlock.requestedby\": \"تم الطلب من قبل\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"ضبط الإعدادات العامة والإفتراضية بأوفرسيرر.\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} تم التحديث\",\n  \"components.TitleCard.cleardata\": \"محو البيانات\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} غير موجود\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"قائمة الرغبات (watchlist) الخاصة ببليكس\",\n  \"components.RequestList.RequestItem.tvdbid\": \"المعرّف الخاص بموقع TVDB\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"قائمة رغبات بليكس\",\n  \"components.Settings.experimentalTooltip\": \"تفعيل هذا الخيار قد يؤدي الى نتائج غير متوقعة بأداء التطبيق\",\n  \"components.Discover.tmdbtvstreamingservices\": \"شبكات بث المسلسلات من TMDB\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"شبكات بث الأفلام من (TMDB)\",\n  \"components.Layout.UserDropdown.requests\": \"الطلبات\",\n  \"components.MovieDetails.physicalrelease\": \"الإصدار الفعلي لأقراص البلوري\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"إستقبال تنبيهات عندما يتم تقديم طلبات بشكل تلقائي من رغبات بليكس.\",\n  \"components.PermissionEdit.autorequestSeries\": \"طلبات تلقائية للمسلسلات\",\n  \"components.PermissionEdit.viewrecentDescription\": \"إعطاء الإذن برؤية قائمة المُضاف مؤخراً.\",\n  \"components.PermissionEdit.viewwatchlists\": \"رؤية قائمة رغبات بليكس\",\n  \"components.RequestBlock.lastmodifiedby\": \"أخر تعديل بواسطة\",\n  \"components.RequestBlock.requestdate\": \"تاريخ الطلب\",\n  \"components.RequestCard.approverequest\": \"الموافقة على الطلب\",\n  \"components.RequestCard.cancelrequest\": \"إلغاء الطلب\",\n  \"components.RequestCard.editrequest\": \"تعديل الطلب\",\n  \"components.RequestCard.tvdbid\": \"المعرّف الخاص بموقع TVDB\",\n  \"components.Selector.searchKeywords\": \"بحث بالكلمات الرئيسية أو الدّالة…\",\n  \"components.Selector.searchGenres\": \"إختيار نوع المحتوى…\",\n  \"components.Selector.starttyping\": \"قم بالكتابة لبدء البحث.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"المُعدّل الحالي\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"كل {jobScheduleSeconds, plural, one {ثانية} other {{jobScheduleSeconds} ثواني}}\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"تنظيف تخزين الصور المؤقت\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"تخزين الصور المؤقت\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"الصور والملتقطات المُخزّنة\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"المجموع الكُلي لحجم الملتقطات\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"دمج رغبات بليكس\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"رؤية التفاصيل\",\n  \"components.Settings.SettingsMain.applicationurl\": \"رابط التطبيق\",\n  \"components.Settings.SettingsMain.originallanguage\": \"اللغة الخاصة بصفحة إكتشف\",\n  \"components.Settings.deleteServer\": \"حذف {serverType} سيرفر\",\n  \"components.StatusBadge.openinarr\": \"فتح في {arr}\",\n  \"components.StatusChecker.restartRequired\": \"مطلوب إعادة تشغيل السيرفر\",\n  \"components.StatusBadge.playonplex\": \"تشغيل في بليكس\",\n  \"components.StatusChecker.restartRequiredDescription\": \"الرجاء إعادة تشغيل السيرفر لتطبيق الإعدادات المُحدثة.\",\n  \"components.TitleCard.tmdbid\": \"معرّف موقع TMDB\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# حلقة} other {# حلقات}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"تقديم طلبات تلقائي للأفلام\",\n  \"components.UserProfile.emptywatchlist\": \"المحتوى المضاف إلى <PlexWatchlistSupportLink>رغبات بليكس </PlexWatchlistSupportLink> سيظهر هنا.\",\n  \"components.AirDateBadge.airsrelative\": \"تُعرضْ {relativeTime}\",\n  \"components.PermissionEdit.autorequestMovies\": \"طلبات تلقائية للأفلام\",\n  \"components.StatusChecker.reloadApp\": \"إعادة تحميل {applicationTitle}\",\n  \"components.TvDetails.seasonstitle\": \"مواسم\",\n  \"components.TvDetails.status4k\": \"فور كي {status}\",\n  \"components.Discover.createnewslider\": \"إنشاء شريط محتوى جديد\",\n  \"components.Discover.customizediscover\": \"تخصيص صفحة (إكتشف)\",\n  \"components.Discover.moviegenres\": \"أنواع الأفلام\",\n  \"components.Discover.networks\": \"شبكات البث\",\n  \"components.Discover.resettodefault\": \"إعادة ضبط للوضع الإفتراضي\",\n  \"components.Discover.resetsuccess\": \"تم إعادة ضبط إعدادات إكتشف المخصصة لوضعها الإفتراضي.\",\n  \"components.Discover.tmdbstudio\": \"إستديوهات من TMDB\",\n  \"components.Discover.tmdbnetwork\": \"شبكات البث من (TMDB)\",\n  \"components.Discover.tmdbsearch\": \"بث في TMDB\",\n  \"components.Discover.tvgenres\": \"أنواع المسلسلات\",\n  \"components.Discover.updatefailed\": \"حدث خطأ ما أثناء تحديث الإعدادات المخصصة لصفحة إكتشف.\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: موسم {seasonNumber} حلقة {episodeNumber}\",\n  \"components.TvDetails.reportissue\": \"الإبلاغ عن مشكلةْ\",\n  \"components.TvDetails.rtaudiencescore\": \"تقييم الجمهور من موقع Rotten Tomatoes\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"أفلام\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"الشعبية تصاعديا\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"الشعبية تنازلياً\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"العناوين بتصاعد أبجدي (بحسب الأحرف الإنجليزية)\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"العناوين بتنازل أبجدي (بحسب الأحرف الإنجليزية)\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"تقييم TMDB بترتيب تصاعدي\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"تم حذف شريط المحتوى.\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"تقييم TMDB بترتيب تنازلي\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"فشل حذف شريط المحتوى.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"التبديل للرؤية\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"حَذف\",\n  \"components.Discover.DiscoverTv.discovertv\": \"مُسلسل\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"تاريخ البث بترتيب تصاعدي\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# الفلتر المفعل} other {# الفلاتر المفعلة}}\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"الشعبية بترتيب تصاعدي\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"الشعبية بترتيب تنازلي\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} مسلسل\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# الفلتر المفعل} other {# الفلاتر المفعلة}}\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"محو الفلاتر المفعلة\",\n  \"components.Discover.FilterSlideover.filters\": \"فلاتر\",\n  \"components.Discover.FilterSlideover.from\": \"من\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"اللغة الأصلية\",\n  \"components.Discover.FilterSlideover.runtime\": \"مُدّة العرض\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"تقييم المستخدمين من (TMDB)\",\n  \"components.Discover.FilterSlideover.to\": \"إلى\",\n  \"components.Discover.FilterSlideover.studio\": \"إستديوهات\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"أُضيفَ مؤخراً\",\n  \"components.Discover.tmdbmoviegenre\": \"نوع الأفلام من (TMDB)\",\n  \"components.Discover.tmdbtvgenre\": \"أنواع المسلسلات من TMDB\",\n  \"components.Discover.plexwatchlist\": \"قائمتك الخاصة برغبات بليكس\",\n  \"components.MovieDetails.theatricalrelease\": \"الإصدار السينمائي (العرض بالسينما)\",\n  \"components.MovieDetails.tmdbuserscore\": \"تقييم مستخدمين TMDB\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"تم تقديم الطلب بشكل تلقائي\",\n  \"components.PermissionEdit.autorequest\": \"طلب تلقائي\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"إعطاء الإذن بتقديم طلبات تلقائية للمسلسلات بغير جودة الفور كي من خلال رغبات بليكس.\",\n  \"components.PermissionEdit.viewrecent\": \"رؤية ماتم إضافته مؤخراً\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"إعطاء الإذن برؤية رغبات بليكس الخاصة بكل المستخدمين الأخرين.\",\n  \"components.RequestBlock.decline\": \"رفض الطلب\",\n  \"components.RequestBlock.edit\": \"تعديل الطلب\",\n  \"components.RequestCard.tmdbid\": \"المعرّف الخاص بموقع TMDB\",\n  \"components.RequestList.RequestItem.tmdbid\": \"المعرّف الخاص بموقع TMDB\",\n  \"components.RequestModal.requestseries4ktitle\": \"طلب مسلسل بجودة فور كي\",\n  \"components.Settings.SettingsMain.cacheImages\": \"تفعيل تخزين الملتقطات والصور\",\n  \"components.Settings.SettingsMain.generalsettings\": \"إعدادات عامة\",\n  \"components.Settings.SettingsMain.locale\": \"لغة العرض\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"تم حفظ الإعدادات!\",\n  \"components.StatusChecker.appUpdatedDescription\": \"الرجاء النقر على الزر بالإسفل لإعادة تحميل الصفحة.\",\n  \"components.AirDateBadge.airedrelative\": \"عُرضت {relativeTime}\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# الفلتر المُفعّل } other {# الفلاتر المفعلة}}\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"تاريخ الإصدار تصاعدياً\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"تاريخ الإصدار تنازلياً\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"تاريخ البث بترتيب تنازلي\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"العنوانين بترتيب ابجدي تصاعدي\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"العناوين بترتيب أبجدي تنازلي\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"تقييم TMDB بترتيب تصاعدي\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"تقييم TMDB بترتيب تنازلي\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"تاريخ البث\",\n  \"components.Discover.FilterSlideover.keywords\": \"كلمات رئيسية أو دالّة\",\n  \"components.Discover.FilterSlideover.ratingText\": \"التقييم بين {minValue} و {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"تاريخ الإصدار\",\n  \"components.MovieDetails.managemovie\": \"إدارة الفيلم\",\n  \"components.Layout.Sidebar.browsemovies\": \"أفلام\",\n  \"components.Layout.Sidebar.browsetv\": \"مسلسلاتْ\",\n  \"components.PermissionEdit.autorequestDescription\": \"إعطاء الإذن بتقديم طلبات تلقائية للمحتويات (بغير جودة الفور كي) من خلال رغبات بليكس.\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"إعطاء الإذن بتقديم طلبات أفلام تلقائية بغير جودة الفور كي من خلال رغبات بليكس.\",\n  \"components.RequestCard.unknowntitle\": \"عنوان غير معروف\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"لم يتم العثور على عنوان مطابق لهذا المسلسل.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"طلب تجميعة بجودة فور كي (تجمعية هي الأفلام بأجزاء متعددة أو مرتبطة)\",\n  \"components.RequestModal.requestmovie4ktitle\": \"طلب فيلم بجودة فور كي\",\n  \"components.RequestModal.requestmovietitle\": \"طلب فيلم\",\n  \"components.Selector.nooptions\": \"لا يوجد نتائج.\",\n  \"components.RequestModal.requestcollectiontitle\": \"طلب تجميعة (التجميعة هي حزمة أفلام مرتبطة ببعضها)\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"عند التفعيل بالإعدادات، أوفرسيرر سيقوم بحفظ الملتقطات والصور. يتم تخزين هذه الملتقطات في مجلد الضبط الخاص بك. تستطيع إيجاد هذه الملفات في <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"الملتقطات من المصادر الخارجية (تتطلب حجم هائل متوفر في مساحة التخزين الخاصة بجهازك)\",\n  \"components.Settings.SettingsMain.general\": \"عام\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"إخفاء المحتوى المتوفّر\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"فلترة المحتوى باللغة الأصلية\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"السماح بالطلبات الجزئية للمسلسلات (بمعنى مسلسل لم ينتهي عرض الموسم بالكامل)\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"حدث خطأ ما أثناء إنشاء مفتاح API جديد.\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"حدث خطأ ما أثناء حفظ الإعدادات.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"تم إنشاء مفتاح API جديد بنجاح!\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"يجب تقديم رابط صحيح\",\n  \"components.Settings.advancedTooltip\": \"ضبط هذا الإعداد بشكل غير صحيح قد يؤدي الى عدم عمل بعض الخصائص\",\n  \"components.StatusBadge.seasonepisodenumber\": \"م{seasonNumber}ح{episodeNumber}\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"حدث خطأ ما أثناء محاولة جلب بيانات الموسم.\",\n  \"components.TvDetails.Season.noepisodes\": \"قائمة الحلقات غير متوفرة.\",\n  \"components.TvDetails.seasonnumber\": \"موسم {seasonNumber}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"بشكل تلقائي تقديم طلبات الأفلام <PlexWatchlistSupportLink>من رغبات بليكس </PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"تقديم الطلبات بشكل تلقائي للمسلسلات<PlexWatchlistSupportLink>من رغبات بليكس </PlexWatchlistSupportLink>\",\n  \"components.Discover.FilterSlideover.genres\": \"أنواع المحتوى\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} مدة العرض بالدقائق\",\n  \"components.RequestBlock.delete\": \"حذف الطلب\",\n  \"components.UserProfile.plexwatchlist\": \"رغبات بليكس\",\n  \"components.Discover.emptywatchlist\": \"المحتوى المُضاف إلى<PlexWatchlistSupportLink>رغبات بليكس </PlexWatchlistSupportLink> سيظهر هنا.\",\n  \"components.Discover.tmdbtvkeyword\": \"كلمات بحث رئيسية عن المسلسلات من TMDB\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"شبكات البثّ\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"المحتوى المُضاف إلى <PlexWatchlistSupportLink>رغبات بليكس </PlexWatchlistSupportLink> سيظهر هنا.\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"إنشاء شريط محتوى مخصّص\",\n  \"components.Discover.CreateSlider.addSlider\": \"إضافة شريط محتوى\",\n  \"components.Discover.CreateSlider.addfail\": \"فشل إنشاء شريط محتوى جديد.\",\n  \"components.Discover.CreateSlider.editSlider\": \"تعديل شريط المحتوى\",\n  \"components.Discover.CreateSlider.editfail\": \"فشل تعديل شريط المحتوى.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"تم تعديل الشريط وتم حفظ إعدادات التخصيص لصفحة (إكتشف).\",\n  \"components.Discover.CreateSlider.addsuccess\": \"تم إنشاء شريط جديد و تم حفظ إعدادات التخصيص لصفحة (إكتشف).\",\n  \"components.Discover.CreateSlider.needresults\": \"يجب أن يكون لديك نتيجة واحدة على الأقل.\",\n  \"components.Discover.CreateSlider.nooptions\": \"لا يوجد نتائج.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"قم بتوفير معرّف نوع المحتوى من (TMDB)\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"قم بتوفير معرّف شبكة البث من (TMDB)\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"قم بتوفير بحث إستعلام\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"قم بتوفير معرّف الإستديو من (TMDB)\",\n  \"components.Discover.CreateSlider.searchGenres\": \"بحث بنوع المحتوى…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"بحث بكلمات رئيسية…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"بحث عن الإستديوهات…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"إسم شريط المحتوى\",\n  \"components.Discover.CreateSlider.starttyping\": \"قم بالكتابة لبدء البحث.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"يجب تقديم بيانات.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"يجب تقديم عنوان.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} الأفلام\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"قم بتوفير معرّف كلمات بحث رئيسية من (TMDB)\",\n  \"components.MovieDetails.imdbuserscore\": \"تقييم مستخدمين IMDB\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"صوت التنبيه\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"الجهاز الإفتراضي\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"نوع مسلسل الإنمي\",\n  \"components.Settings.SonarrModal.seriesType\": \"نوع المسلسل\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"صوت التنبيه\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"الجهاز الإفتراضي\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/bg.json",
    "content": "{\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB Рейтинг Възходящ\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Редактиран плъзгач и запазени настройки за откриване.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Филми\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Име на плъзгач\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Възходяща дата на първо излъчване\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Монтирането на дялът с път <code>{appDataPath}</code> не е конфигуриран правилно. Всички данни ще бъдат изчистени, когато контейнерът бъде спрян или рестартиран.\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Сериали\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Популярност низходяща\",\n  \"components.AirDateBadge.airsrelative\": \"Излъчва се {relativeTime}\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB Рейтинг Низходящ\",\n  \"components.CollectionDetails.overview\": \"Преглед\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Активен филтър} other {# Активни филтри}}\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB Рейтинг Възходящ\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Сериали\",\n  \"components.AirDateBadge.airedrelative\": \"Излъчен {relativeTime}\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Търсете студия…\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Дата на издаване в низходящ ред\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Предоставете TMDB ID на мрежа\",\n  \"components.Discover.CreateSlider.addfail\": \"Провали се създаването на нов плъзгач.\",\n  \"components.CollectionDetails.requestcollection\": \"Заявка на колекция\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} Филми\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Филми\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Активен филтър} other {# Активни филтри}}\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Сериали\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Популярност възходяща\",\n  \"components.Discover.CreateSlider.needresults\": \"Трябва да имате поне 1 резултат.\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Създай персонализиран плъзгач\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Популярност възходяща\",\n  \"components.Discover.CreateSlider.editSlider\": \"Редактирай плъзгач\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Заглавие (А-Я) Възходящо\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Трябва да предоставите стойност на данните.\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Низходяща дата на първо излъчване\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Сериали\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Провали се изтриване на плъзгач.\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Предоставете TMDB ID на Студио\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Заглавие (А-Я) Низходящо\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} Филми\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Популярност низходяща\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Търсете жанрове…\",\n  \"components.Discover.CreateSlider.editfail\": \"Провали се редакцията на слайдера.\",\n  \"components.Discover.CreateSlider.starttyping\": \"Започнете въвеждане на търсене.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Превключване на видимостта\",\n  \"components.Discover.CreateSlider.addSlider\": \"Добави плъзгач\",\n  \"components.CollectionDetails.requestcollection4k\": \"Заявка на колекция в 4К\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Въведете заявка за търсене\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} Сериали\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Предоставете ID на TMDB ключова дума\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Филми\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Трябва да предоставите заглавие.\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Дата на издаване Възходящ ред\",\n  \"components.Discover.CreateSlider.nooptions\": \"Няма резултати.\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB Рейтинг Низходящ\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Търсете ключови думи…\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Създаден е нов плъзгач и са запазени настройките за Открийте.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Успешно изтрит плъзгач.\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Филми\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Заглавие (А-Я) Възходящо\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Предоставете TMDB ID на жанра\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Заглавие (А-Я) Низходящо\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Премахване\",\n  \"components.Layout.Sidebar.browsemovies\": \"Филми\",\n  \"components.IssueList.IssueItem.issuetype\": \"Тип\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Неизвестен\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Статус\",\n  \"components.Login.signinheader\": \"Впишете се, за да продължите\",\n  \"components.IssueDetails.allseasons\": \"Всички сезони\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Редактирай описание\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Сигурни ли сте, че искате да изтриете този коментар?\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Засегнат епизод\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Нещо се обърка при редактиране на описанието на проблема.\",\n  \"components.Discover.updatesuccess\": \"Актуализирани настройки за персонализиране на Откриване.\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезони}}\",\n  \"components.IssueDetails.problemepisode\": \"Засегнат епизод\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Засегнат сезон\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Развоен\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Заявки за филми\",\n  \"components.IssueDetails.issuepagetitle\": \"Проблем\",\n  \"components.IssueList.showallissues\": \"Покажи всички проблеми\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Описанието на проблема е редактирано успешно!\",\n  \"components.Layout.UserDropdown.signout\": \"Отписване\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Докладвайте за проблем\",\n  \"components.Layout.UserDropdown.myprofile\": \"Профил\",\n  \"components.Login.email\": \"Имейл адрес\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Изтриване на проблем\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Изпратете проблем\",\n  \"components.IssueDetails.episode\": \"Епизод {episodeNumber}\",\n  \"components.IssueDetails.unknownissuetype\": \"Неизвестен\",\n  \"components.Layout.Sidebar.issues\": \"Проблеми\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} от {user}\",\n  \"components.Login.signinwithoverseerr\": \"Използвайте своя акаунт {applicationTitle}\",\n  \"components.Discover.updatefailed\": \"Нещо се обърка при актуализирането на настройките за Откриване.\",\n  \"components.Layout.Sidebar.requests\": \"Заявки\",\n  \"components.Layout.Sidebar.settings\": \"Настройки\",\n  \"components.IssueList.IssueItem.opened\": \"Отворен\",\n  \"components.IssueDetails.problemseason\": \"Засегнат сезон\",\n  \"components.Layout.UserDropdown.requests\": \"Заявки\",\n  \"components.Login.loginerror\": \"Нещо се обърка при опит за влизане.\",\n  \"components.IssueList.sortAdded\": \"Последни\",\n  \"components.IssueDetails.IssueDescription.description\": \"Описание\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Заявки за сериали\",\n  \"components.LanguageSelector.languageServerDefault\": \"По подразбиране ({language})\",\n  \"components.IssueModal.issueSubtitles\": \"Субтитри\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Засегнат епизод\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Нещо се обърка при изтриването на проблема.\",\n  \"components.IssueDetails.openin4karr\": \"Отвори в 4K {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Пусни в 4K в Plex\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Нещо се обърка при изпращането на проблема.\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Трябва да въведете съобщение\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Публикуван {relativeTime} от {username} (Редактиран)\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Докладът за проблем <strong>{title}</strong> е изпратен успешно!\",\n  \"components.IssueDetails.IssueComment.delete\": \"Изтрий коментар\",\n  \"components.IssueDetails.openedby\": \"#{issueId} е оворен {relativeTime} от {username}\",\n  \"components.IssueDetails.nocomments\": \"Няма коментари.\",\n  \"components.IssueDetails.allepisodes\": \"Всички епизоди\",\n  \"components.Login.signingin\": \"Вписване…\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Търсене на Филми§ТВ\",\n  \"components.IssueDetails.season\": \"Сезон {seasonNumber}\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Публикуван {relativeTime} от {username}\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Отвори отново с коментар\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Нещо се обърка при актуализиране на състоянието на проблема.\",\n  \"components.IssueList.issues\": \"Проблеми\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Трябва да предоставите описание\",\n  \"components.IssueDetails.reopenissue\": \"Отвори отново проблема\",\n  \"components.IssueDetails.closeissueandcomment\": \"Приключване с коментар\",\n  \"components.IssueDetails.deleteissue\": \"Изтрий проблем\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Всички сезони\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Сезон {seasonNumber}\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Сезон {seasonNumber} Епизод {episodeNumber}\",\n  \"components.IssueDetails.IssueComment.edit\": \"Редактирай коментар\",\n  \"components.IssueModal.issueVideo\": \"Видео\",\n  \"components.Layout.Sidebar.users\": \"Потребители\",\n  \"components.Layout.UserDropdown.settings\": \"Настройки\",\n  \"components.Login.password\": \"Парола\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Виж проблема\",\n  \"components.Layout.VersionStatus.outofdate\": \"Остарял\",\n  \"components.IssueList.IssueItem.viewissue\": \"Виж проблема\",\n  \"components.IssueDetails.comments\": \"Коментари\",\n  \"components.Login.forgotpassword\": \"Забравена парола?\",\n  \"components.Layout.Sidebar.dashboard\": \"Открийте\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Екстри\",\n  \"components.IssueDetails.toastissuedeleted\": \"Проблемът е изтрит успешно!\",\n  \"components.DownloadBlock.estimatedtime\": \"Приблизително {time}\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Какво не е наред?\",\n  \"components.IssueDetails.toaststatusupdated\": \"Състоянието на проблема е актуализирано успешно!\",\n  \"components.Login.signin\": \"Впиши се\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Епизод} other {Епизоди}}\",\n  \"components.IssueDetails.lastupdated\": \"Последно опреснен\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Всички епизоди\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Език на дисплея\",\n  \"components.Layout.Sidebar.browsetv\": \"Сериали\",\n  \"components.IssueDetails.commentplaceholder\": \"Добави коментар …\",\n  \"components.IssueList.sortModified\": \"Последно редактирани\",\n  \"components.IssueDetails.openinarr\": \"Отвори в {arr}\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Моля, дайте подробно обяснение на проблема, който сте срещнали.\",\n  \"components.IssueDetails.closeissue\": \"Приключване на проблема\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Всички езици\",\n  \"components.IssueModal.issueOther\": \"Друго\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Епизод {episodeNumber}\",\n  \"components.IssueDetails.issuetype\": \"Тип\",\n  \"components.IssueDetails.leavecomment\": \"Коментар\",\n  \"components.IssueDetails.playonplex\": \"Пусни в Plex\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Стабилен\",\n  \"components.IssueModal.issueAudio\": \"Аудио\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Сигурни ли сте, че искате да изтриете този проблем?\",\n  \"components.PermissionEdit.request\": \"Заявка\",\n  \"components.Discover.moviegenres\": \"Филмови жанрове\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestList.RequestItem.modified\": \"Изменен\",\n  \"components.MovieDetails.digitalrelease\": \"Цифрово издание\",\n  \"components.Settings.RadarrModal.announced\": \"Обявен\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Най-нов\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} други {<strong>#</strong>}} {type} {remaining, plural, one {заявка} other {заявки}} оставащи\",\n  \"components.PersonDetails.alsoknownas\": \"Също известен като: {names}\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Известието за тест чрез имейл е изпратено!\",\n  \"components.Discover.FilterSlideover.studio\": \"Студио\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Настройките за известяване на Gotify не успяха да бъдат запазени.\",\n  \"components.RequestModal.requestseries4ktitle\": \"Заявка на сериали в 4К\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Трябва да предоставите токен за достъп\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Текущ\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Мултимедията, добавена към вашия <PlexWatchlistSupportLink>списък за гледане в Plex</PlexWatchlistSupportLink>, ще се появи тук.\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Известието за тест към Telegram е изпратено!\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Пропуски\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Получавайте известие, когато заявките ви за медии станат налични.\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Наскоро добавен\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Звук за известяване\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Настройките за известяване чрез Webhook не успяха да бъдат запазени.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Трябва да предоставите валиден URL адрес\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Частен ключ за PGP\",\n  \"components.PermissionEdit.requestTvDescription\": \"Дайте разрешение за изпращане на заявки за не-4K сериали.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Гарантиране на автоматично одобрение за заявки на 4K филми.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Трябва да предоставите валиден токен за приложение\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Базов URL адрес\",\n  \"components.Discover.FilterSlideover.keywords\": \"Ключови думи\",\n  \"components.Discover.tvgenres\": \"Жанрове сериали\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook URL\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Не успяхме да намерим съвпадение за този сериал.\",\n  \"components.PermissionEdit.autorequest\": \"Автоматична заявка\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Винаги използвайте STARTTLS\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Оценки между {minValue} и {maxValue}\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Автоматично одобряване на сериали\",\n  \"components.RequestButton.approverequests\": \"Одобри {requestCount, plural, one {заявка} other {{requestCount} заявки}}\",\n  \"components.PersonDetails.crewmember\": \"Екип\",\n  \"components.RequestButton.requestmore4k\": \"Заявете повече в 4К\",\n  \"components.PersonDetails.ascharacter\": \"като {character}\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Трябва да предоставите валиден chat ID\",\n  \"components.ManageSlideOver.downloadstatus\": \"Изтегляния\",\n  \"components.Settings.Notifications.enableMentions\": \"Активиране на споменаванията\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Трябва да предоставите валидна PGP парола\",\n  \"components.Settings.SettingsAbout.timezone\": \"Време зона\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Връзката към Radarr е установена успешно!\",\n  \"components.Discover.resetwarning\": \"Нулирайте всички плъзгачи по подразбиране. Това също ще изтрие всички персонализирани плъзгачи!\",\n  \"components.RequestList.RequestItem.editrequest\": \"Редакция на заявка\",\n  \"components.Settings.RadarrModal.ssl\": \"Използвай SSL\",\n  \"components.MovieDetails.showless\": \"Покажи по-малко\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Дайте разрешение за управление на медийни проблеми.\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Активиране на агент\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Профил качество\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Изпращайте известия, когато проблемите получат нови коментари.\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Тествайте връзката за зареждане на тагове\",\n  \"components.Settings.Notifications.sendSilently\": \"Изпрати безшумно\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Паролите трябва да съвпадат\",\n  \"components.RequestList.requests\": \"Заявки\",\n  \"components.RequestModal.QuotaDisplay.season\": \"сезон\",\n  \"components.PermissionEdit.managerequests\": \"Управление на заявки\",\n  \"components.ResetPassword.emailresetlink\": \"Връзка за възстановяване на имейл\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Получавайте известие, когато проблемите, за които сте докладвали, бъдат отворени отново.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Получавайте известия, когато медийните заявки не успеят да бъдат добавени към Radarr или Sonarr.\",\n  \"components.RequestButton.approverequest4k\": \"Одобряване на 4K заявка\",\n  \"components.PermissionEdit.manageissues\": \"Управление на проблемите\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Трябва да предоставите токен за оторизация на бота\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.Settings.Notifications.authUser\": \"SMTP потребител\",\n  \"components.PermissionEdit.viewrequests\": \"Преглед на заявките\",\n  \"components.RequestCard.failedretry\": \"Нещо се обърка при повторен опит за заявка.\",\n  \"components.PermissionEdit.requestMovies\": \"Заявка за филми\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Можете да прегледате обобщение на ограниченията на заявки от потребителя на неговата <ProfileLink>профилна страница</ProfileLink>.\",\n  \"components.Discover.StudioSlider.studios\": \"Студия\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Заявки\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Изпращайте известия при докладване на проблеми.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Изпращайте известия, когато медийните заявки станат налични.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Заявете филм в 4K\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> е заявен успешно!\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Създайте <DiscordWebhookLink>интегриране на webhook</DiscordWebhookLink> във вашия сървър\",\n  \"components.Settings.RadarrModal.selecttags\": \"Изберете етикети\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Неуспешно изпращане на тестово известие към Pushbullet.\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB Ключови думи във филма\",\n  \"components.RequestButton.declinerequest\": \"Отказ на заявка\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Регистриране на приложение</ApplicationRegistrationLink> за използване с Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Известието към Pushover тест е изпратено!\",\n  \"components.Settings.Notifications.emailsender\": \"Адрес на изпращача\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Трябва да предоставите токен за приложение\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Преглед на Дневник на промените\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезони}}\",\n  \"components.Settings.RadarrModal.released\": \"Излъчен\",\n  \"components.ManageSlideOver.movie\": \"филм\",\n  \"components.Discover.stopediting\": \"Спрете редактирането\",\n  \"components.RequestCard.declinerequest\": \"Отказ на заявка\",\n  \"components.Settings.RadarrModal.port\": \"Порт\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Дайте разрешение за изпращане на заявки за 4K филми.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Разширено\",\n  \"components.Discover.resetsuccess\": \"Успешно нулиране на настройките за персонализиране на откриването.\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Минимална наличност\",\n  \"components.Settings.Notifications.agentenabled\": \"Активиране на агент\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Издания\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Трябва да предоставите API ключ\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Трябва да изберете минимална наличност\",\n  \"components.RequestModal.requestseasons\": \"Заявете {seasonCount} {seasonCount, plural, one {сезон} other {сезони}}\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Изпраща се тестово известие към Slack…\",\n  \"components.RequestButton.viewrequest\": \"Преглед на заявката\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Трябва да предоставите валиден URL адрес\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Настройките за известяване към Slack са запазени успешно!\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Трябва да изберете профил за качество\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Общо заявки\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Разширено\",\n  \"components.Discover.customizediscover\": \"Персонализирайте Откриване\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Настройките за известяване към Gotify са запазени успешно!\",\n  \"components.RequestModal.approve\": \"Одобряване на заявката\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Известието за тест към Gotify е изпратено!\",\n  \"components.Discover.emptywatchlist\": \"Мултимедията, добавена към вашия <PlexWatchlistSupportLink>списък за гледане в Plex</PlexWatchlistSupportLink>, ще се появи тук.\",\n  \"components.MovieDetails.runtime\": \"{minutes} минути\",\n  \"components.Settings.Notifications.encryption\": \"Метод на криптиране\",\n  \"components.Discover.populartv\": \"Популярни сериали\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Общо ключове\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Без етикети.\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Тествайте връзката за зареждане на основните папки\",\n  \"components.RequestModal.pendingapproval\": \"Вашата заявка чака одобрение.\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Трябва да изберете поне един тип известие\",\n  \"components.RequestBlock.rootfolder\": \"Основна папка\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Сървър по подразбиране\",\n  \"components.MovieDetails.watchtrailer\": \"Гледайте трейлър\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Коментар на проблема\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезони}}\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Изберете минимална наличност\",\n  \"components.Selector.showmore\": \"Покажи повече\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Изберете главна папка\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} от {user}\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Основна папка\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Изпраща се известие за тест чрез Web push…\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Изпращайте известия, когато медийните заявки са одобрени ръчно.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Етикетите се зареждат…\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Създайте интеграция на <WebhookLink>входен Webhook</WebhookLink>\",\n  \"components.PermissionEdit.autoapprove4k\": \"Автоматично одобрение 4К\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Гарантирано автоматично одобрение за заявки за не-4K филми.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Трябва да предоставите валиден потребителски или групов ключ\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Дневник на промените\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Медия\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Проблемът е решен\",\n  \"components.MovieDetails.originaltitle\": \"Оригинално заглавие\",\n  \"components.Discover.trending\": \"Тендеция\",\n  \"components.RequestButton.declinerequests\": \"Отхвърли {requestCount, plural, one {заявка} other {{requestCount} заявки}}\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Създайте токен от вашите <PushbulletSettingsLink>Настройки на акаунта</PushbulletSettingsLink>\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Дайте разрешение за изпращане на заявки за не-4K филми.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Изпраща се тестово известие към Discord…\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Заявка като\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Хитове\",\n  \"components.Settings.RadarrModal.inCinemas\": \"В кината\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Неуспешно изпращане на тестово известие чрез Telegram.\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Успешно нулиране на паролата!\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Този сериал е аниме.\",\n  \"components.RequestBlock.requestoverrides\": \"Охвърляне на заявката\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} не е намерен\",\n  \"components.RequestModal.selectmovies\": \"Изберете филм(и)\",\n  \"components.RequestModal.requestApproved\": \"Заявката за <strong>{title}</strong> е одобрена!\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Тествайте връзката, за да заредите профилите за качество\",\n  \"components.QuotaSelector.unlimited\": \"Неограничен\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Паролата е твърде кратка; трябва да съдържа минимум 8 знака\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Активирайте сканирането\",\n  \"components.RequestModal.numberofepisodes\": \"# брой епизоди\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Настройките за известяване към Pushover не успяха да бъдат запазени.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Настройките за известяване чрез Web push са запазени успешно!\",\n  \"components.MovieDetails.originallanguage\": \"Оригинален език\",\n  \"components.PermissionEdit.request4kTv\": \"Заявете 4K сериал\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Изчистване на активните филтри\",\n  \"components.RequestModal.edit\": \"Редакция на заявка\",\n  \"components.RequestBlock.profilechanged\": \"Профил качество\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Добавяне на нов 4K Radarr сървър\",\n  \"components.Settings.Notifications.senderName\": \"Име на изпращача\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Автоматично одобряване на 4К филми\",\n  \"components.ManageSlideOver.playedby\": \"Изигран от\",\n  \"components.Settings.RadarrModal.default4kserver\": \"4K сървър по подразбиране\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Трябва да предоставите валидно име на хост или IP адрес\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB Ключови думи в сериали\",\n  \"components.Settings.SettingsAbout.documentation\": \"Документация\",\n  \"components.RequestModal.season\": \"Сезон\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Неуспешно изпращане на тестово известие чрез Web push.\",\n  \"components.Discover.tmdbnetwork\": \"TMDB Мрежи\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Маркирайте като налично в 4K\",\n  \"components.Settings.SettingsAbout.about\": \"Относно\",\n  \"components.ManageSlideOver.tvshow\": \"серии\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"За да получава уеб насочени известия, Seerr трябва да се работи през HTTPS.\",\n  \"components.MovieDetails.cast\": \"В ролите\",\n  \"components.PermissionEdit.viewissues\": \"Преглед на проблемите\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Получавайте известия, когато автоматично се изпращат заявки за елементи от вашия списък за гледане в Plex.\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Филмови жанрове\",\n  \"components.PermissionEdit.viewrecent\": \"Преглед на наскоро добавените\",\n  \"components.Discover.networks\": \"Мрежи\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL адресът не трябва да завършва с наклонена черта в края\",\n  \"components.MovieDetails.budget\": \"Бюджет\",\n  \"components.RequestList.showallrequests\": \"Покажи всички заявки\",\n  \"components.Settings.Notifications.validationTypes\": \"Трябва да изберете поне един тип известие\",\n  \"components.Selector.searchGenres\": \"Изберете жанрове…\",\n  \"components.Settings.RadarrModal.servername\": \"Име на сървъра\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Гарантирано автоматично одобрение за заявки за 4K медии.\",\n  \"components.RequestModal.requestmovies\": \"Заявка {count} {count, plural, one {филм} other {филми}}\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Трябва да предоставите валидно име на хост или IP адрес\",\n  \"components.RequestModal.requestedited\": \"Заявката за <strong>{title}</strong> е редактирана успешно!\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Жанрове сериали\",\n  \"components.RequestModal.selectseason\": \"Изберете сезон(и)\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Получавайте известия, когато проблемите бъдат разрешени от други потребители.\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.PermissionEdit.createissues\": \"Докладвайте проблеми\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Заявен\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Настройките за известяване към Discord са запазени успешно!\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"филм\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Профил качество\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Активирайте автоматичното търсене\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr кешира заявки към външни крайни точки на API, за да оптимизира производителността и да избегне извършването на ненужни извиквания на API.\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {гледа} other {гледат}}\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Жанрове сериали\",\n  \"components.RequestModal.requestcancelled\": \"Заявката за <strong>{title}</strong> е анулирана.\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Размер на ключове\",\n  \"components.MovieDetails.overviewunavailable\": \"Прегледът не е наличен.\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Без етикети.\",\n  \"components.Login.signinwithplex\": \"Използвайте своя Plex акаунт\",\n  \"components.MovieDetails.productioncountries\": \"Продукция на {countryCount, plural, one {държава} other {държави}}\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Неуспешно свързване с Radarr.\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Остарял\",\n  \"components.MovieDetails.managemovie\": \"Управление на филм\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON payload нулиран успешно!\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4К медия\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Получавайте известие, когато проблемите се отварят отново от други потребители.\",\n  \"components.ResetPassword.password\": \"Парола\",\n  \"components.ManageSlideOver.alltime\": \"Всички времена\",\n  \"components.RequestBlock.delete\": \"Изтриване на заявка\",\n  \"components.ResetPassword.validationemailrequired\": \"Трябва да предоставите валиден имейл адрес\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Няма заявки.\",\n  \"components.Settings.Notifications.validationEmail\": \"Трябва да предоставите валиден имейл адрес\",\n  \"components.RequestModal.requestmovies4k\": \"Заявка {count} {count, plural, one {филм} other {филми}} в 4К\",\n  \"components.Discover.NetworkSlider.networks\": \"Мрежи\",\n  \"components.PermissionEdit.autorequestSeries\": \"Автоматична заявка на сериали\",\n  \"components.MovieDetails.showmore\": \"Покажи повече\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Дайте разрешение за преглед на заявки за медии, изпратени от други потребители.\",\n  \"components.Settings.Notifications.encryptionNone\": \"Нищо\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Базовият URL адрес не трябва да завършва с наклонена черта в края\",\n  \"components.ManageSlideOver.openarr4k\": \"Отвори в 4K {arr}\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Услуги за стрийминг\",\n  \"components.RequestBlock.lastmodifiedby\": \"Последна промяна от\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Дата на излизане} other {Дати на излизане}}\",\n  \"components.Discover.popularmovies\": \"Популярни филми\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{филми} за {quotaDays} {дни}</quotaUnits>\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Връзката за повторно задаване на парола ще ви бъде изпратена на предоставения имейл адрес, ако е свързан с валиден потребител.\",\n  \"components.RequestBlock.approve\": \"Одобряване на заявката\",\n  \"components.RegionSelector.regionDefault\": \"Всички региони\",\n  \"components.RequestCard.editrequest\": \"Редакция на заявка\",\n  \"components.Selector.searchStudios\": \"Търсете студия…\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Активен филтър} other {# Активни филтри}}\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Получаване на поддръжка\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Настройките за известяване към Pushbullet са запазени успешно!\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Трябва да изберете поне един тип известие\",\n  \"components.Discover.upcomingmovies\": \"Предстоящи филми\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Отворени въпроси\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Настройките за известяване към Telegram са запазени успешно!\",\n  \"components.RequestButton.viewrequest4k\": \"Преглед на 4К заявка\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Редактирай 4К Radarr сървър\",\n  \"components.PermissionEdit.request4k\": \"Заявка 4K\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Можете да прегледате обобщение на ограниченията на вашите заявки на вашата <ProfileLink>профилна страница</ProfileLink>.\",\n  \"components.Discover.plexwatchlist\": \"Вашият Plex списък за гледане\",\n  \"components.ResetPassword.confirmpassword\": \"Потвърди парола\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB потребителска оценка\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Етикет на канала\",\n  \"components.Settings.RadarrModal.createradarr\": \"Добавяне на нов Radarr сървър\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Заявката е одобрена\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Заявка на колекция в 4К\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB Жанр сериали\",\n  \"components.MovieDetails.theatricalrelease\": \"Излъчване в кината\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Трябва да предоставите валиден URL адрес\",\n  \"components.Settings.Notifications.chatId\": \"Чат ID\",\n  \"components.MovieDetails.overview\": \"Преглед\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Синхронизиране наличността на медиите\",\n  \"components.Discover.tmdbstudio\": \"TMDB Студио\",\n  \"components.Discover.upcoming\": \"Предстоящи филми\",\n  \"components.ManageSlideOver.pastdays\": \"Последните {days, number} дни\",\n  \"components.MovieDetails.rtaudiencescore\": \"Резултат от публиката на Rotten Tomatoes\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {филм} other {филми}}\",\n  \"components.RequestModal.requesterror\": \"Нещо се обърка при изпращане на заявката.\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Подписвайте шифровани имейл съобщения с помощта на <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.RequestList.RequestItem.failedretry\": \"Нещо се обърка при повторен опит за заявка.\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB потребителска оценка\",\n  \"components.RequestButton.decline4krequests\": \"Отхвърли {requestCount, plural, one {4K заявка} other {{requestCount} 4K заявки}}\",\n  \"components.RequestButton.declinerequest4k\": \"Отказ на 4К заявка\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL адрес на сървъра\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Трябва да изберете поне един тип известие\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Изпращайте известия, когато потребителите изпращат нови медийни заявки, които изискват одобрение.\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB Услуги за стрийминг на сериали\",\n  \"components.ResetPassword.gobacklogin\": \"Върнете се към страницата за вход\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Това ще премахне необратимо всички данни за този {mediaType}, включително всички заявки. Ако този елемент съществува във вашата Plex библиотека, медийната информация ще бъде отново създадена по време на следващото сканиране.\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Използвайте STARTTLS, ако има такъв\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Актуално\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP Парола\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Този потребител трябва да има най-малко <strong>{seasons}</strong> {seasons, plural, one {заявка за сезон} other {заявки за сезони}} оставащи, за да изпрати заявка за този сериал.\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Хедър за удостоверяване\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Дайте разрешение за изпращане на заявки за 4K сериали.\",\n  \"components.ManageSlideOver.markavailable\": \"Маркирайте като наличен\",\n  \"components.Selector.showless\": \"Покажи по-малко\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Вашият Plex списък за гледане\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Неизвестно заглавие\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Общо медия\",\n  \"components.RegionSelector.regionServerDefault\": \"По подразбиране ({region})\",\n  \"components.PermissionEdit.request4kMovies\": \"Заявка за 4K филми\",\n  \"components.RequestButton.approve4krequests\": \"Одобри {requestCount, plural, one {4K заявка} other {{requestCount} 4K Заявки}}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Дата на излизане\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook URL\",\n  \"components.RequestModal.errorediting\": \"Нещо се обърка при редактирането на заявката.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Известието за тест към Slack е изпратено!\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Автоматично одобрение на 4К сериали\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Дайте разрешение за автоматично изпращане на заявки за не-4K серии чрез Plex Списък за гледане.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Активиране на агент\",\n  \"components.MovieDetails.similar\": \"Подобни заглавия\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Директория с данни\",\n  \"components.Settings.Notifications.botUsername\": \"Бот потребителско име\",\n  \"components.MovieDetails.mark4kavailable\": \"Маркирайте като налично в 4K\",\n  \"components.RequestCard.approverequest\": \"Одобряване на заявката\",\n  \"components.Discover.recentlyAdded\": \"Наскоро добавен\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL адреса трябва да има водеща наклонена черта\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Трябва да предоставите валиден номер на порт\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Настройките за известяване към Slack не успяха да бъдат запазени.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Известието чрез Webhook тест е изпратено!\",\n  \"components.RequestButton.approverequest\": \"Одобряване на заявката\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Понастоящем няма налични данни за изданието.\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Вижте в GitHub\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Изпраща се тестово известие чрез Telegram…\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Дайте разрешение за управление на медийни заявки. Всички заявки, направени от потребител с това разрешение, ще бъдат автоматично одобрени.\",\n  \"components.Settings.SettingsAbout.version\": \"Версия\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Имате право да заявявате <strong>{limit}</strong> {type} на всеки <strong>{days}</strong> дни.\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Дайте разрешение за автоматично изпращане на заявки за не-4K филми чрез Plex Списък за гледане.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Получавайте известие, когато заявките ви за медия бъдат отхвърлени.\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {промяна} other {промени}} назад\",\n  \"components.ResetPassword.resetpassword\": \"Нулиране на паролата ви\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP Host\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Изпращайте известия, когато потребителите изпращат нови медийни заявки, които се одобряват автоматично.\",\n  \"components.Discover.FilterSlideover.runtime\": \"Времетраене\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Дискусии в GitHub\",\n  \"components.PermissionEdit.autoapprove\": \"Автоматично одобрение\",\n  \"components.RequestCard.deleterequest\": \"Изтриване на заявка\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Настройките за известяване по имейл са запазени успешно!\",\n  \"components.RequestBlock.server\": \"Целеви сървър\",\n  \"components.Discover.FilterSlideover.from\": \"От\",\n  \"components.Settings.RadarrModal.add\": \"Добавете сървър\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Настройките за известяване към Telegram не успяха да бъдат запазени.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Настройките за известяване чрез Webhook са запазени успешно!\",\n  \"components.RequestModal.pending4krequest\": \"Изчакваща заявка за 4K\",\n  \"components.PermissionEdit.viewwatchlists\": \"Вижте списъците за гледане от Plex\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Целеви сървър\",\n  \"components.PermissionEdit.createissuesDescription\": \"Дайте разрешение за докладване на проблеми с медиите.\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Потребителски или групов ключ\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Основна папка\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{сезона} за {quotaDays} {дни}</quotaUnits>\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Получавайте известия, когато други потребители коментират проблеми.\",\n  \"components.PermissionEdit.adminDescription\": \"Пълен администраторски достъп. Заобикаля всички други проверки на права.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Заявката е отхвърлена\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Настройките за известяване по имейл не успяха да бъдат запазени.\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Дайте разрешение за преглед на списъка с наскоро добавени медии.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Получавайте известия, когато други потребители изпращат нови медийни заявки, които изискват одобрение.\",\n  \"components.Discover.studios\": \"Студия\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Автоматично добавяне на допълнителен етикет с потребителското ID и показваното име на заявителя\",\n  \"components.RequestBlock.requestdate\": \"Дата на заявка\",\n  \"components.PermissionEdit.usersDescription\": \"Дайте разрешение за управление на потребители. Потребителите с това разрешение не могат да променят потребители с привилегии или да предоставят привилегия за администратор.\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL адрес на аватара на бота\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Настройките за известяване към Discord не успяха да бъдат запазени.\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB Услуги за стрийминг на филми\",\n  \"components.Discover.FilterSlideover.to\": \"До\",\n  \"components.RequestList.sortAdded\": \"Най-скорошен\",\n  \"components.Discover.resetfailed\": \"Нещо се обърка при нулирането на настройките за персонализиране на откриването.\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Трябва да изберете основна папка\",\n  \"components.Discover.createnewslider\": \"Създайте нов плъзгач\",\n  \"components.Search.searchresults\": \"Резултати от търсенето\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Активиране на агент\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Неуспешно изпращане на тестово известие към Pushover.\",\n  \"components.RequestModal.requestfrom\": \"Заявката на {username} чака одобрение.\",\n  \"components.Discover.FilterSlideover.filters\": \"Филтри\",\n  \"components.RequestCard.unknowntitle\": \"Неизвестно заглавие\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {филм} other {филми}}\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB потребителска оценка\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Създай бот</CreateBotLink> за използване от Seerr\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex списък за гледане\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Етикети\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} не е намерен\",\n  \"components.Discover.discover\": \"Открийте\",\n  \"components.PermissionEdit.admin\": \"Админ\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Трябва да изберете поне един тип известие\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP Порт\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Изпраща се известие за тест към Pushbullet…\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Откажи заявката\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Активиране на агент\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Изпраща се тестово известие към имейл…\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Гарантирано автоматично одобрение за заявки за не-4K медии.\",\n  \"components.Settings.Notifications.encryptionTip\": \"В повечето случаи Implicit TLS използва порт 465, а STARTTLS използва порт 587\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Трябва да предоставите валиден URL адрес\",\n  \"components.RequestList.sortModified\": \"Последно променен\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Заявка в очакване на одобрение\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Автоматично одобряване на филми\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Дайте разрешение за преглед на медийни проблеми, докладвани от други потребители.\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Трябва да предоставите валиден PGP частен ключ\",\n  \"components.RequestList.RequestItem.tvdbid\": \"Идентификатор за TheTVDB\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Маркирайте всички сезони като налични\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Позволете на потребителите също да започнат чат с вашия бот и да конфигурират свои собствени известия\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Основните папки се зареждат…\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Вашият 30-знаков <UsersGroupsLink>идентификатор на потребител или група</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Изпраща се известие за тест към Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Токен за API към приложение\",\n  \"components.PersonDetails.birthdate\": \"Роден {birthdate}\",\n  \"components.PermissionEdit.requestTv\": \"Заявка на сериали\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Токен за достъп\",\n  \"components.Selector.starttyping\": \"Започнете въвеждане на търсене.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Получавайте известия, когато проблемите, за които сте докладвали, получат нови коментари.\",\n  \"components.Settings.Notifications.botAPI\": \"Токен за оторизация на бот\",\n  \"components.Discover.tmdbsearch\": \"TMDB Търсене\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Размер на стойността\",\n  \"components.PermissionEdit.autorequestMovies\": \"Автоматично заявяване на филми\",\n  \"components.RequestModal.requestadmin\": \"Тази заявка ще бъде одобрена автоматично.\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Първа дата за ефир\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Неуспешно изпращане на тестово известие чрез Webhook.\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Гарантирано автоматично одобрение за заявки за 4K филми.\",\n  \"components.PermissionEdit.request4kDescription\": \"Дайте разрешение за изпращане на заявки за 4K медии.\",\n  \"components.RequestModal.cancel\": \"Откажи заявката\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Дайте разрешение за промяна на разширените опции за заявка на медия.\",\n  \"components.Selector.searchKeywords\": \"Търсете ключови думи…\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Пълен актьорски състав\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Вие изпълнявате версия <code>develop</code> на Seerr, която се препоръчва само за тези, които допринасят за разработката или помагат при тестване на последните версии.\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Външен URL адрес\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON съдържание\",\n  \"components.RequestBlock.edit\": \"Редакция на заявка\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} минути времетраене\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Неуспешно изпращане на тестово известие към Gotify.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Неуспешно изпращане на тестово известие към Slack.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Вашият Plex списък за гледане\",\n  \"components.Selector.nooptions\": \"Няма резултати.\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Изберете етикети\",\n  \"components.Settings.RadarrModal.editradarr\": \"Редактирай Radarr сървър\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Изпращайте известия без звук\",\n  \"components.ResetPassword.email\": \"Имейл адрес\",\n  \"components.RequestBlock.languageprofile\": \"Езиков профил\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Трябва да изберете поне един тип известие\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Получавайте известия, когато други потребители съобщават за проблеми.\",\n  \"components.Discover.FilterSlideover.genres\": \"Жанрове\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Този потребител има право да заявяви <strong>{limit}</strong> {type} на всеки <strong>{days}</strong> дни.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Неуспешна обработка на заявката\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Неуспешно изпращане на тестово известие чрез Telegram.\",\n  \"components.RequestList.RequestItem.requested\": \"Заявен\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Помощ за променливи на шаблони\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Настройките за известяване към Pushover са запазени успешно!\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Трябва да въведете парола\",\n  \"components.Login.validationemailrequired\": \"Трябва да предоставите валиден имейл адрес\",\n  \"components.PermissionEdit.requestDescription\": \"Дайте разрешение за изпращане на заявки за не-4K медии.\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Оригинален език\",\n  \"components.MovieDetails.recommendations\": \"Препоръки\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Активиране на агент\",\n  \"components.MovieDetails.markavailable\": \"Маркирайте като наличен\",\n  \"components.RequestBlock.requestedby\": \"Поискано от\",\n  \"components.Discover.resettodefault\": \"Нулиране до първоначално\",\n  \"components.MovieDetails.reportissue\": \"Докладвайте за проблем\",\n  \"components.RequestModal.autoapproval\": \"Автоматично одобрение\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Разрешаване на самоподписани сертификати\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Известието към Pushbullet тест е изпратено!\",\n  \"components.MovieDetails.revenue\": \"Приходи\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Виж повече\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Получавайте известие, когато заявките ви за медии бъдат одобрени.\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {студио} other {студия}}\",\n  \"components.PermissionEdit.advancedrequest\": \"Разширени заявки\",\n  \"components.RequestBlock.decline\": \"Отказ на заявка\",\n  \"components.PersonDetails.appearsin\": \"Изяви\",\n  \"components.PermissionEdit.users\": \"Управление на потребителите\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Изпраща се тестово известие към Gotify…\",\n  \"components.Search.search\": \"Търсене\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Зареждат се профилите за качество…\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Токен за приложение\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Дайте разрешение за преглед на списъците за гледане от Plex на други потребители.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Известието чрез Web push тест е изпратено!\",\n  \"components.ManageSlideOver.opentautulli\": \"Отвори в Tautulli\",\n  \"components.MovieDetails.viewfullcrew\": \"Вижте целия екип\",\n  \"components.Settings.RadarrModal.hostname\": \"Име на хост или IP адрес\",\n  \"components.RequestModal.requestCancel\": \"Заявката за <strong>{title}</strong> е анулирана.\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Устройство по подразбиране\",\n  \"components.RequestCard.tvdbid\": \"Идентификатор за TheTVDB\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Известието за тест към Discord е изпратено!\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Изпращайте известия, когато медийните заявки не могат да бъдат добавени към Radarr или Sonarr.\",\n  \"components.RequestModal.requestmovietitle\": \"Заявка за филм\",\n  \"components.RequestButton.requestmore\": \"Заявете повече\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Проблемът е отворен отново\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {ден} other {дни}}\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Заявката е автоматично одобрена\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Заявки за етикети\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Подписвайте шифровани имейл съобщения с помощта на <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Трябва да имате оставащи поне <strong>{seasons}</strong> {seasons, plural, one {заявка за сезон} other {заявки за сезони}}, за да изпратите заявка за този сериал.\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Маркирайте всички сезони като налични в 4K\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Получавайте известия, когато други потребители изпращат нови медийни заявки, които се одобряват автоматично.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Кешът на {cachename} е изчистен.\",\n  \"components.RequestModal.seasonnumber\": \"Сезон {number}\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB брой гласували потребители\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB Филмови жанрове\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Нулиране до първоначално\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Не остават достатъчно заявки за сезона\",\n  \"components.RequestModal.requestseasons4k\": \"Заявете {seasonCount} {seasonCount, plural, one {сезон} other {сезони}} в 4К\",\n  \"components.RequestModal.pendingrequest\": \"Изчакваща заявка\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Изпраща се известие за тест чрез Webhook…\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Изпращайте известия, когато проблемите се отварят отново.\",\n  \"components.Settings.Notifications.chatIdTip\": \"Започнете чат с вашия бот, добавете <GetIdBotLink>@get_id_bot</GetIdBotLink> и изпълнете командата <code>/my_id</code>\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Активиране на агент\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {сезон} other {сезони}}\",\n  \"components.RequestModal.requestseriestitle\": \"Заявка на сериали\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Използвайте Implicit TLS\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Изтриване на заявка\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Управление на {mediaType}\",\n  \"components.ResetPassword.passwordreset\": \"Нулиране на парола\",\n  \"components.ManageSlideOver.openarr\": \"Отвори в {arr}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезони}}\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Не успяхме автоматично да съпоставим този сериал. Моля, изберете правилното съвпадение по-долу.\",\n  \"components.PermissionEdit.autorequestDescription\": \"Дайте разрешение за автоматично изпращане на заявки за не-4K медии чрез Plex Списък за гледане.\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (подразбиране)\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Настройките за известяване чрез Web push не успяха да бъдат запазени.\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Трябва да предоставите валиден JSON payload\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Филмови жанрове\",\n  \"components.RequestModal.requestcollectiontitle\": \"Заявка на колекция\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Екипа\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {сезон} other {сезони}}\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Изпращайте известия, когато проблемите бъдат разрешени.\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Езиков профил\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Неуспешно изпращане на тестово известие към имейл.\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Брой гласове между {minValue} и {maxValue}\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Проблемът е докладван\",\n  \"components.RequestModal.alreadyrequested\": \"Вече е заявено\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Налична заявка\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Настройките за известяване към Pushbullet не успяха да бъдат запазени.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Гарантирано автоматично одобрение за заявки за 4K сериали.\",\n  \"components.Settings.Notifications.authPass\": \"SMTP Парола\",\n  \"components.Discover.recentrequests\": \"Последни заявки\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Трябва да посочите име на сървъра\",\n  \"components.Login.validationpasswordrequired\": \"Трябва да въведете парола\",\n  \"components.Settings.RadarrModal.server4k\": \"4K сървър\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Изпращайте известия, когато медийните заявки бъдат отхвърлени.\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Трябва да предоставите валиден номер на порт\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Заявката е изпратена автоматично\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Изчистване на данните\",\n  \"components.Settings.RadarrModal.apiKey\": \"API ключ\",\n  \"components.MovieDetails.streamingproviders\": \"В момента се излъчва по\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Видове известия\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Изберете профил за качество\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL адресът не трябва да завършва с наклонена черта в края\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Кеш\",\n  \"components.Discover.upcomingtv\": \"Предстоящи сериали\",\n  \"components.Settings.RadarrModal.tags\": \"Етикети\",\n  \"components.Settings.Notifications.validationUrl\": \"Трябва да предоставите валиден URL адрес\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Кеш име\",\n  \"components.RequestCard.cancelrequest\": \"Откажи заявката\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Получавайте известие, когато проблемите, за които сте докладвали, бъдат разрешени.\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Скриване на наличните медии\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Подробности за лог файл\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Настройките са запазени успешно!\",\n  \"components.UserList.sortRequests\": \"Брой заявки\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Редактирай 4К Sonarr сървър\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Кеш изображения\",\n  \"components.UserProfile.totalrequests\": \"Общо заявки\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Роля\",\n  \"components.StatusChecker.reloadApp\": \"Презареди {applicationTitle}\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli настройките са запазени успешно!\",\n  \"components.Settings.default4k\": \"По подразбиране 4К\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"На всяка {jobScheduleMinutes, plural, one {минута} other {{jobScheduleMinutes} минути}}\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Общ размер на кеша\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Трябва да изберете езиков профил\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Етикетите се зареждат…\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Моля, рестартирайте сървъра, за да приложите актуализираните настройки.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Тип\",\n  \"components.Settings.menuAbout\": \"Относно\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Устройство по подразбиране\",\n  \"components.Settings.SettingsUsers.users\": \"Потребители\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Нещо се обърка при запазване на настройките.\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Неуспешно свързване с Plex.\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.TvDetails.episodeRuntime\": \"Времетраене на епизод\",\n  \"i18n.all\": \"Всичко\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Потребителските настройки са запазени успешно!\",\n  \"components.Settings.notificationsettings\": \"Настройки за известията\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Можете също да видите тези лог файлове директно чрез <code>stdout</code> или в <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# епизод} other {# епизоди}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID на потребител в Discord\",\n  \"components.TvDetails.firstAirDate\": \"Първа дата за ефир\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"components.UserList.validationEmail\": \"Трябва да предоставите валиден имейл адрес\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Потвърди парола\",\n  \"components.Settings.SettingsLogs.logs\": \"Лог файлове\",\n  \"i18n.tvshows\": \"Сериали\",\n  \"i18n.notrequested\": \"Не е заявен\",\n  \"i18n.saving\": \"Запазване…\",\n  \"components.Settings.notifications\": \"Известия\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Настройките са запазени успешно!\",\n  \"components.UserList.edituser\": \"Редактиране на потребителски права\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Настройките за известяване към Telegram са запазени успешно!\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Пълен екип на сериала\",\n  \"pages.somethingwentwrong\": \"Нещо се обърка\",\n  \"components.Settings.radarrsettings\": \"Radarr настройки\",\n  \"i18n.canceling\": \"Отменя се…\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Без етикети.\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Почистване на кеша на изображенията\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Права\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Автоматично заявяване на филми\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Връзката към Sonarr е установена успешно!\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Първоначални права, присвоени на нови потребители\",\n  \"i18n.deleting\": \"Изтриване…\",\n  \"components.Settings.cancelscan\": \"Отказ от сканиране\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Пусни сега\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Настройките за известяване към Pushbullet са запазени успешно!\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Внимание\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Виж детайлите\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Трябва да предоставите API ключ\",\n  \"i18n.save\": \"Запазване на промените\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Трябва да предоставите валиден PGP публичен ключ\",\n  \"components.Settings.SonarrModal.add\": \"Добавете сървър\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Списъкът със сървъри на Plex е извлечен успешно!\",\n  \"components.Settings.serverpresetManualMessage\": \"Ръчна конфигурация\",\n  \"components.UserList.autogeneratepasswordTip\": \"Изпратете генерирана от сървъра парола до потребителя\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Основна папка за аниме\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Език в Открийте\",\n  \"components.TvDetails.similar\": \"Подобни сериали\",\n  \"components.TvDetails.reportissue\": \"Докладвайте за проблем\",\n  \"components.UserList.admin\": \"Админ\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Чат ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Настройките за известяване към Telegram не успяха да бъдат запазени.\",\n  \"components.UserList.validationpasswordminchars\": \"Паролата е твърде кратка; трябва да съдържа минимум 8 знака\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Текуща честота\",\n  \"components.UserList.userfail\": \"Нещо се обърка при запазване на потребителски права.\",\n  \"i18n.retry\": \"Опитайте отново\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Копирано в клипборда\",\n  \"components.TvDetails.overviewunavailable\": \"Прегледът не е наличен.\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Синхронизиране на Plex Списък за гледане\",\n  \"components.UserList.createlocaluser\": \"Създайте локален потребител\",\n  \"components.TvDetails.nextAirDate\": \"Следваща дата на излъчване\",\n  \"components.UserList.sortDisplayName\": \"Показвано име\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Информация\",\n  \"i18n.view\": \"Преглед\",\n  \"components.Settings.scan\": \"Синхронизиране на библиотеки\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Заданието редактирана успешно!\",\n  \"components.UserList.usercreatedsuccess\": \"Потребителят е създаден успешно!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Настройките за известяване по имейл са запазени успешно!\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Заявки за етикети\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Паролите трябва да съвпадат\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Токън за API към приложение\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Трябва да предоставите валиден потребителски идентификатор (User ID) в Discord\",\n  \"i18n.importing\": \"Импортиране.…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Автоматична заявка на сериали\",\n  \"components.UserList.create\": \"Създавайте\",\n  \"i18n.restartRequired\": \"Изисква се рестартиране\",\n  \"components.Settings.tautulliSettingsDescription\": \"По желание конфигурирайте настройките за вашия сървър Tautulli. Seerr извлича данни от хронологията на гледане за вашата Plex медия от Tautulli.\",\n  \"i18n.request\": \"Заявка\",\n  \"components.Settings.validationApiKey\": \"Трябва да предоставите API ключ\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Редактирай Sonarr сървър\",\n  \"components.Settings.addradarr\": \"Добавяне на нов Radarr сървър\",\n  \"components.Settings.notrunning\": \"Не работи\",\n  \"components.Settings.urlBase\": \"Базов URL адрес\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Основна папка\",\n  \"components.Settings.SonarrModal.apiKey\": \"API ключ\",\n  \"components.UserList.userssaved\": \"Потребителските права са запазени успешно!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Този потребителски акаунт в момента няма зададена парола. Конфигурирайте парола по-долу, за да позволите на този акаунт да влиза като „локален потребител“.\",\n  \"components.Settings.mediaTypeMovie\": \"филм\",\n  \"components.Settings.SettingsMain.locale\": \"Език на дисплея\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Непозната задача\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Сканиране на наскоро добавени в Plex\",\n  \"components.UserList.localuser\": \"Локален потребител\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Регион за Открийте\",\n  \"components.UserList.importfromplexerror\": \"Нещо се обърка при импортирането на потребители на Plex.\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Изберете главна папка\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Известия\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Трябва да предоставите валиден URL адрес\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Папки по сезони\",\n  \"i18n.resultsperpage\": \"Показване на {pageSize} резултати на страница\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Глобален лимит за заявки на филми\",\n  \"components.Settings.advancedTooltip\": \"Неправилното конфигуриране на тази настройка може да доведе до нарушена функционалност\",\n  \"components.UserList.newplexsigninenabled\": \"<strong>Локално влизане</strong> в момента е разрешено. Потребителите на Plex с достъп до библиотека не трябва да бъдат импортирани, за да влязат.\",\n  \"components.UserList.deleteconfirm\": \"Сигурни ли сте, че искате да изтриете този потребител? Всички данни за техните заявки ще бъдат премахнати за постоянно.\",\n  \"components.TvDetails.productioncountries\": \"Продукция на {countryCount, plural, one {държава} other {държави}}\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Нещо се обърка при запазване на настройките.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Настройките за известяване по имейл не успяха да бъдат запазени.\",\n  \"components.Settings.hostname\": \"Име на хост или IP адрес\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Автоматично добавяне на допълнителен етикет с потребителското ID и показваното име на заявителя\",\n  \"components.TvDetails.Season.noepisodes\": \"Няма наличен списък с епизоди.\",\n  \"components.Settings.serviceSettingsDescription\": \"Конфигурирайте вашия {serverType} сървър(и) по-долу. Можете да свържете множество {serverType} сървъри, но само два от тях могат да бъдат маркирани като стандартни (един не-4K и един 4K). Администраторите могат да заменят сървъра, използван за обработка на нови заявки преди одобрението.\",\n  \"components.TvDetails.seasonstitle\": \"Сезони\",\n  \"i18n.available\": \"Наличен\",\n  \"components.Settings.menuGeneralSettings\": \"Общ\",\n  \"components.Settings.manualscanDescription\": \"Обикновено това ще се изпълнява само веднъж на всеки 24 часа. Seerr ще проверява наскоро добавения Plex сървър по-агресивно. Ако за първи път конфигурирате Plex, препоръчва се еднократно пълно ръчно сканиране на библиотека!\",\n  \"components.UserList.user\": \"Потребител\",\n  \"i18n.pending\": \"Очаква се\",\n  \"i18n.decline\": \"Откажи\",\n  \"components.StatusChecker.restartRequired\": \"Изисква се рестартиране на сървъра\",\n  \"i18n.movie\": \"Филм\",\n  \"components.UserList.owner\": \"Собственик\",\n  \"components.UserProfile.requestsperdays\": \"{limit} оставащи\",\n  \"components.Settings.SettingsLogs.showall\": \"Показване на всички лог файлове\",\n  \"components.Settings.is4k\": \"4К\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Профил качество\",\n  \"components.TvDetails.recommendations\": \"Препоръки\",\n  \"components.UserList.userdeleteerror\": \"Нещо се обърка при изтриването на потребителя.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Общ\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB потребителска оценка\",\n  \"components.Settings.SettingsJobsCache.process\": \"Процес\",\n  \"components.Settings.plexsettingsDescription\": \"Конфигурирайте настройките за вашия Plex сървър. Seerr сканира вашите Plex библиотеки, за да определи наличното съдържанието.\",\n  \"i18n.import\": \"Импорт\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Заглавие на приложението\",\n  \"components.StatusBadge.playonplex\": \"Пусни в Plex\",\n  \"i18n.open\": \"Отвори\",\n  \"components.Settings.port\": \"Порт\",\n  \"components.Settings.SonarrModal.default4kserver\": \"4K сървър по подразбиране\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr сканиране\",\n  \"pages.serviceunavailable\": \"Услугата не е достъпна\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Трябва да предоставите валиден токен за приложение\",\n  \"components.Settings.librariesRemaining\": \"Оставащи библиотеки: {count}\",\n  \"i18n.advanced\": \"Разширено\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Трябва да предоставите токен за достъп\",\n  \"components.Settings.SettingsJobsCache.command\": \"Команда\",\n  \"components.Settings.tautulliApiKey\": \"API ключ\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Присъединил се на {joindate}\",\n  \"components.TvDetails.anime\": \"Аниме\",\n  \"i18n.areyousure\": \"Сигурни ли сте?\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Неуспешно извличане на списъка със сървъри на Plex.\",\n  \"components.Settings.startscan\": \"Започни сканиране\",\n  \"components.TvDetails.rtaudiencescore\": \"Резултат от публиката на Rotten Tomatoes\",\n  \"components.Settings.SonarrModal.tags\": \"Етикети\",\n  \"components.Settings.menuNotifications\": \"Известия\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Тип на профила\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Трябва да предоставите валиден user ID\",\n  \"components.Setup.configureservices\": \"Конфигуриране на услуги\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Позволете на потребителите на Plex да влизат, без първо да бъдат импортирани\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Език в Открийте\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Изберете профил за качество\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Езиков профил за аниме\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Задания\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Добавяне на нов Sonarr сървър\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} започна.\",\n  \"components.Settings.SettingsLogs.filterError\": \"Грешка\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Прочистване на кеша\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Отмени задание\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Мрежа} other {Мрежи}}\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Основните папки се зареждат…\",\n  \"i18n.collection\": \"Колекция\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Базовият URL адрес не трябва да завършва с наклонена черта в края\",\n  \"components.Settings.SonarrModal.server4k\": \"4K сървър\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Продължи\",\n  \"components.UserList.accounttype\": \"Тип\",\n  \"components.Settings.webAppUrl\": \"URL адрес на <WebAppLink>уеб приложението</WebAppLink>\",\n  \"components.TvDetails.manageseries\": \"Управление на сериали\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Настройките за известяване към Discord не успяха да бъдат запазени.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Вашият акаунт в момента няма зададена парола. Конфигурирайте парола по-долу, за да разрешите влизане като „локален потребител“, използвайки своя имейл адрес.\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Нова честота\",\n  \"components.UserList.created\": \"Присъединиха\",\n  \"components.Settings.currentlibrary\": \"Текуща библиотека: {name}\",\n  \"i18n.resolved\": \"Разрешен\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Нещо се обърка при извличане на данни за сезона.\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Моля, щракнете върху бутона по-долу, за да презаредите приложението.\",\n  \"components.UserList.bulkedit\": \"Групово редактиране\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Трябва да предоставите валиден потребителски или групов ключ\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Нещо се обърка при генерирането на нов API ключ.\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Пауза\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Лимит за заявка на филм\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Неуспешно свързване със Sonarr.\",\n  \"components.Settings.validationUrl\": \"Трябва да предоставите валиден URL адрес\",\n  \"i18n.showingresults\": \"Показани <strong>{from}</strong> до <strong>{to}</strong> от <strong>{total}</strong> резултата\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Трябва да предоставите текущата си парола\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Филтрирайте съдържанието по оригинален език\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Кеширане на външни изображения (изисква значително количество дисково пространство)\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Настройки за известията\",\n  \"components.Settings.noDefaultServer\": \"Поне един {serverType} сървър трябва да бъде маркиран като стандартен, за да могат {mediaType} заявките да бъдат обработени.\",\n  \"components.UserList.email\": \"Имейл адрес\",\n  \"i18n.declined\": \"Отказан\",\n  \"components.Settings.settingUpPlexDescription\": \"За да настроите Plex, можете или да въведете подробностите ръчно, или да изберете сървър, извлечен от <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Натиснете бутона вдясно от падащото меню, за да извлечете списъка с налични сървъри.\",\n  \"components.Settings.plexlibrariesDescription\": \"Библиотеките, които Seerr сканира за заглавия. Настройте и запазете вашите настройки за връзката към Plex, след което щракнете върху бутона по-долу, ако няма изброени библиотеки.\",\n  \"components.TvDetails.seasonnumber\": \"Сезон {seasonNumber}\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Сезон} other {# Сезони}}\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Трябва да посочите име на сървъра\",\n  \"i18n.movies\": \"Филми\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Зареждат се профилите за качество…\",\n  \"i18n.testing\": \"Тествам…\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Нещо се обърка при запазването на паролата. Вашата текуща парола правилно ли е въведена?\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Конфигурирайте глобалните потребителски настройки и настройките по подразбиране.\",\n  \"i18n.noresults\": \"Няма резултати.\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Конфигурирайте и активирайте агенти за уведомяване.\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex потребител\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Добавяне на нов 4K Sonarr сървър\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Изберете езиков профил\",\n  \"components.Settings.SettingsLogs.message\": \"Съобщение\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Общи настройки\",\n  \"components.Settings.tautulliSettings\": \"Tautulli настройки\",\n  \"i18n.test\": \"Тест\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr трябва да се рестартира, за да влязат в сила промените в тази настройка\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Изпращайте известия без звук\",\n  \"components.Settings.validationHostnameRequired\": \"Трябва да предоставите валидно име на хост или IP адрес\",\n  \"i18n.partiallyavailable\": \"Частично наличен\",\n  \"components.UserList.creating\": \"Създаване…\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Актуализиран\",\n  \"i18n.requesting\": \"Заявяване…\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL адресът не трябва да завършва с наклонена черта в края\",\n  \"components.Settings.default\": \"По подразбиране\",\n  \"components.Settings.services\": \"Услуги\",\n  \"components.Settings.address\": \"Адрес\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Трябва да предоставите валидно име на хост или IP адрес\",\n  \"components.Setup.continue\": \"Продължи\",\n  \"components.Settings.externalUrl\": \"Външен URL адрес\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Трябва да предоставите валиден номер на порт\",\n  \"i18n.back\": \"Назад\",\n  \"components.Settings.mediaTypeSeries\": \"серии\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Сървър по подразбиране\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.StatusBadge.openinarr\": \"Отвори в {arr}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Потребител\",\n  \"pages.returnHome\": \"Обратно към Начало\",\n  \"components.Settings.scanning\": \"Синхронизиране…\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Тип аниме сериал\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Отмяна на глобалния лимит\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Текуща парола\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL адресът не трябва да завършва с наклонена черта в края\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Автоматично заявявайте сериали във вашия <PlexWatchlistSupportLink>Plex Списък за гледане</PlexWatchlistSupportLink>\",\n  \"i18n.edit\": \"Редакция\",\n  \"components.Settings.SettingsMain.apikey\": \"API ключ\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Започнете чат</TelegramBotLink>, добавете <GetIdBotLink>@get_id_bot</GetIdBotLink>, и изпълнете команда <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Токен за достъп\",\n  \"components.Settings.SettingsLogs.time\": \"Времево клеймо\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Нямате права, за да промените настройките на този потребител.\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Тествайте връзката за зареждане на основните папки\",\n  \"i18n.processing\": \"В обработка\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Конфигурирайте глобалните настройки и настройките по подразбиране за Seerr.\",\n  \"components.UserList.password\": \"Парола\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Правата са запазени успешно!\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Тествайте връзката, за да заредите профилите за качество\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Име на задание\",\n  \"i18n.previous\": \"Предишен\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Нов API ключ е генериран успешно!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Трябва да предоставите нова парола\",\n  \"components.MovieDetails.physicalrelease\": \"Физическо издание\",\n  \"components.Settings.toastPlexRefresh\": \"Списък със сървъри се извлича от Plex…\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Потребителски настройки\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Активирайте кеширането на изображения\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Нова парола\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Активирайте сканирането\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Известия\",\n  \"i18n.retrying\": \"Повторно…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Потребителски идентификатор (User ID)\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Настройките за известяване към Pushover са запазени успешно!\",\n  \"components.Settings.deleteServer\": \"Изтриване на сървър {serverType}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Потребителски или групов ключ\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Настройките за известяване към Pushbullet не успяха да бъдат запазени.\",\n  \"components.TvDetails.showtype\": \"Тип сериали\",\n  \"components.UserList.localLoginDisabled\": \"<strong>Локално влизане</strong> настройката в момента е деактивирана.\",\n  \"i18n.failed\": \"Неуспешно\",\n  \"pages.pagenotfound\": \"Страницата не е намерена\",\n  \"components.Settings.toastPlexConnecting\": \"Опит за свързване с Plex…\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Пълно сканиране на Plex библиотека\",\n  \"components.Settings.SonarrModal.selecttags\": \"Изберете етикети\",\n  \"i18n.next\": \"Следващ\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"<FindDiscordIdLink>Номерът</FindDiscordIdLink> асоцийран с вашият Discord потребителски профил\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Имейл\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Нещо се обърка при запазването на паролата.\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Трябва да изберете профил за качество\",\n  \"components.UserList.role\": \"Роля\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Външен URL адрес\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Езиковите профили се зареждат…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Изпрати безшумно\",\n  \"i18n.requested\": \"Заявен\",\n  \"components.Settings.validationPortRequired\": \"Трябва да предоставите валиден номер на порт\",\n  \"i18n.delete\": \"Изтрий\",\n  \"components.TvDetails.viewfullcrew\": \"Вижте целия екип\",\n  \"components.Settings.activeProfile\": \"Активен профил\",\n  \"components.Settings.SonarrModal.seriesType\": \"Тип сериали\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Парола\",\n  \"components.Settings.serverLocal\": \"локален\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Редактиране на настройките\",\n  \"i18n.approved\": \"Одобрен\",\n  \"components.UserProfile.unlimited\": \"Неограничен\",\n  \"i18n.tvshow\": \"Сериали\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Синхронизиране на изтеглянията\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Админ\",\n  \"components.UserList.userlist\": \"Списък с потребители\",\n  \"components.UserProfile.limit\": \"{remaining} от {limit}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"На всяка {jobScheduleSeconds, plural, one {секунда} other {{jobScheduleSeconds} секунда}}\",\n  \"components.Settings.deleteserverconfirm\": \"Сигурни ли сте, че искате да изтриете този сървър?\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Език на дисплея\",\n  \"components.TvDetails.watchtrailer\": \"Гледайте трейлър\",\n  \"components.Settings.serverpreset\": \"Сървър\",\n  \"components.Settings.SonarrModal.servername\": \"Име на сървъра\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Езиков профил\",\n  \"components.Settings.menuUsers\": \"Потребители\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Автоматично заявявайте филми във вашия <PlexWatchlistSupportLink>Plex Списък за гледане</PlexWatchlistSupportLink>\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL адреса трябва да има водеща наклонена черта\",\n  \"components.StatusBadge.managemedia\": \"Управление на {mediaType}\",\n  \"components.UserList.deleteuser\": \"Изтриване на потребител\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Нещо се обърка при запазване на настройките.\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Пълен актьорски състав на сериала\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.Setup.finishing\": \"Завършва се…\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Изображенията са кеширани\",\n  \"components.Settings.serverpresetLoad\": \"Натиснете бутона, за да заредите наличните сървъри\",\n  \"components.Settings.email\": \"Имейл\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Профил за качество на аниме\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Активиране на локално влизане\",\n  \"components.Settings.menuLogs\": \"Лог файлове\",\n  \"components.Settings.sonarrsettings\": \"Sonarr настройки\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Показвано име\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL адресът не трябва да завършва с наклонена черта в края\",\n  \"components.Settings.addsonarr\": \"Добавяне на Sonarr сървър\",\n  \"components.Settings.plexlibraries\": \"Plex Библиотеки\",\n  \"components.UserList.passwordinfodescription\": \"Конфигурирайте URL адрес на приложение и активирайте известия по имейл, за да позволите автоматично генериране на парола.\",\n  \"components.UserList.sortCreated\": \"Дата на присъединяване\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL адрес на приложението\",\n  \"components.Settings.SettingsLogs.label\": \"Етикет\",\n  \"i18n.loading\": \"Зареждане…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Настройките за известяване към Pushover не успяха да бъдат запазени.\",\n  \"components.Settings.SettingsLogs.level\": \"Тежест\",\n  \"components.UserProfile.movierequests\": \"Заявки за филми\",\n  \"components.UserProfile.pastdays\": \"{type} (преди {days} дни)\",\n  \"components.Settings.SettingsMain.general\": \"Общ\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Потребителски идентификатор: {userid}\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr сканиране\",\n  \"components.UserList.importfromplex\": \"Импортиране на потребители на Plex\",\n  \"components.Settings.SonarrModal.port\": \"Порт\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Създайте токен от вашите <PushbulletSettingsLink>Настройки на акаунта</PushbulletSettingsLink>\",\n  \"components.UserList.userdeleted\": \"Потребителят е изтрит успешно!\",\n  \"components.Settings.serverSecure\": \"сигурен\",\n  \"components.Setup.finish\": \"Завършете настройката\",\n  \"components.Settings.experimentalTooltip\": \"Активирането на тази настройка може да доведе до неочаквано поведение на приложението\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Не можете да променяте собствените си права.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Звук за известяване\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Базовият URL адрес трябва да има водеща наклонена черта\",\n  \"components.Settings.serverpresetRefreshing\": \"Сървърите се получават…\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Тествайте връзката за зареждане на езикови профили\",\n  \"i18n.request4k\": \"Заявка в 4K\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} е отменено.\",\n  \"components.UserProfile.seriesrequest\": \"Заявки за сериали\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Дебъг\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Паролата е твърде кратка; трябва да съдържа минимум 8 знака\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Трябва да изберете основна папка\",\n  \"components.Setup.signinMessage\": \"Започнете, като влезете с вашия Plex акаунт\",\n  \"components.Settings.manualscan\": \"Ръчно сканиране на библиотека\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"<FindDiscordIdLink>ID номерът</FindDiscordIdLink> асоцийран с вашият потребителски акаунт\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Разрешаване на частични заявки за сериали\",\n  \"components.Settings.SonarrModal.hostname\": \"Име на хост или IP адрес\",\n  \"components.Setup.setup\": \"Настройване\",\n  \"components.UserProfile.emptywatchlist\": \"Мултимедията, добавена към вашия <PlexWatchlistSupportLink>списък за гледане в Plex</PlexWatchlistSupportLink>, ще се появи тук.\",\n  \"components.Settings.enablessl\": \"Използвай SSL\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Позволете на потребителите да влизат, като използват своя имейл адрес и парола\",\n  \"components.Settings.noDefaultNon4kServer\": \"Ако имате само един сървър {serverType} както за съдържание, което не е 4K, така и за 4K (или ако изтегляте само 4K съдържание), вашият сървър {serverType} трябва <strong>ДА НЕ БЪДЕ</strong> обозначен като 4K сървър.\",\n  \"components.UserList.nouserstoimport\": \"Няма Plex потребители за импортиране.\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Виж профил\",\n  \"components.Setup.welcome\": \"Добре дошли в Seerr\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Лимит за заявки на сериали\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} не е намерен\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Вашият 30-знаков <UsersGroupsLink>идентификатор на потребител или група</UsersGroupsLink>\",\n  \"components.UserProfile.recentlywatched\": \"Наскоро гледани\",\n  \"components.UserList.users\": \"Потребители\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Задания и кеш\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr изпълнява определени задачи по поддръжката като редовно планирани задачи, но те също могат да бъдат ръчно задействани по-долу. Ръчното изпълнение на задание няма да промени неговия график.\",\n  \"components.Settings.SonarrModal.animeTags\": \"Етикети за аниме\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Кодирай имейлите използвайки <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Базов URL адрес\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Филтрирайте съдържанието по оригинален език\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Връзката с Plex е установена успешно!\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Общ\",\n  \"components.Settings.SettingsLogs.extraData\": \"Допълнителни данни\",\n  \"components.UserList.plexuser\": \"Plex потребител\",\n  \"components.UserProfile.plexwatchlist\": \"Plex списък за гледане\",\n  \"components.TvDetails.streamingproviders\": \"В момента се излъчва по\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"На всеки {jobScheduleHours, plural, one {час} other {{jobScheduleHours} часа}}\",\n  \"components.TvDetails.originaltitle\": \"Оригинално заглавие\",\n  \"components.Settings.noDefault4kServer\": \"4K {serverType} сървър трябва да бъде маркиран като стандартен, за да може потребителите да изпращат 4K {mediaType} заявки.\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Глобален лимит за заявка на сериали\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Нещо се обърка при запазване на настройките.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"По подразбиране ({language})\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"URL адресът не трябва да завършва с наклонена черта в края\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Когато е активиран в настройките, Seerr ще бъде прокси и ще кешира изображения от предварително конфигурирани външни източници. Кешираните изображения се записват във вашата конфигурационна папка. Можете да намерите файловете в <code>{appDataPath}/cache/images</code>.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"PGP публичен ключ\",\n  \"components.TitleCard.cleardata\": \"Изчистване на данните\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Нямате права, за да промените паролата на този потребител.\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Нещо се обърка при запазване на настройките на Tautulli.\",\n  \"pages.internalservererror\": \"Вътрешна грешка в сървъра\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Регистриране на приложение</ApplicationRegistrationLink> за използване с {applicationTitle}\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Следващо изпълнение\",\n  \"components.UserList.totalrequests\": \"Заявки\",\n  \"i18n.close\": \"Затвори\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Трябва да предоставите валиден URL адрес\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Общи настройки\",\n  \"components.TvDetails.cast\": \"Участват\",\n  \"i18n.approve\": \"Одобряване\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Локален потребител\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Нещо се обърка при запазване на заданието.\",\n  \"i18n.usersettings\": \"Потребителски настройки\",\n  \"components.Settings.menuServices\": \"Услуги\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Активирайте автоматичното търсене\",\n  \"i18n.cancel\": \"Отказ\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Трябва да потвърдите новата парола\",\n  \"components.UserList.usercreatedfailedexisting\": \"Предоставеният имейл адрес вече се използва от друг потребител.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Собственик\",\n  \"components.TitleCard.tvdbid\": \"Идентификатор за TheTVDB\",\n  \"components.Settings.serverRemote\": \"отдалечен\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Парола\",\n  \"i18n.experimental\": \"Експериментален\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Промяна на задание\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Трябва да предоставите валиден chat ID\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Успешно записана паролата!\",\n  \"components.UserProfile.recentrequests\": \"Последни заявки\",\n  \"i18n.unavailable\": \"Неналичен\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Права по подразбиране\",\n  \"pages.oops\": \"Опааа\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} минути\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Филтрирайте съдържанието по регионална наличност\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Тествайте връзката за зареждане на тагове\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Права\",\n  \"components.UserList.autogeneratepassword\": \"Автоматично генериране на парола\",\n  \"components.Settings.webAppUrlTip\": \"По избор насочете потребителите към уеб приложението на вашия сървър вместо към „хостваното“ уеб приложение\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Трябва да посочите заглавие на приложението\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Лог файл е копиран в клипборда.\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {потребител} other {потребители}} импортиран(и) успешно!\",\n  \"i18n.status\": \"Статус\",\n  \"components.Settings.SonarrModal.ssl\": \"Използвай SSL\",\n  \"components.TvDetails.originallanguage\": \"Оригинален език\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Нулиране на синхронизирането на изтеглянията\",\n  \"components.UserList.usercreatedfailed\": \"Нещо се обърка при създаването на потребителя.\",\n  \"components.TvDetails.overview\": \"Преглед\",\n  \"components.Settings.plexsettings\": \"Plex Настройки\",\n  \"components.Settings.menuJobs\": \"Задания и кеш\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Активиране на ново влизане в Plex\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Настройките за известяване към Discord са запазени успешно!\",\n  \"i18n.settings\": \"Настройки\",\n  \"components.Login.back\": \"Обратно\",\n  \"components.Discover.FilterSlideover.status\": \"Статус\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Невалиден имейл адрес.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Трябва да предоставите имейл адрес.\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Предстоящи сериали\",\n  \"components.Login.credentialerror\": \"Въведено неправилно име или парола.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Необхода е парола.\",\n  \"components.Login.adminerror\": \"Трябва да използвате администраторски акаунт при вписване.\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Това ще премахне необратимо този/тази {mediaType} от {arr}, заедно с всички свързани файлове.\",\n  \"components.Login.noadminerror\": \"На сървъра не е открит администратор.\",\n  \"components.Login.validationemailformat\": \"Изисква се валиден имейл адрес\",\n  \"components.Login.username\": \"Потребителско име\",\n  \"components.Login.validationhostformat\": \"Изисква се валиден URL адрес\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"Базовият URL адрес не трябва да завършва с наклонена черта\",\n  \"components.Login.validationhostrequired\": \"Изисква се {mediaServerName} URL адрес\",\n  \"components.Login.description\": \"Тъй като това е първото Ви влизане в {applicationName}, трябва да добавите валиден имейл адрес.\",\n  \"components.Login.emailtooltip\": \"Не е необходимо имейл адресът да бъде свързан с вашия {mediaServerName} сървър.\",\n  \"components.Login.enablessl\": \"Използвай SSL\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.initialsignin\": \"Свързване\",\n  \"components.Login.initialsigningin\": \"Установява се връзка…\",\n  \"components.Login.invalidurlerror\": \"Не може да се осъществи връзка със сървъра {mediaServerName}.\",\n  \"components.Login.loginwithapp\": \"Влез със {appName}\",\n  \"components.Login.orsigninwith\": \"Или влез със\",\n  \"components.Login.port\": \"Порт\",\n  \"components.Login.save\": \"Добави\",\n  \"components.Login.servertype\": \"Тип на сървъра\",\n  \"components.Login.signinwithjellyfin\": \"Използвай своя {mediaServerName} акаунт\",\n  \"components.Login.title\": \"Добави имейл\",\n  \"components.Login.urlBase\": \"Основен URL\",\n  \"components.Login.validationEmailFormat\": \"Невалиден имейл адрес\",\n  \"components.Login.validationEmailRequired\": \"Трябва да въведете имейл адрес\",\n  \"components.Login.validationPortRequired\": \"Трябва да въведете валиден номер на порт\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"Базовият URL адрес трявба да започва със наклонена черта\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL адресът не трябва да завършва с наклонена черта\",\n  \"components.Login.validationservertyperequired\": \"Моля изберете тип на сървъра\",\n  \"components.Login.validationusernamerequired\": \"Изисква се потребителско име\",\n  \"components.Login.saving\": \"Добавяне…\",\n  \"components.MovieDetails.openradarr\": \"Отвори филма в Radarr\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Профил за качество\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"НЕ активирайте тази настройка освен ако не знаете какво правите!\",\n  \"components.MovieDetails.play\": \"Пусни на {mediaServerName}\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> Успешно премахнат от листата за гледане!\",\n  \"components.Selector.canceled\": \"Отказано\",\n  \"components.Selector.searchUsers\": \"Избери потребители…\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Приложи това правило за избраната услуга.\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Нещо се обърка докато запаметявахте настройките.\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Потребителски аватари\",\n  \"components.Settings.apiKey\": \"API ключ\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Игнорирани прокси адреси\",\n  \"components.MovieDetails.addtowatchlist\": \"Добави към листата за гледане\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Жанрове\",\n  \"components.ManageSlideOver.removearr\": \"Премахни от {arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"Премахни от 4К {arr}\",\n  \"components.MovieDetails.downloadstatus\": \"Статус на сваляне\",\n  \"components.MovieDetails.openradarr4k\": \"Отвори филма в 4К Radarr\",\n  \"components.MovieDetails.play4k\": \"Пусни 4К на {mediaServerName}\",\n  \"components.MovieDetails.removefromwatchlist\": \"Премахни от листата за гледане\",\n  \"components.MovieDetails.watchlistError\": \"Нещо се обърка.Моля опитайте отново.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> Успешно добавен към листата за гледане!\",\n  \"components.RequestList.RequestItem.profileName\": \"Профил\",\n  \"components.RequestList.RequestItem.removearr\": \"Премахване от {arr}\",\n  \"components.Selector.inProduction\": \"В продукция\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Състояние\",\n  \"components.Settings.OverrideRuleModal.create\": \"Създайте правило\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Ключови думи\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Езици\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Без тагове.\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Изберете профил за капество\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Изберете услуга\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Изберете тагове\",\n  \"components.Settings.OverrideRuleModal.service\": \"Услуга\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Настройки\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Тагове\",\n  \"components.Settings.OverrideRuleModal.users\": \"Потребители\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Жанр\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Ключови думи\",\n  \"components.Settings.OverrideRuleTile.language\": \"Език\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Профил за капество\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Настройки\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Тагове\",\n  \"components.Settings.OverrideRuleTile.users\": \"Потребители\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Пълно сканиране на библиотеката Jellyfin\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Позволи искане за специални епизоди\",\n  \"components.Settings.SettingsNetwork.docs\": \"Документация\",\n  \"components.Settings.SettingsNetwork.network\": \"Мрежа\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Мрежови настройки\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Прокси парола\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Прокси порт\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Използвайте SSL за прокси\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Прокси потребител\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Настройките са запаметени успешно!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Активирай прокси поддръжка\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Трябва да предоставите валиден порт\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Метод за влизане\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Настройте методи за влизане напотребителите\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Позволи на потребителите да се вписват с техния {mediaServerName} акаунт\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Изисква потребителски е-майл\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName} Настройки\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Нещо се обърка докато запаметявахте {mediaServerName} настройките.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName} настройките са запазени успешно!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Друг потребител вече използва това потребителско име. Трябва да въведете е-майл\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Този акаунт вече е свързан с {applicationName} потребител\",\n  \"components.TvDetails.removefromwatchlist\": \"Премахни от листата за гледане\",\n  \"components.UserList.validationUsername\": \"Трябва да предоставите потребителско име\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Трябва да предоставите потребителско име\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Свързани акаунти\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Този е-майл вече се използва!\",\n  \"components.UserProfile.localWatchlist\": \"Списък за гледане на {username}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Появи се непозната грешка\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Парола\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Трябва да предоставите парола\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Добавяне…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Потребителско име\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"Е-майл\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName} Потребител\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Запамети промените\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Запазване…\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Появи се непозната грешка\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Свързани акаунти\",\n  \"i18n.specials\": \"Специални\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/ca.json",
    "content": "{\n  \"components.Login.email\": \"Adreça electrònica\",\n  \"components.UserList.email\": \"Adreça electrònica\",\n  \"components.UserList.edituser\": \"Editeu els permisos d'usuari\",\n  \"components.UserList.deleteuser\": \"Suprimeix l'usuari\",\n  \"components.UserList.deleteconfirm\": \"Esteu segur que voleu suprimir aquest usuari? S'eliminaran totes les sol·licituds de forma permanent.\",\n  \"components.UserList.creating\": \"S'està creant …\",\n  \"components.UserList.createlocaluser\": \"Crea un usuari local\",\n  \"components.UserList.created\": \"Registre\",\n  \"components.UserList.create\": \"Crea\",\n  \"components.UserList.bulkedit\": \"Edició massiva\",\n  \"components.UserList.autogeneratepassword\": \"Genereu automàticament una contrasenya\",\n  \"components.UserList.admin\": \"Administrador\",\n  \"components.UserList.accounttype\": \"Tipus\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Podeu veure un resum dels límits de sol·licituds d’aquest usuari a la seva <ProfileLink>pàgina de perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Necessites tenir al menys <strong>{seasons}</strong> {seasons, plural, one {petició de temporada} other {peticions de temporades}} restant(s) per a poder enviar una petició per a aquesta sèrie.\",\n  \"components.RequestModal.pendingrequest\": \"Sol·licitud pendent\",\n  \"components.RequestModal.pending4krequest\": \"Sol·licitud en 4K pendent\",\n  \"components.RequestModal.numberofepisodes\": \"# d'episodis\",\n  \"components.RequestModal.errorediting\": \"S'ha produït un error en editar la sol·licitud.\",\n  \"components.RequestModal.cancel\": \"Cancel·la la sol·licitud\",\n  \"components.RequestModal.autoapproval\": \"Aprovació automàtica\",\n  \"components.RequestModal.alreadyrequested\": \"Ja s'ha sol·licitat\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"No s'ha pogut trobar coincidència d'aquesta serie. Seleccioneu l'emparellament correcte de la llista següent.\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {temporada} other {temporades}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"temporada\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Aquest usuari ha de tenir almenys <strong>{seasons}</strong> {seasons, plural, one {sol·licitud de temporada} other {sol·licituds de temporades}} per enviar una sol·licitud per a aquesta sèrie.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {sol·licitud} other {sol·licituds}} restant(s)\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Podeu veure un resum dels límits de sol·licituds a la vostra <ProfileLink>pàgina de perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"No podeu sol·licitar més temporades\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {pel·lícula} other {pel·lícules}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"Pel·lícula\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Aquest usuari pot sol·licitar <strong>{limit}</strong> {type} cada <strong>{days}</strong> dies.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Podeu sol·licitar <strong>{limit}</strong> {type} cada <strong>{days}</strong> dies.\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Carpeta arrel\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Sol·licita com a\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Perfil de qualitat\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Perfil d'idioma\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Servidor de destí\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Predeterminat)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Aquesta sèrie es un anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avançat\",\n  \"components.RequestList.sortModified\": \"Última modificació\",\n  \"components.RequestList.sortAdded\": \"Més recent\",\n  \"components.RequestList.showallrequests\": \"Mostra totes les sol·licituds\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Estudis} other {Estudis}}\",\n  \"components.RequestList.RequestItem.requested\": \"Sol·licitat\",\n  \"components.PermissionEdit.request\": \"Sol·licitud\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporades}}\",\n  \"components.PermissionEdit.usersDescription\": \"Concedeix permís per gestionar els usuaris d'Seerr. Els usuaris amb aquest permís no poden modificar els usuaris administrador ni concedir aquest privilegi a altres.\",\n  \"components.PermissionEdit.request4k\": \"Sol·licita 4K\",\n  \"components.MovieDetails.revenue\": \"Recaptació\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporades}}\",\n  \"components.RequestList.requests\": \"Sol·licituds\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporades}}\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} per {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Modificat\",\n  \"components.RequestList.RequestItem.failedretry\": \"S'ha produït un error en tornar a demanar la sol·licitud.\",\n  \"components.RequestButton.viewrequest4k\": \"Veure sol·licitud 4K\",\n  \"components.RequestButton.viewrequest\": \"Veure sol·licitud\",\n  \"components.RequestButton.requestmore4k\": \"Sol·licita més en 4K\",\n  \"components.RequestButton.requestmore\": \"Sol·licita'n més\",\n  \"components.RequestButton.declinerequests\": \"Rebutja {requestCount, plural, one {sol·licitud} other {{requestCount} sol·licituds}\",\n  \"components.RequestButton.declinerequest4k\": \"Rebutja sol·licitud 4K\",\n  \"components.RequestButton.declinerequest\": \"Rebutja sol·licitud\",\n  \"components.RequestButton.decline4krequests\": \"Rebutja {requestCount, plural, one {sol·licitud en 4K} other {{requestCount} sol·licituds en 4K}\",\n  \"components.RequestButton.approverequests\": \"Aprova {requestCount, plural, one {sol·licitud} other {{requestCount} sol·licituds}}\",\n  \"components.RequestButton.approverequest4k\": \"Aprova la sol·licitud 4K\",\n  \"components.RequestButton.approverequest\": \"Aprova la sol·licitud\",\n  \"components.RequestButton.approve4krequests\": \"Aprova {requestCount, plural, one {solicitud en 4K} other {{requestCount} sol·licituds en 4K}}\",\n  \"components.RequestBlock.server\": \"Servidor de destí\",\n  \"components.RequestBlock.rootfolder\": \"Carpeta arrel\",\n  \"components.RequestBlock.requestoverrides\": \"Anul·lacions de sol·licituds\",\n  \"components.RequestBlock.profilechanged\": \"Perfil de qualitat\",\n  \"components.RegionSelector.regionServerDefault\": \"Predeterminada ({Region})\",\n  \"components.RegionSelector.regionDefault\": \"Totes les regions\",\n  \"components.QuotaSelector.unlimited\": \"Il·limitat\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.crewmember\": \"Equip\",\n  \"components.PersonDetails.birthdate\": \"Nascut/da {birthdate}\",\n  \"components.PersonDetails.ascharacter\": \"com a {character}\",\n  \"components.PersonDetails.appearsin\": \"Aspectes\",\n  \"components.PersonDetails.alsoknownas\": \"També conegut com: {names}\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Concedeix permís per veure les sol·licituds de continguts d'altres usuaris.\",\n  \"components.PermissionEdit.viewrequests\": \"Veure sol·licituds\",\n  \"components.PermissionEdit.users\": \"Gestiona els usuaris\",\n  \"components.PermissionEdit.requestDescription\": \"Concedeix permís per sol·licitar contingut no 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Concedeix permís per sol·licitar sèrie en 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"Sol·licita Sèrie en 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Concedeix permís per sol·licitar pel·lícules en 4K.\",\n  \"components.PermissionEdit.request4kMovies\": \"Sol·licitud de pel·lícules en 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Concedeix permís per sol·licitar contingut en 4K.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Concedeix permís per gestionar les sol·licituds de contingut d'Seerr. Totes les sol·licituds que faci un usuari amb aquest permís s’aprovaran automàticament.\",\n  \"components.PermissionEdit.managerequests\": \"Gestiona les sol·licituds\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Concedeix l’aprovació automàtica de les sol·licituds de sèries que no siguin 4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Aprovació automàtica de sèries\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Concedeix l’aprovació automàtica de les sol·licituds de pel·lícules que no siguin 4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Aprovació automàtica de pel·lícules\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Concedeix l’aprovació automàtica a totes les sol·licituds de contingut que no siguin 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Concedeix l'aprovació automàtica de les sol·licituds de sèries 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Aprovació automàtica Sèries en 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Concedeix l’aprovació automàtica per a les sol·licituds de pel·lícules 4K.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Aprova automàticament pel·lícules 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Concedeix l’aprovació automàtica a totes les sol·licituds de contingut 4K.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Aprovació automàtica 4K\",\n  \"components.PermissionEdit.autoapprove\": \"Aprovació automàtica\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Sol·licitud rebutjada\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Sol·licitud pendent d'aprovació\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Envieu notificacions quan els usuaris envien sol·licituds de contingut nous que s’aprovin automàticament.\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Dona permís per modificar opcions avançades en les sol·licituds de contingut.\",\n  \"components.PermissionEdit.advancedrequest\": \"Sol·licituds avançades\",\n  \"components.PermissionEdit.adminDescription\": \"Accés complet d'administrador. Ignora totes les altres comprovacions de permisos.\",\n  \"components.PermissionEdit.admin\": \"Administrador\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Envia notificacions quan es sol·licita contingut que requereix aprovació.\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Envia notificacions quan el contingut sol·licitat no s’afegeix a Radarr o Sonarr.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"S'ha produït un error en el processament de la sol·licitud\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Envia notificacions quan es rebutja una sol·licitud.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Envia notificacions quan la sol·licitud estigui disponible.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Sol·licitud disponible\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Envia notificacions quan la sol·licitud s’aprova manualment.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Sol·licitud aprovada\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Sol·licituds aprovades automàticament\",\n  \"components.MovieDetails.watchtrailer\": \"Mireu el tràiler\",\n  \"components.MovieDetails.viewfullcrew\": \"Veure equip complet\",\n  \"components.MovieDetails.similar\": \"Títols similars\",\n  \"components.MovieDetails.runtime\": \"Ingressos\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Data} other {Dates}} de llançament\",\n  \"components.MovieDetails.recommendations\": \"Recomanacions\",\n  \"components.MovieDetails.overviewunavailable\": \"Descripció general no disponible.\",\n  \"components.MovieDetails.overview\": \"Visió general\",\n  \"components.MovieDetails.originaltitle\": \"Títol original\",\n  \"components.MovieDetails.originallanguage\": \"Idioma original\",\n  \"components.MovieDetails.markavailable\": \"Marca com a disponible\",\n  \"components.MovieDetails.mark4kavailable\": \"Marca com a disponible en 4K\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Heu de seleccionar un perfil de qualitat\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Heu de proporcionar un número de port vàlid\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Heu de proporcionar un nom de servidor\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Heu de seleccionar una disponibilitat mínima\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Heu de proporcionar un nom d’amfitrió o una adreça IP vàlides\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"L'URL base no pot acabar amb una barra inclinada final\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"L'URL base ha de tenir una barra inclinada\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Heu de proporcionar un URL vàlid\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"L'URL no pot acabar amb una barra inclinada final\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Heu de proporcionar una clau API\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"La connexió amb Radarr s'ha establert correctament!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"No s'ha pogut connectar amb Radarr.\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Proveu la connexió per carregar les carpetes arrel\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Prova la connexió per carregar perfils de qualitat\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Activa l’escaneig\",\n  \"components.Settings.RadarrModal.ssl\": \"Utilitza SSL\",\n  \"components.Settings.RadarrModal.servername\": \"Nom del Servidor\",\n  \"components.Settings.RadarrModal.server4k\": \"Servidor 4K\",\n  \"components.MovieDetails.cast\": \"Repartiment\",\n  \"components.MovieDetails.budget\": \"Pressupost\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Equip complet\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Repartiment complet\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Veure més\",\n  \"components.Login.validationpasswordrequired\": \"Heu de proporcionar una contrasenya\",\n  \"components.Login.validationemailrequired\": \"Heu de proporcionar una adreça de correu electrònic vàlida\",\n  \"components.Login.signinwithplex\": \"Utilitzeu el vostre compte de Plex\",\n  \"components.Login.signinwithoverseerr\": \"Utilitzeu el vostre compte de {applicationTitle}\",\n  \"components.Login.signinheader\": \"Inicieu sessió per continuar\",\n  \"components.Login.signingin\": \"S'està iniciant la sessió…\",\n  \"components.Login.signin\": \"Inicieu la sessió\",\n  \"components.Login.password\": \"Contrasenya\",\n  \"components.Login.loginerror\": \"S'ha produït un error en intentar iniciar la sessió.\",\n  \"components.Login.forgotpassword\": \"Has oblidat la contrasenya?\",\n  \"components.Layout.UserDropdown.signout\": \"Tanqueu la sessió\",\n  \"components.Layout.UserDropdown.settings\": \"Configuració\",\n  \"components.Layout.UserDropdown.myprofile\": \"Perfil\",\n  \"components.Layout.Sidebar.users\": \"Usuaris\",\n  \"components.Layout.Sidebar.settings\": \"Configuració\",\n  \"components.Layout.Sidebar.requests\": \"Sol·licituds\",\n  \"components.Layout.Sidebar.dashboard\": \"Descobriu\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Cerqueu Pel·lícules i Sèries\",\n  \"components.Discover.upcomingtv\": \"Pròximes sèries\",\n  \"components.Discover.upcomingmovies\": \"Pròximes pel·lícules\",\n  \"components.Discover.upcoming\": \"Pròximes pel·lícules\",\n  \"components.Discover.trending\": \"Tendències\",\n  \"components.Discover.recentrequests\": \"Sol·licituds recents\",\n  \"components.Discover.recentlyAdded\": \"Afegit recentment\",\n  \"components.Discover.populartv\": \"Sèries populars\",\n  \"components.Discover.popularmovies\": \"Pel·lícules populars\",\n  \"components.Discover.discover\": \"Descobriu\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Gèneres de Sèries\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Gèneres de Sèries\",\n  \"components.Discover.StudioSlider.studios\": \"Estudis\",\n  \"components.Discover.NetworkSlider.networks\": \"Emissors\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Gèneres de Pel·lícules\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Gèneres de Pel·lícules\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Sèries en {language}\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Sèries de {genre}\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Pel·lícules de {studio}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Sèries de {network}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Pel·lícules en {language}\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Pel·lícules de {genre}\",\n  \"components.CollectionDetails.requestcollection4k\": \"Sol·licita Col·lecció en 4K\",\n  \"components.CollectionDetails.requestcollection\": \"Sol·licita Col·lecció\",\n  \"components.CollectionDetails.overview\": \"Sinopsi\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Pel·lícules\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"El muntatge de volum <code> {appDataPath} </code> no s'ha configurat correctament. Totes les dades s’esborraran quan el contenidor s’aturi o es reiniciï.\",\n  \"components.RequestModal.requestfrom\": \"La sol·licitud de {username} està pendent d'aprovació.\",\n  \"components.RequestModal.requesterror\": \"S'ha produït un error en enviar la sol·licitud.\",\n  \"components.RequestModal.requestedited\": \"Sol·licitud per a <strong>{title}</strong> editada correctament!\",\n  \"components.RequestModal.requestcancelled\": \"S'ha cancel·lat la sol·licitud de <strong>{title}</strong>.\",\n  \"components.RequestModal.requestadmin\": \"Aquesta sol·licitud s'aprovarà automàticament.\",\n  \"components.RequestModal.requestCancel\": \"S'ha cancel·lat la sol·licitud de <strong>{title}</strong>.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> s'ha sol·licitat correctament!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Heu de proporcionar un URL vàlid\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"La configuració de notificacions Slack s'ha desat correctament!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"No s'ha pogut desar la configuració de notificacions Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Activa l'agent\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Heu de proporcionar una clau d'usuari o grup vàlida\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Heu de proporcionar un testimoni d’aplicació vàlid\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Clau d'usuari o grup\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"La configuració de notificacions Pushover s'ha desat correctament!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"No s'ha pogut desar la configuració de les notificacions de Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Activa l'agent\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Testimoni de l'API de l'aplicació\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Heu de proporcionar un testimoni d'accés\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"La configuració de les notificacions de pushbullet s'ha desat correctament!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"No s'ha pogut desar la configuració de notificacions de Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Activa l'agent\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Testimoni d'accés\",\n  \"components.Search.searchresults\": \"Resultats de la cerca\",\n  \"components.Search.search\": \"Cerca\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Heu de proporcionar una contrasenya\",\n  \"components.ResetPassword.validationpasswordminchars\": \"La contrasenya és massa curta; ha de tenir un mínim de 8 caràcters\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Les contrasenyes han de coincidir\",\n  \"components.ResetPassword.validationemailrequired\": \"Heu de proporcionar una adreça de correu electrònic vàlida\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Contrasenya restablerta amb èxit!\",\n  \"components.ResetPassword.resetpassword\": \"Restableix la contrasenya\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"S'enviarà un enllaç de restabliment de contrasenya a l'adreça electrònica proporcionada si està associada amb un usuari vàlid.\",\n  \"components.ResetPassword.passwordreset\": \"Reinicialització de la contrasenya\",\n  \"components.ResetPassword.password\": \"Contrasenya\",\n  \"components.ResetPassword.gobacklogin\": \"Torna a la pàgina d'inici de sessió\",\n  \"components.ResetPassword.emailresetlink\": \"Envieu l'enllaç de recuperació per correu electrònic\",\n  \"components.ResetPassword.email\": \"Adreça electrònica\",\n  \"components.ResetPassword.confirmpassword\": \"Confirmeu la contrasenya\",\n  \"components.RequestModal.selectseason\": \"Selecciona les temporades\",\n  \"components.RequestModal.seasonnumber\": \"Temporada {number}\",\n  \"components.RequestModal.season\": \"Temporada\",\n  \"components.RequestModal.requestseasons\": \"Sol·licita {seasonCount} {seasonCount, plural, one {Temporada} other {Temporades}}\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"La configuració de les notificacions de Discord s'ha desat correctament!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"No s'ha pogut desar la configuració de notificacions del Webhook.\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"No s'ha pogut desar la configuració de les notificacions de Discord.\",\n  \"components.Settings.Notifications.chatId\": \"Identificador del xat\",\n  \"components.Settings.Notifications.botUsername\": \"Nom d'usuari del Bot\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL de l’avatar del Bot\",\n  \"components.Settings.Notifications.botAPI\": \"Testimoni d'autorització del Bot\",\n  \"components.Settings.Notifications.authUser\": \"Nom d'usuari SMTP\",\n  \"components.Settings.Notifications.authPass\": \"Contrasenya SMTP\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Permet certificats autosignats\",\n  \"components.Settings.Notifications.agentenabled\": \"Activa l'agent\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"La configuració de notificacions del Webhook s'ha desat correctament!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL del Webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Heu de proporcionar un URL vàlid\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Heu de proporcionar un payload JSON vàlid\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Ajuda de la variable de plantilla\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"El Payload de JSON s'ha restablert correctament!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Restableix els valors per defecte\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Payload de JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Capçalera d'autorització\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Activa l'agent\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL del Webhook\",\n  \"i18n.processing\": \"En procés\",\n  \"i18n.close\": \"Tanca\",\n  \"i18n.advanced\": \"Avançat\",\n  \"i18n.previous\": \"Endarrere\",\n  \"pages.somethingwentwrong\": \"Alguna cosa ha anat malament\",\n  \"pages.serviceunavailable\": \"Servei no disponible\",\n  \"pages.returnHome\": \"Torna a l'inici\",\n  \"pages.pagenotfound\": \"No s'ha trobat la pàgina\",\n  \"pages.oops\": \"Vaja\",\n  \"pages.internalservererror\": \"S'ha produït un error intern al servidor\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"i18n.view\": \"Mostra\",\n  \"i18n.usersettings\": \"Configuració de l'usuari\",\n  \"i18n.unavailable\": \"No disponible\",\n  \"i18n.tvshows\": \"Sèries\",\n  \"i18n.tvshow\": \"Sèries\",\n  \"i18n.testing\": \"S'està provant…\",\n  \"i18n.test\": \"Prova\",\n  \"i18n.status\": \"Estat\",\n  \"i18n.showingresults\": \"Mostrant <strong>{from}</strong> a <strong>{to}</strong> de <strong>{total}</strong> resultats\",\n  \"i18n.settings\": \"Configuració\",\n  \"i18n.saving\": \"S'està desant…\",\n  \"i18n.save\": \"Desa els canvis\",\n  \"i18n.retry\": \"Torna-ho a provar\",\n  \"i18n.resultsperpage\": \"Mostra {pageSize} resultats per pàgina\",\n  \"i18n.requesting\": \"S'està sol·licitant …\",\n  \"i18n.requested\": \"Sol·licitat\",\n  \"i18n.request4k\": \"Sol·licita en 4K\",\n  \"i18n.request\": \"Sol·licita\",\n  \"i18n.pending\": \"Pendent\",\n  \"i18n.partiallyavailable\": \"Parcialment disponible\",\n  \"i18n.notrequested\": \"No sol·licitat\",\n  \"i18n.noresults\": \"Sense resultats.\",\n  \"i18n.next\": \"Endavant\",\n  \"i18n.movies\": \"Pel·lícules\",\n  \"i18n.movie\": \"Pel·lícula\",\n  \"i18n.loading\": \"S'està carregant…\",\n  \"i18n.failed\": \"Fallit\",\n  \"i18n.experimental\": \"Experimental\",\n  \"i18n.edit\": \"Edita\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.delete\": \"Suprimeix\",\n  \"i18n.deleting\": \"S'està suprimint…\",\n  \"i18n.declined\": \"Rebutjat\",\n  \"i18n.decline\": \"Rebutja\",\n  \"i18n.canceling\": \"S'està cancel·lant …\",\n  \"i18n.cancel\": \"Canceŀla\",\n  \"i18n.back\": \"Torna\",\n  \"i18n.available\": \"Disponible\",\n  \"i18n.areyousure\": \"N'esteu segur?\",\n  \"i18n.approved\": \"Aprovat\",\n  \"i18n.approve\": \"Aprova\",\n  \"i18n.all\": \"Totes\",\n  \"components.UserProfile.unlimited\": \"Il·limitat\",\n  \"components.UserProfile.totalrequests\": \"Sol·licituds totals\",\n  \"components.UserProfile.seriesrequest\": \"Sol·licituds de sèries\",\n  \"components.UserProfile.requestsperdays\": \"{limit} restants\",\n  \"components.UserProfile.recentrequests\": \"Sol·licituds recents\",\n  \"components.UserProfile.pastdays\": \"{type} (últims {days} dies)\",\n  \"components.UserProfile.movierequests\": \"Sol·licituds de pel·lícules\",\n  \"components.UserProfile.limit\": \"{remaining} de {limit}\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"No teniu permís per modificar la configuració d'aquest usuari.\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Permisos\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notificacions\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"General\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Contrasenya\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"No podeu modificar els vostres propis permisos.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Els permisos s'han desat correctament!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"S'ha produït un error en desar la configuració.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Permisos\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"La contrasenya és massa curta; ha de tenir un mínim de 8 caràcters\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Heu de proporcionar una nova contrasenya\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Heu de proporcionar la vostra contrasenya actual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Les contrasenyes han de coincidir\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Heu de confirmar la nova contrasenya\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"La contrasenya s'ha desat correctament!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"S'ha produït un error en desar la contrasenya. La vostra contrasenya actual s'ha introduït correctament?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"S'ha produït un error en desar la contrasenya.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Contrasenya\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"No teniu permís per modificar la contrasenya d'aquest usuari.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nova contrasenya\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Contrasenya actual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Confirmeu la contrasenya\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Heu de proporcionar un identificador de xat vàlid\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Heu de proporcionar un identificador d'usuari vàlid\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"La configuració s'ha desat correctament!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rol\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Inicieu un xat</TelegramBotLink>, afegiu <GetIdBotLink>@get_id_bot</GetIdBotLink> i executeu l'ordre <code>/ my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Identificador del xat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Envia notificacions sense so\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Envia missatges silenciosament\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Configuració de les notificacions\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notificacions\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"El <FindDiscordIdLink>número d'ID de diversos dígits</FindDiscordIdLink> associat al vostre compte d'usuari\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID de Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Usuari\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"S'ha produït un error en desar la configuració.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Límit de sol·licituds de sèries\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtra el contingut per disponibilitat regional\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Regió de Descobriu\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Usuari de Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Propietari\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtra el contingut per l'idioma original\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Idioma per a la secció «Descobriu»\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Límit de sol·licituds de pel·lícules\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Usuari local\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Configuració general\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"General\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Sobreescriu el límit global\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Nom de visualització\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrador\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Tipus de compte\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID d'usuari: {userid}\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Edita la configuració\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Mostra el perfil\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Unit el {joindate}\",\n  \"components.UserList.validationpasswordminchars\": \"La contrasenya és massa curta; ha de tenir un mínim de 8 caràcters\",\n  \"components.UserList.validationEmail\": \"Heu de proporcionar una adreça de correu electrònic vàlida\",\n  \"components.UserList.userssaved\": \"Els permisos d'usuari s'han desat correctament!\",\n  \"components.UserList.users\": \"Usuaris\",\n  \"components.UserList.userlist\": \"Llista d'usuaris\",\n  \"components.UserList.userfail\": \"S'ha produït un error en desar els permisos de l'usuari.\",\n  \"components.UserList.userdeleteerror\": \"S'ha produït un error en suprimir l'usuari.\",\n  \"components.TvDetails.overviewunavailable\": \"Sinopsi no disponible.\",\n  \"components.TvDetails.overview\": \"Sinopsi\",\n  \"components.TvDetails.originaltitle\": \"Títol original\",\n  \"components.TvDetails.originallanguage\": \"Idioma original\",\n  \"components.TvDetails.nextAirDate\": \"Pròxima data d'emissió\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Emissor} other {Emissors}}\",\n  \"components.TvDetails.firstAirDate\": \"Primera data d'emissió\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minuts\",\n  \"components.TvDetails.episodeRuntime\": \"Duració de l'episodi\",\n  \"components.TvDetails.cast\": \"Repartiment\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Equip complet de la sèrie\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Repartiment complet de la sèrie\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Setup.welcome\": \"Benvingut a Seerr\",\n  \"components.Setup.signinMessage\": \"Comenceu iniciant sessió amb el vostre compte de Plex\",\n  \"components.Setup.setup\": \"Configuració\",\n  \"components.Setup.finishing\": \"S'està acabant…\",\n  \"components.Setup.finish\": \"Finalitza la configuració\",\n  \"components.Setup.continue\": \"Continua\",\n  \"components.Setup.configureservices\": \"Configureu els serveis\",\n  \"components.Settings.toastPlexRefresh\": \"S'està recuperant la llista de servidors de Plex…\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.validationPortRequired\": \"Heu de proporcionar un número de port vàlid\",\n  \"components.Settings.validationHostnameRequired\": \"Heu de proporcionar un nom d’amfitrió o una adreça IP vàlida\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"La llista de servidors Plex s'ha recuperat correctament!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"No s'ha pogut recuperar la llista de servidors Plex.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"La connexió amb Plex s'ha establert correctament!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"No s'ha pogut connectar amb Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"S'està intentant connectar amb Plex…\",\n  \"components.Settings.startscan\": \"Inicia l'exploració\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.sonarrsettings\": \"Configuració de Sonarr\",\n  \"components.Settings.settingUpPlexDescription\": \"Per configurar Plex, podeu introduir les dades manualment o seleccioneu un servidor recuperat de <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Premeu el botó situat a la dreta del menú desplegable per recuperar els servidors disponibles.\",\n  \"components.Settings.services\": \"Serveis\",\n  \"components.Settings.serverpresetRefreshing\": \"S'estan recuperant els servidors…\",\n  \"components.Settings.serverpresetManualMessage\": \"Configuració manual\",\n  \"components.Settings.serverpresetLoad\": \"Premeu el botó per carregar els servidors disponibles\",\n  \"components.Settings.serverpreset\": \"Servidor\",\n  \"components.Settings.serverRemote\": \"remot\",\n  \"components.Settings.serverLocal\": \"local\",\n  \"components.Settings.scanning\": \"S'està sincronitzant …\",\n  \"components.Settings.scan\": \"Sincronitza les biblioteques\",\n  \"components.Settings.radarrsettings\": \"Configuració de Radarr\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.plexsettingsDescription\": \"Configureu la paràmetres del vostre servidor Plex. Seerr explora les vostres biblioteques Plex per determinar la disponibilitat de continguts.\",\n  \"components.Settings.plexsettings\": \"Configuració de Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"Les biblioteques en les que Seerr explora títols. Configureu i deseu la configuració de la connexió Plex i feu clic al botó següent si no apareix cap.\",\n  \"components.Settings.plexlibraries\": \"Biblioteques Plex\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.manualscanDescription\": \"Normalment, només s’executarà una vegada cada 24 hores. Seerr 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!\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Exploració d'elements de Plex afegits recentment\",\n  \"components.Settings.notrunning\": \"No s'està executant\",\n  \"components.Settings.notificationsettings\": \"Configuració de les notificacions\",\n  \"components.Settings.notifications\": \"Notificacions\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Configureu i activeu els agents de notificació.\",\n  \"components.Settings.menuUsers\": \"Usuaris\",\n  \"components.Settings.menuServices\": \"Serveis\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Notificacions\",\n  \"components.Settings.menuLogs\": \"Registres\",\n  \"components.Settings.menuJobs\": \"Tasques programades i memòria cau\",\n  \"components.Settings.menuGeneralSettings\": \"General\",\n  \"components.Settings.menuAbout\": \"Quant a\",\n  \"components.Settings.manualscan\": \"Exploració manual de la biblioteca\",\n  \"components.Settings.librariesRemaining\": \"Biblioteques restants: {count}\",\n  \"components.Settings.hostname\": \"Nom de l’amfitrió o adreça IP\",\n  \"components.Settings.deleteserverconfirm\": \"Esteu segur que voleu suprimir aquest servidor?\",\n  \"components.Settings.currentlibrary\": \"Biblioteca actual: {name}\",\n  \"components.Settings.cancelscan\": \"Cancel·la l'exploració\",\n  \"components.Settings.addsonarr\": \"Afegeix un servidor Sonarr\",\n  \"components.Settings.activeProfile\": \"Perfil actiu\",\n  \"components.Settings.enablessl\": \"Utilitza SSL\",\n  \"components.Settings.email\": \"Adreça electrònica\",\n  \"components.Settings.default4k\": \"4K predeterminat\",\n  \"components.Settings.default\": \"Predeterminat\",\n  \"components.Settings.address\": \"Adreça\",\n  \"components.Settings.addradarr\": \"Afegeix un servidor Radarr\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Heu de seleccionar una carpeta arrel\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Heu de seleccionar un perfil de qualitat\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Heu de proporcionar un número de port vàlid\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Heu de proporcionar un nom de servidor\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Heu de seleccionar un perfil d'idioma\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Heu de proporcionar un nom d’amfitrió o una adreça IP vàlides\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"L'URL base no pot acabar amb una barra inclinada final\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"L'URL base ha de tenir una barra inclinada\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"L'URL no pot acabar amb una barra inclinada final\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Heu de proporcionar un URL vàlid\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Heu de proporcionar una clau API\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"La connexió amb Sonarr s'ha establert correctament!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"No s'ha pogut connectar amb Sonarr.\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Proveu la connexió per carregar les carpetes arrel\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Prova la connexió per carregar perfils de qualitat\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Prova la connexió per carregar els perfils d'idioma\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Activa l’escaneig\",\n  \"components.Settings.SonarrModal.ssl\": \"Utilitza SSL\",\n  \"components.Settings.SonarrModal.servername\": \"Nom del Servidor\",\n  \"components.Settings.SonarrModal.server4k\": \"Servidor 4K\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Seleccioneu la carpeta arrel\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Seleccioneu la carpeta arrel\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Seleccioneu un perfil de qualitat\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Seleccioneu el perfil d'idioma\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Carpeta per temporada\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Carpeta arrel\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Perfil de qualitat\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"S'estan carregant les carpetes arrel…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"S'estan carregant els perfils de qualitat…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"S'estan carregant els perfils d'idioma…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Perfil d'idioma\",\n  \"components.Settings.SonarrModal.hostname\": \"Nom de l’amfitrió o adreça IP\",\n  \"components.Settings.SonarrModal.externalUrl\": \"URL extern\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Editeu el servidor Sonarr\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Servidor predeterminat\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Afegeix un nou servidor Sonarr\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Perfil de qualitat de l'anime\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Configureu la configuració global i predeterminada de l'usuari.\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"S'ha produït un error en desar la configuració.\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Base d’URL\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Base d'URL\",\n  \"components.Settings.SonarrModal.apiKey\": \"Clau API\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Carpeta arrel de l'anime\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Perfil d'idioma per a Anime\",\n  \"components.Settings.SonarrModal.add\": \"Afegeix un servidor\",\n  \"components.Settings.SettingsUsers.users\": \"Usuaris\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Configuració de l'usuari\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Límit global de sol·licituds de Sèries\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"La configuració de l'usuari s'ha desat correctament!\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Obteniu d’ajuda\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Activa l'inici de sessió local\",\n  \"components.Settings.SettingsLogs.time\": \"Marca de temps\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Reprèn\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pausa\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Depuració\",\n  \"components.Settings.SettingsLogs.extraData\": \"Dades addicionals\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Copia al porta-retalls\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"S'ha copiat el missatge de registre al porta-retalls.\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Executa-ho ara\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Exploració completa de la biblioteca plex\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Exploració completa de la biblioteca Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Exploració d'elements de Jellyfin afegits recentment\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Pròxima execució\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"S'ha iniciat {jobname}.\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} s'ha cancel·lat.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Buida la memòria cau\",\n  \"components.Settings.SettingsJobsCache.command\": \"Ordre\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Mida del valor\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Nom de la memòria cau\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Mida de la clau\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Claus totals\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"La memòria cau de {cachename} s'ha buidat.\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Sol·licituds totals\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Total de contingut\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Debats de GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Visualitza a GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Visualitza el registre de canvis\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Registre de canvis {version}\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Límit global de sol·licituds de pel·lícules\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Permisos per defecte\",\n  \"components.Settings.SettingsLogs.showall\": \"Mostra tots els registres\",\n  \"components.Settings.SettingsLogs.message\": \"Missatge\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"També podeu veure aquests registres directament mitjançant <code>stdout</code> o a <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.logs\": \"Registres\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Detalls del registre\",\n  \"components.Settings.SettingsLogs.level\": \"Gravetat\",\n  \"components.Settings.SettingsLogs.label\": \"Etiqueta\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Avís\",\n  \"components.Settings.SettingsLogs.filterError\": \"Error\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Tasca programada desconeguda\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Escaneig de Sonarr\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Escaneig de Radarr\",\n  \"components.Settings.SettingsJobsCache.process\": \"Procés\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tipus\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Tasques programades i memòria cau\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr 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ó.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Tasques programades\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Nom de la tasca programada\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Restableix la sincronització de descàrregues\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Sincronitza les baixades\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Cancel·la la tasca programada\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Errades\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Consultes\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr 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.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Memòria cau\",\n  \"components.Settings.SettingsAbout.version\": \"Versió\",\n  \"components.Settings.SettingsAbout.timezone\": \"Zona horària\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentació\",\n  \"components.Settings.SettingsAbout.about\": \"Quant a\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Actualitzat\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Seleccioneu un perfil de qualitat\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Seleccioneu la disponibilitat mínima\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Disponibilitat mínima\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"S'estan carregant les carpetes arrel…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"S'estan carregant els perfils de qualitat…\",\n  \"components.Settings.RadarrModal.hostname\": \"Nom de l’amfitrió o adreça IP\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Servidor predeterminat\",\n  \"components.Settings.RadarrModal.createradarr\": \"Afegiu un servidor Radarr nou\",\n  \"components.Settings.RadarrModal.add\": \"Afegeix un servidor\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Heu de proporcionar un nom d’amfitrió o una adreça IP vàlids\",\n  \"components.Settings.Notifications.validationEmail\": \"Heu de proporcionar una adreça de correu electrònic vàlida\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Heu de proporcionar un identificador de xat vàlid\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Heu de proporcionar un testimoni d'autorització del bot\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"No s'ha pogut desar la configuració de les notificacions de Telegram.\",\n  \"components.Settings.Notifications.smtpHost\": \"Amfitrió SMTP\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"No s'ha pogut desar la configuració de les notificacions per correu electrònic.\",\n  \"components.Settings.RadarrModal.apiKey\": \"Clau API\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Versions\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"La informació de la versió no està disponible.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Última versió\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Heu de seleccionar una carpeta arrel\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Carpeta arrel\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Perfil de qualitat\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.externalUrl\": \"URL extern\",\n  \"components.Settings.RadarrModal.editradarr\": \"Editeu el servidor Radarr\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL del Webhook\",\n  \"components.Settings.Notifications.validationUrl\": \"Heu de proporcionar un URL vàlid\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Heu de proporcionar un número de port vàlid\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"La configuració de les notificacions de Telegram s'ha desat correctament!\",\n  \"components.Settings.Notifications.smtpPort\": \"Port SMTP\",\n  \"components.Settings.Notifications.senderName\": \"Nom de l'emissor\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Envia notificacions sense so\",\n  \"components.Settings.Notifications.sendSilently\": \"Envia-ho silenciosament\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Signa missatges de correu electrònic xifrats utilitzant <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Clau privada PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Signa missatges de correu electrònic utilitzant <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPassword\": \"Contrasenya de PGP\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"La configuració de les notificacions per correu electrònic s'ha desat correctament!\",\n  \"components.Settings.Notifications.emailsender\": \"Adreça de l'emissor\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Tots els idiomes\",\n  \"components.LanguageSelector.languageServerDefault\": \"Predeterminat ({language})\",\n  \"components.UserList.userdeleted\": \"L'usuari s'ha suprimit correctament!\",\n  \"components.UserList.usercreatedsuccess\": \"L'usuari s'ha creat correctament!\",\n  \"components.UserList.usercreatedfailed\": \"S'ha produït un error en crear l'usuari.\",\n  \"components.UserList.user\": \"Usuari\",\n  \"components.UserList.totalrequests\": \"Sol·licituds\",\n  \"components.UserList.sortRequests\": \"Recompte de sol·licituds\",\n  \"components.UserList.sortDisplayName\": \"Nom de visualització\",\n  \"components.UserList.sortCreated\": \"Data de registre\",\n  \"components.UserList.role\": \"Rol\",\n  \"components.UserList.plexuser\": \"Usuari de Plex\",\n  \"components.UserList.passwordinfodescription\": \"Configureu l'URL d'una aplicació i activeu les notificacions per correu electrònic per permetre la generació automàtica de contrasenyes.\",\n  \"components.UserList.password\": \"Contrasenya\",\n  \"components.UserList.owner\": \"Propietari\",\n  \"components.UserList.nouserstoimport\": \"No hi ha usuaris nous de Plex a importar.\",\n  \"components.UserList.localuser\": \"Usuari local\",\n  \"components.UserList.importfromplexerror\": \"S'ha produït un error en importar usuaris de Plex.\",\n  \"components.UserList.importfrommediaserver\": \"Importeu usuaris de {mediaServerName}\",\n  \"components.UserList.importfromplex\": \"Importeu usuaris de Plex\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> {userCount, plural, one {usuari} other {usuaris}} de Plex importat correctament!\",\n  \"components.TvDetails.watchtrailer\": \"Veure el tràiler\",\n  \"components.TvDetails.viewfullcrew\": \"Mostreu equip complet\",\n  \"components.TvDetails.similar\": \"Sèries similars\",\n  \"components.TvDetails.showtype\": \"Tipus de sèrie\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Temporada} other {# Temporades}}\",\n  \"components.TvDetails.recommendations\": \"Recomanacions\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Proveu la connexió per carregar etiquetes\",\n  \"components.Settings.SonarrModal.tags\": \"Etiquetes\",\n  \"components.Settings.SonarrModal.selecttags\": \"Seleccioneu les etiquetes\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Sense etiquetes.\",\n  \"components.Settings.SonarrModal.loadingTags\": \"S'estan carregant les etiquetes…\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Editeu el servidor Sonarr 4K\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Servidor 4K predeterminat\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Afegiu un nou servidor Sonarr 4K\",\n  \"components.Settings.SonarrModal.animeTags\": \"Etiquetes d'anime\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Proveu la connexió per carregar etiquetes\",\n  \"components.Settings.RadarrModal.tags\": \"Etiquetes\",\n  \"components.Settings.RadarrModal.selecttags\": \"Seleccioneu les etiquetes\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Sense etiquetes.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"S'estan carregant les etiquetes…\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Editeu el servidor Radarr 4K\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Servidor 4K predeterminat\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Afegiu un nou servidor Radarr 4K\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Etiquetes\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Seleccioneu les etiquetes\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Sense etiquetes.\",\n  \"components.Settings.mediaTypeMovie\": \"pel·lícula\",\n  \"i18n.retrying\": \"S'està tornant a provar…\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"El vostre compte no té cap contrasenya definida. Configureu una contrasenya a continuació per habilitar l'inici de sessió com a \\\"usuari local\\\" mitjançant la vostra adreça de correu electrònic.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Aquest compte d'usuari no té cap contrasenya definida. Configureu una contrasenya a continuació perquè aquest compte pugui iniciar la sessió com a \\\"usuari local\\\"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Heu de proporcionar una clau pública PGP vàlida\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"La configuració de les notificacions de Telegram s'ha desat correctament!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"No s'ha pogut desar la configuració de les notificacions de Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Xifra els missatges de correu electrònic mitjançant <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Clau pública PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"La configuració de les notificacions per correu electrònic s'ha desat correctament!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"No s'ha pogut desar la configuració de les notificacions per correu electrònic.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Correu electrònic\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"La configuració de les notificacions de Discord s'ha desat correctament!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"No s'ha pogut desar la configuració de les notificacions de Discord.\",\n  \"components.UserList.autogeneratepasswordTip\": \"Envieu a l'usuari una contrasenya generada per servidor\",\n  \"components.Settings.serviceSettingsDescription\": \"Configureu els vostres servidors {serverType} a continuació. Podeu connectar diversos servidors {serverType}, però només dos es poden marcar com a valors predeterminats (un no 4K i un 4K). Els administradors poden substituir el servidor utilitzat per processar noves sol·licituds abans de l’aprovació.\",\n  \"components.Settings.serverSecure\": \"segur\",\n  \"components.Settings.noDefaultServer\": \"Cal marcar com a mínim un servidor {serverType} com a predeterminat perquè es processin les sol·licituds de {mediaType}.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Si només teniu un servidor únic {serverType} per a contingut no 4K i 4K (o si només descarregueu contingut 4K), el vostre servidor {serverType} <strong> NO</strong> deuria marcar-se com a servidor 4K.\",\n  \"components.Settings.mediaTypeSeries\": \"sèrie\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Actualitzat\",\n  \"components.Settings.SettingsAbout.outofdate\": \"No està actualitzat\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Heu de proporcionar una clau privada PGP vàlida\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Heu de proporcionar una contrasenya PGP\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Permetre als usuaris iniciar un xat amb el bot i configurar les seves pròpies notificacions\",\n  \"components.RequestModal.pendingapproval\": \"La vostra sol·licitud està pendent d'aprovació.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"No s'ha trobat {mediaType}\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Suprimeix la sol·licitud\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Cancel·la la sol·licitud\",\n  \"components.RequestCard.mediaerror\": \"No s'ha trobat {mediaType}\",\n  \"components.RequestCard.deleterequest\": \"Suprimeix la sol·licitud\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Tipus de notificacions\",\n  \"components.Layout.VersionStatus.streamstable\": \"Jellyseer (Estable)\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr (Desenvolupament)\",\n  \"components.Layout.VersionStatus.outofdate\": \"No està actualitzat\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {canvi} other {canvis}} posterior(s)\",\n  \"components.UserList.usercreatedfailedexisting\": \"Un altre usuari ja utilitza l'adreça electrònica proporcionada.\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Activa la cerca automàtica\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Activa la cerca automàtica\",\n  \"components.RequestModal.edit\": \"Edita la sol·licitud\",\n  \"components.RequestList.RequestItem.editrequest\": \"Edita la sol·licitud\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Predeterminat ({language})\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"No s'ha pogut enviar la notificació de prova de Telegram.\",\n  \"components.DownloadBlock.estimatedtime\": \"{time} de temps estimat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Idioma de visualització\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Settings.noDefault4kServer\": \"Cal marcar un servidor 4K de {serverType} com a predeterminat per permetre als usuaris enviar sol·licituds de {mediaType} en 4K.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Permetre als usuaris de {mediaServerName} iniciar la sessió sense haver-los importat prèviament\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Activa nou inici de sessió de {mediaServerName}\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"S'ha enviat la notificació de prova de Telegram!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"S'està enviant la notificació de prova de Telegram…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"S'ha enviat una notificació de prova per correu electrònic!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"S'està enviant la notificació de prova per correu electrònic…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"No s'ha pogut enviar la notificació de prova per correu electrònic.\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"S'ha enviat una notificació de prova de Discord!\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"S'està enviant la notificació de prova de Discord…\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"No s'ha pogut enviar la notificació de prova de Discord.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"S'ha enviat una notificació de prova de Webhook!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"S'està enviant una notificació de prova de Webhook…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"No s'ha pogut enviar la notificació de prova de Webhook.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"La configuració de notificacions de Push Web s'ha desat correctament!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"No s'ha pogut desar la configuració de notificacions de Push Web.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"S'ha enviat una notificació de prova de Push Web!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"S'està enviant la notificació de prova de Push Web…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"No s'ha pogut enviar la notificació de prova de Push Web.\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Activa l'agent\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"S'ha enviat la notificació de la prova de Slack!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"S'està enviant la notificació de prova de Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"No s'ha pogut enviar la notificació de prova de Slack.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"S'ha enviat una notificació de prova de Pushover!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"S'està enviant la notificació de prova de Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"No s'ha pogut enviar la notificació de prova de Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"S'ha enviat la notificació de prova Pushbullet!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"S'està enviant la notificació de prova de Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"No s'ha pogut enviar la notificació de prova Pushbullet.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Concedeix permís per sol·licitar sèries no 4K.\",\n  \"components.PermissionEdit.requestTv\": \"Sol·licita sèries\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Concedeix permís per sol·licitar pel·lícules no 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Sol·liciteu pel·lícules\",\n  \"components.UserList.localLoginDisabled\": \"El paràmetre <strong>Activa l'inici de sessió local</strong> està desactivat actualment.\",\n  \"components.Settings.webAppUrlTip\": \"Opcionalment, dirigiu els usuaris a l'aplicació web del vostre servidor en lloc de l'aplicació web \\\"allotjada\\\"\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>URL de l'aplicació web</WebAppLink>\",\n  \"components.Settings.Notifications.encryptionTip\": \"En la majoria dels casos, TLS implícit utilitza el port 465 i STARTTLS utilitza el port 587\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Utilitzeu TLS implícit\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Utilitzeu STARTTLS si està disponible\",\n  \"components.Settings.Notifications.encryption\": \"Mètode de xifratge\",\n  \"components.Settings.Notifications.chatIdTip\": \"Inicieu un xat amb el bot, afegiu <GetIdBotLink>@get_id_bot</GetIdBotLink> i indiqueu l'ordre <code>/my_id</code>\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Creeu un bot</CreateBotLink> per utilitzar-lo amb Seerr\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Per tal de rebre notificacions push web, Seerr s'ha de servir mitjançant HTTPS.\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Creeu una integració <WebhookLink>Webhook entrant</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"El vostre <UsersGroupsLink>identificador d'usuari o grup</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registreu una aplicació</ApplicationRegistrationLink> per utilitzar-la amb Seerr\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Creeu un testimoni a partir de la <PushbulletSettingsLink>Configuració del compte</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Creeu una <DiscordWebhookLink>integració de webhook</DiscordWebhookLink> al vostre servidor\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Utilitzeu sempre STARTTLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"Cap\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Permetre als usuaris iniciar la sessió mitjançant la seva adreça de correu electrònic i contrasenya, en lloc de l'autenticació de Plex\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Permisos inicials assignats a usuaris nous\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Sol·licitat\",\n  \"components.RequestCard.failedretry\": \"S'ha produït un error en tornar a demanar la sol·licitud.\",\n  \"components.Settings.Notifications.validationTypes\": \"Heu de seleccionar com a mínim un tipus de notificació\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Heu de seleccionar com a mínim un tipus de notificació\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Heu de seleccionar com a mínim un tipus de notificació\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Heu de seleccionar com a mínim un tipus de notificació\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Heu de seleccionar com a mínim un tipus de notificació\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{temporades} per {quotaDays} {dies}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {temporada} other {temporades}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {pel·lícula} other {pel·lícules}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{pel·lícules} per {quotaDays} {dies}</quotaUnits>\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {dia} other {dies}}\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Rep notificacions quan altres usuaris envien sol·licituds de contingut noves que requereixen aprovació.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Rep notificacions quan no es puguin afegir sol·licituds de contingut a Radarr o Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Rep notificacions quan es rebutgin les teves sol·licituds de contingut.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Rep notificacions quan les teves sol·licituds de contingut estiguin disponibles.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Rep notificacions quan s'aprovin les teves sol·licituds de contingut.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Rep notificacions quan altres usuaris envien sol·licituds de contingut noves que s’aprovin automàticament.\",\n  \"components.MovieDetails.showmore\": \"Mostra més\",\n  \"components.MovieDetails.showless\": \"Mostra menys\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Idioma de visualització\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Esteu segur que voleu suprimir aquest comentari?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Suprimeix el comentari\",\n  \"components.IssueDetails.IssueComment.edit\": \"Edita el comentari\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Suprimeix la incidència\",\n  \"components.IssueDetails.IssueDescription.description\": \"Descripció\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Publicat per {username} el {relativeTime}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Publicat per {username} el {relativeTime} (Modificat)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Heu d'introduir un missatge\",\n  \"components.IssueDetails.allepisodes\": \"Tots els episodis\",\n  \"components.IssueDetails.comments\": \"Comentaris\",\n  \"components.IssueDetails.issuepagetitle\": \"Incidència\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Edita la descripció\",\n  \"components.IssueDetails.allseasons\": \"Totes les temporades\",\n  \"components.IssueDetails.closeissue\": \"Tanca la incidència\",\n  \"components.IssueDetails.closeissueandcomment\": \"Tanca amb comentaris\",\n  \"components.IssueDetails.deleteissue\": \"Suprimeix la incidència\",\n  \"components.IssueDetails.leavecomment\": \"Comentari\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Esteu segur que voleu suprimir aquesta incidència?\",\n  \"components.IssueDetails.episode\": \"Episodi {episodeNumber}\",\n  \"components.IssueDetails.lastupdated\": \"Última actualització\",\n  \"components.IssueDetails.openinarr\": \"Obre a {arr}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"S'ha produït un error en editar la descripció de la incidència.\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"S'ha produït un error en suprimir la incidència.\",\n  \"components.IssueDetails.unknownissuetype\": \"Desconegut\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} per {user}\",\n  \"components.IssueDetails.nocomments\": \"Sense comentaris.\",\n  \"components.IssueDetails.issuetype\": \"Tipus\",\n  \"components.IssueDetails.openin4karr\": \"Obre en {arr} 4K\",\n  \"components.IssueDetails.problemseason\": \"Temporada afectada\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Torna a obrir amb comentaris\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporades}}\",\n  \"components.IssueDetails.toastissuedeleted\": \"La incidència s'ha suprimit correctament!\",\n  \"components.IssueDetails.toaststatusupdated\": \"L'estat de l'incidència s'ha actualitzat correctament!\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Estat\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Heu de proporcionar una descripció\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Què passa?\",\n  \"components.IssueModal.issueAudio\": \"Àudio\",\n  \"components.IssueModal.issueOther\": \"Altre\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Això eliminarà de manera irreversible totes les dades de {mediaType}, incloses les sol·licituds. Si aquest element existeix a la vostra biblioteca {mediaServerName}, la informació dels continguts es recrearà durant la següent exploració.\",\n  \"components.ManageSlideOver.downloadstatus\": \"Descàrregues\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"La descripció de l'incidència s'ha editat correctament!\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tipus\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Episodi afectat\",\n  \"components.IssueDetails.problemepisode\": \"Episodi afectat\",\n  \"components.IssueDetails.openedby\": \"#{issueId} oberta {relativeTime} per {username}\",\n  \"components.IssueDetails.play4konplex\": \"Veure en 4K a {mediaServerName}\",\n  \"components.IssueDetails.reopenissue\": \"Torna a obrir la incidència\",\n  \"components.IssueDetails.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Desconegut\",\n  \"components.IssueList.IssueItem.viewissue\": \"Veure incidència\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Tots els episodis\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Totes les temporades\",\n  \"components.IssueDetails.playonplex\": \"Veure a {mediaServerName}\",\n  \"components.IssueList.IssueItem.opened\": \"Oberta\",\n  \"components.IssueList.issues\": \"Incidències\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Informar d'una incidència\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Envia la incidència\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"S'ha produït un error en enviar la incidència.\",\n  \"components.IssueList.showallissues\": \"Mostra tots les incidències\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Episodi afectat\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Si us plau, proporcioneu una explicació detallada del problema que heu trobat.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"L'informe de la incidència per a <strong>{title}</strong> s'ha enviat correctament!\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Temporada afectada\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episodi {episodeNumber}\",\n  \"components.IssueList.sortModified\": \"Última modificació\",\n  \"components.IssueList.sortAdded\": \"Més recent\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Envia notificacions quan les incidències rebin comentaris nous.\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Envieu notificacions quan s'informin d'incidències.\",\n  \"components.IssueModal.issueSubtitles\": \"Subtítol\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Envieu notificacions quan es resolguin les incidències.\",\n  \"components.Layout.Sidebar.issues\": \"Incidències\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Notifica'm quan altres usuaris facin comentaris sobre incidències.\",\n  \"components.ManageSlideOver.tvshow\": \"sèries\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modifica la tasca programada\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Freqüència nova\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Cada {jobScheduleHours, plural, one {hora} other {{jobScheduleHours} hores}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Cada {jobScheduleMinutes, plural, one {minut} other {{jobScheduleMinutes} minuts}}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registreu una aplicació</ApplicationRegistrationLink> per utilitzar-la amb {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"El vostre <UsersGroupsLink>identificador d'usuari o grup </UsersGroupsLink> de 30 caràcters\",\n  \"components.MovieDetails.streamingproviders\": \"Actualment s'està retransmetent\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"S'ha produït un error en desar la tasca programada.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Tasca programada editada correctament!\",\n  \"components.IssueModal.issueVideo\": \"Vídeo\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Comentari de la incidència\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Incidència informada\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Doneu permís per gestionar incidències en continguts.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Alguna cosa ha fallat en actualitzar l'estat de la incidència.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Testimoni d'accés\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Creeu un testimoni des del vostra <PushbulletSettingsLink>configuració del compte</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"La configuració de les notificacions Pushbullet no s'ha pogut desar.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"La configuració de notificació Pushbullet s'ha desat correctament!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Testimoni API de l'aplicació\",\n  \"components.IssueList.IssueItem.episodes\": \"{EpisodeCount, plural, one {Episodi} other {Episodis}}\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Veure incidència\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Esborra les dades\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Sense sol·licituds.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Sol·licituds\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Gestiona {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Marca com a disponible en 4K\",\n  \"components.ManageSlideOver.markavailable\": \"Marca com a disponible\",\n  \"components.ManageSlideOver.movie\": \"pel·lícula\",\n  \"components.ManageSlideOver.openarr\": \"Obre a {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Obre en 4K {arr}\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Incidència resolta\",\n  \"components.PermissionEdit.createissues\": \"Informa d'incidències\",\n  \"components.PermissionEdit.viewissues\": \"Veure altres incidències\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Doneu permís per veure incidències de continguts informats per altres usuaris.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Doneu permís per informar incidències en continguts.\",\n  \"components.PermissionEdit.manageissues\": \"Gestiona les incidències\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Esteu executant la branca <code>develop</code> d'Seerr, que només es recomana per a aquells que contribueixen al desenvolupament o ajuden amb proves de nous desenvolupaments.\",\n  \"components.TvDetails.streamingproviders\": \"Actualment s'està retransmetent\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Clau d'usuari o grup\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"La configuració de notificacions Pushover no s'ha pogut desar.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"La configuració de notificació Pushover s'ha desat correctament!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Heu de proporcionar un testimoni d'accés\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Heu de proporcionar un testimoni d'aplicació vàlid\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Heu de proporcionar una clau d'usuari o grup vàlida\",\n  \"i18n.open\": \"Oberta\",\n  \"i18n.resolved\": \"Resolta\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Notifica'm quan incidències reportades per mi rebin comentaris nous.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Notifica'm quan altres usuaris informen incidències.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Notifica'm quan es resolguin incidències reportades per mi.\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Incidències obertes\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extres\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Notifica'm quan es tornin a obrir incidències per altres usuaris.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Notifica'm quan altres usuaris resolguin incidències.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Incidències reobertes\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Notifica'm quan es tornin a obrir incidències.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Notifica'm quan es tornin a obrir incidències reportades per mi.\",\n  \"components.RequestModal.requestmovies4k\": \"{count} {count, plural, one {Pel·lícula} other {Pel·lícules}} en 4K solicitada/es\",\n  \"components.RequestModal.requestseasons4k\": \"{seasonCount} {seasonCount, plural, one {temporada} other {temporades}} solicitada/es\",\n  \"components.RequestModal.selectmovies\": \"Selecciona les pel·lícules\",\n  \"components.TvDetails.productioncountries\": \"{countryCount, plural, one {País} other {Països}} de producció\",\n  \"components.RequestModal.requestmovies\": \"{count} {count, plural, one {Pel·lícula} other {Pel·lícules}} solicitada/es\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {País} other {Països}} de producció\",\n  \"components.RequestModal.approve\": \"Aprova la sol·licitud\",\n  \"components.RequestModal.requestApproved\": \"S'ha aprovat la sol·licitud de <strong>{title}</strong>!\",\n  \"components.Settings.Notifications.enableMentions\": \"Activa les mencions\",\n  \"components.Settings.RadarrModal.announced\": \"Anunciat\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Als cinemes\",\n  \"components.IssueDetails.commentplaceholder\": \"Afegeix un comentari…\",\n  \"components.Settings.RadarrModal.released\": \"Alliberat\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Activa l'agent\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"La configuració de notificacions de Gotify no s'ha pogut desar.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"La configuració de notificacions de Gotify s'ha desat correctament!\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Heu de proporcionar un testimoni d'aplicació\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"El <FindDiscordIdLink>número d'ID de diversos dígits</FindDiscordIdLink> associat al vostre compte d'usuari de Discord\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avançat\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Contingut\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Contingut 4K\",\n  \"components.ManageSlideOver.alltime\": \"Tots els temps\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Marqueu totes les temporades com a disponibles en 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Marqueu totes les temporades com a disponibles\",\n  \"components.ManageSlideOver.opentautulli\": \"Obre a Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Darrers {days, number} dies\",\n  \"components.ManageSlideOver.playedby\": \"Reproduït per\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {reproducció} other {reproduccions}}\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL del servidor\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"S'ha enviat una notificació de prova de Gotify!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Testimoni d'aplicació\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Heu de seleccionar almenys un tipus de notificació\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Heu de proporcionar un URL vàlid\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"L'URL no ha d'acabar amb una barra inclinada final\",\n  \"components.Settings.tautulliApiKey\": \"Clau API\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"La base de l'URL ha de tenir una barra inclinada inicial\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"La base de l'URL no ha d'acabar amb una barra inclinada final\",\n  \"components.Settings.validationUrlTrailingSlash\": \"L'URL no ha d'acabar amb una barra inclinada final\",\n  \"i18n.import\": \"Importa\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Etiqueta de canal\",\n  \"components.Settings.externalUrl\": \"URL extern\",\n  \"components.Settings.tautulliSettings\": \"Configuració de Tautulli\",\n  \"components.Settings.tautulliSettingsDescription\": \"Opcionalment podeu configurar del vostre servidor Tautulli. Seerr recupera les dades de l'historial de visualitzacions dels vostres continguts Plex de Tautulli.\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Alguna cosa ha fallat en desar la configuració de Tautulli.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"La configuració de Tautulli s'ha desat correctament!\",\n  \"components.Settings.urlBase\": \"URL base\",\n  \"components.Settings.validationApiKey\": \"Heu de proporcionar una clau API\",\n  \"components.Settings.validationUrl\": \"Heu de proporcionar un URL vàlid\",\n  \"components.UserList.newplexsigninenabled\": \"La configuració <strong>Activa el nou inici de sessió Plex</strong> està activada actualment. Els usuaris de Plex amb accés a la biblioteca no cal que s'importin per iniciar la sessió.\",\n  \"components.UserProfile.recentlywatched\": \"Vist recentment\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"No s'ha pogut enviar la notificació de prova de Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"S'està enviant una notificació de prova de Gotify…\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Directori de dades\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Identificador d'usuari de Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Heu de proporcionar un identificador d'usuari de Discord vàlid\",\n  \"i18n.importing\": \"S'està important…\",\n  \"components.RequestBlock.languageprofile\": \"Perfil d'idioma\",\n  \"components.AirDateBadge.airedrelative\": \"Emès {relativeTime}\",\n  \"components.MovieDetails.digitalrelease\": \"Llançament digital\",\n  \"components.MovieDetails.physicalrelease\": \"Alliberament físic\",\n  \"components.PermissionEdit.viewrecent\": \"Veure afegits recentment\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Concediu permís per veure la llista de contingut afegits recentment.\",\n  \"components.Settings.deleteServer\": \"Suprimeix el servidor {serverType}\",\n  \"components.StatusChecker.reloadApp\": \"Torna a carregar {applicationTitle}\",\n  \"components.TitleCard.cleardata\": \"Esborra les dades\",\n  \"i18n.restartRequired\": \"Cal reiniciar\",\n  \"components.RequestList.RequestItem.tvdbid\": \"Identificador de TheTVDB\",\n  \"components.TitleCard.tvdbid\": \"Identificador de TheTVDB\",\n  \"components.RequestList.RequestItem.tmdbid\": \"Identificador TMDB\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"La vostra llista de seguiment de Plex\",\n  \"components.Discover.plexwatchlist\": \"La vostra llista de seguiment de Plex\",\n  \"components.PermissionEdit.autorequest\": \"Sol·licitud automàtica\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Sol·licitud enviada automàticament\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Rep notificacions quan s'enviïn automàticament sol·licituds de contingut multimèdia nous per als elements de la teva llista de seguiment de Plex.\",\n  \"components.RequestCard.tmdbid\": \"Identificador TMDB\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Sol·liciteu automàticament pel·lícules de la vostra <PlexWatchlistSupportLink>Llista de seguiment de Plex</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Sol·licitud automàtica de pel·lícules\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Sol·licitud automàtica de sèries\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Sol·liciteu sèries automàticament de la vostra <PlexWatchlistSupportLink>Llista de seguiment de Plex</PlexWatchlistSupportLink>\",\n  \"components.PermissionEdit.autorequestSeries\": \"Sol·licitud automàtica de sèrie\",\n  \"components.PermissionEdit.autorequestMovies\": \"Sol·licitud automàtica de pel·lícules\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Concediu permís per enviar automàticament sol·licituds de pel·lícules que no siguin 4K mitjançant Plex Watchlist.\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Concediu permís per enviar automàticament sol·licituds de sèries que no siguin 4K mitjançant Plex Watchlist.\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Veure detalls\",\n  \"components.TitleCard.tmdbid\": \"Identificador TMDB\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Llista de seguiment de Plex\",\n  \"components.MovieDetails.managemovie\": \"Gestiona la pel·lícula\",\n  \"components.MovieDetails.theatricalrelease\": \"Estrena en cines\",\n  \"components.PermissionEdit.autorequestDescription\": \"Concediu permís per enviar automàticament sol·licituds de contingut que no siguin 4K mitjançant llistes de seguiment de Plex.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Veure les llistes de seguiment de Plex\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Concediu permís per veure les llistes de seguiment de Plex d'altres usuaris.\",\n  \"components.RequestCard.tvdbid\": \"Identificador de TheTVDB\",\n  \"components.Settings.advancedTooltip\": \"La configuració incorrecta d'aquesta configuració pot provocar un malfuncionament\",\n  \"components.Settings.experimentalTooltip\": \"L'activació d'aquesta configuració pot provocar un comportament inesperat de l'aplicació\",\n  \"components.TvDetails.reportissue\": \"Informar d'un problema\",\n  \"components.TitleCard.mediaerror\": \"No s'ha trobat {mediaType}\",\n  \"components.UserProfile.plexwatchlist\": \"Llista de seguiment de Plex\",\n  \"components.Layout.UserDropdown.requests\": \"Sol·licituds\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Sol·licituds de pel·lícules\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Sol·licituds de sèries\",\n  \"components.MovieDetails.reportissue\": \"Informa d'un problema\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Fes clic al botó següent per a tornar a carregar l'aplicació.\",\n  \"components.StatusChecker.appUpdated\": \"Actualitzat {applicationTitle}\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Si us plau, reinicieu el servidor per aplicar la configuració actualitzada.\",\n  \"components.AirDateBadge.airsrelative\": \"Emissió {relativeTime}\",\n  \"components.MovieDetails.rtaudiencescore\": \"Puntuació d'audiència de Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomàmetre Rotten Tomatoes\",\n  \"components.MovieDetails.tmdbuserscore\": \"Puntuació d'usuaris de TMDB\",\n  \"components.RequestBlock.approve\": \"Aprova la sol·licitud\",\n  \"components.RequestBlock.decline\": \"Rebutja la sol·licitud\",\n  \"components.RequestBlock.requestdate\": \"Data de sol·licitud\",\n  \"components.RequestBlock.requestedby\": \"Sol·licitat per\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr s'ha de reiniciar perquè els canvis a aquesta configuració tinguin efecte\",\n  \"components.StatusBadge.managemedia\": \"Gestiona {mediaType}\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"S'ha produït un error en recuperar les dades de la temporada.\",\n  \"components.TvDetails.rtaudiencescore\": \"Puntuació d'audiència de Rotten Tomatoes\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomàmetre Rotten Tomatoes\",\n  \"components.TvDetails.seasonstitle\": \"Temporades\",\n  \"components.RequestCard.approverequest\": \"Aprova la sol·licitud\",\n  \"components.RequestCard.cancelrequest\": \"Cancel·la la sol·licitud\",\n  \"components.RequestCard.editrequest\": \"Edita la sol·licitud\",\n  \"components.TvDetails.manageseries\": \"Gestiona les Sèries\",\n  \"components.RequestBlock.delete\": \"Suprimeix la sol·licitud\",\n  \"components.RequestBlock.edit\": \"Edita la sol·licitud\",\n  \"components.RequestBlock.lastmodifiedby\": \"Última modificació per\",\n  \"components.StatusBadge.playonplex\": \"Reprodueix a {mediaServerName}\",\n  \"components.RequestCard.declinerequest\": \"Rebutja la sol·licitud\",\n  \"components.StatusBadge.openinarr\": \"Obre a {arr}\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Sincronització de la llista de seguiment de Plex\",\n  \"components.TvDetails.seasonnumber\": \"Temporada {seasonNumber}\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Episodi} other {# Episodis}}\",\n  \"components.TvDetails.tmdbuserscore\": \"Puntuació d'usuaris de TMDB\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.StatusChecker.restartRequired\": \"Cal reiniciar el servidor\",\n  \"components.Discover.emptywatchlist\": \"Els continguts afegits a la vostra <PlexWatchlistSupportLink>Llista de seguiment de Plex</PlexWatchlistSupportLink> apareixeran aquí.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Sol·licitud de col·lecció en 4K\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"No hem pogut trobar cap coincidència per a aquesta sèrie.\",\n  \"components.UserProfile.emptywatchlist\": \"Els continguts afegits a la vostra <PlexWatchlistSupportLink>Llista de seguiment de Plex</PlexWatchlistSupportLink> apareixeran aquí.\",\n  \"components.RequestModal.requestseries4ktitle\": \"Sol·licitud de sèries en 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Sol·licitud de col·lecció\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Sol·licitud de pel·lícula en 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Sol·licitud de pel·lícula\",\n  \"components.RequestModal.requestseriestitle\": \"Sol·licitud de sèries\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Freqüència actual\",\n  \"components.TvDetails.Season.noepisodes\": \"Llista d'episodis no disponible.\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Neteja de la memòria cau d'imatges\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Memòria cau d'imatges\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Imatges a la memòria cau\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Mida total de la memòria cau\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Quan està activat a la configuració, Seerr enviarà les imatges a la memòria cau de fonts externes preconfigurades. Les imatges emmagatzemades a la memòria cau es desen a la vostra carpeta de configuració. Podeu trobar els fitxers a <code>{appDataPath}/cache/images</code>.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"Pel·lícules {keywordTitle}\",\n  \"components.Discover.tmdbtvgenre\": \"Gènere de la sèrie TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Paraula clau de la sèrie TMDB\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Proporciona un ID de paraula clau de TMDB\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Proporciona una consulta de cerca\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Cercar per estudi…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Nom del control lliscant\",\n  \"components.Discover.CreateSlider.starttyping\": \"Començar a escriure per a cercar.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Commutar la visibilitat\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Suprimir\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"La teva llista Plex\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Afegit recentment\",\n  \"components.Discover.CreateSlider.addSlider\": \"Afegir un control lliscant\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Crear un control lliscant personalitzat\",\n  \"components.Discover.CreateSlider.addfail\": \"No s'ha pogut crear un control lliscant nou.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Editar el control lliscant\",\n  \"components.Discover.CreateSlider.editfail\": \"No s'ha pogut editar el control lliscant.\",\n  \"components.Discover.tmdbmoviegenre\": \"Gènere de pel·lícula TMDB\",\n  \"components.Discover.tmdbsearch\": \"Cerca TMDB\",\n  \"components.Discover.tmdbstudio\": \"Estudi TMDB\",\n  \"components.Discover.CreateSlider.editsuccess\": \"S'ha editat el control lliscant i s'ha desat la configuració de la pàgina de Descobriu.\",\n  \"components.Discover.CreateSlider.needresults\": \"Cal tenir almenys 1 resultat.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Sense resultats.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Proporciona un ID de categoria TMDB\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Proporciona l'ID d'emissor TMDB\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Proporciona l'ID d'estudi TMDB\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Cercar per gènere…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Cercar per paraules clau…\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"No s'ha pogut suprimir el control lliscant.\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"El contingut afegit a la teva <PlexWatchlistSupportLink>llista de visualització de Plex</PlexWatchlistSupportLink> apareixerà aquí.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"S'ha creat un control lliscant nou i s'ha desat la configuració de personalització de Descobriu.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Has de proporcionar un valor de dades.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Has de proporcionar un títol.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Control lliscant suprimit amb èxit.\",\n  \"components.Discover.createnewslider\": \"Crear un control lliscant nou\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Pel·lícules\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularitat ascendent\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# filtre actiu} other {# filtres actius}}\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularitat descendent\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Data de llançament ascendent\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Data de llançament descendent\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Títol (A-Z) ascendent\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Títol (Z-A) descendent\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Puntuació TMDB ascendent\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Puntuació TMDB descendent\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# filtre actiu} other {# filtres actius}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Sèries\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Data de primera d'emissió ascendent\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Data de primera d'emissió descendent\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularitat ascendent\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularitat descendent\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Puntuació TMDB ascendent\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Puntuació TMDB descendent\",\n  \"components.Discover.networks\": \"Emissors\",\n  \"components.Discover.resetwarning\": \"Restablir tots els controls lliscants al valor predeterminat. Això també suprimirà els controls lliscants personalitzats!\",\n  \"components.Discover.tmdbmoviekeyword\": \"Paraula clau de pel·lícula TMDB\",\n  \"components.Discover.tmdbnetwork\": \"Emissors TMDB\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Puntuació d'usuaris TMDB\",\n  \"components.Discover.tvgenres\": \"Gèneres de sèries\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"Sèries {keywordTitle}\",\n  \"components.Discover.moviegenres\": \"Gèneres de pel·lícules\",\n  \"components.Discover.resetsuccess\": \"Restablerta la configuració personalitzada de Descobriu.\",\n  \"components.Discover.studios\": \"Estudis\",\n  \"components.Discover.stopediting\": \"Parar l'edició\",\n  \"components.Discover.updatefailed\": \"S'ha produït un error en actualitzar la configuració de personalitzada de Descobriu.\",\n  \"components.Discover.updatesuccess\": \"S'ha actualitzat la configuració de personalitzada de Descobriu.\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Data de publicació\",\n  \"components.Discover.FilterSlideover.runtime\": \"Temps d'execució\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Títol desconegut\",\n  \"components.RequestCard.unknowntitle\": \"Títol desconegut\",\n  \"components.Selector.nooptions\": \"Sense resultats.\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Títol (A-Z) ascendent\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Títol (Z-A) descendent\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# filtre actiu} other {# filtres actius}}\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Netejar els filtres actius\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtres\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Data primera d'emissió\",\n  \"components.Discover.FilterSlideover.from\": \"Des de\",\n  \"components.Discover.FilterSlideover.genres\": \"Gèneres\",\n  \"components.Discover.FilterSlideover.keywords\": \"Paraules clau\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Idioma original\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Puntuació entre {minValue} i {maxValue}\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} durada en minuts\",\n  \"components.Discover.resetfailed\": \"S'ha produït un error en restablir la configuració de personalització de Descobriu.\",\n  \"components.Discover.customizediscover\": \"Personalitza Descobriu\",\n  \"components.Discover.resettodefault\": \"Restablir al valor predeterminat\",\n  \"components.Layout.Sidebar.browsemovies\": \"Pel·lícules\",\n  \"components.Layout.Sidebar.browsetv\": \"Sèries\",\n  \"components.Selector.searchGenres\": \"Seleccionar gèneres…\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Temporada {temporadaNumber} Episodi {episodeNumber}\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Serveis en streaming\",\n  \"components.Discover.FilterSlideover.studio\": \"Estudi\",\n  \"components.Discover.FilterSlideover.to\": \"A\",\n  \"components.Settings.SettingsMain.general\": \"General\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Configuració general\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Activar la memòria cau d'imatges\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Configuració global i predeterminada per a Seerr.\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Amagar el contingut disponible\",\n  \"components.Settings.SettingsMain.apikey\": \"Clau API\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL de l'aplicació\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Memòria cau d'imatges d'origen extern (requereix una quantitat important d'espai en disc)\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Cada {jobScheduleSeconds, plural, one {segon} other {{jobScheduleSeconds} segons}}\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Títol de l'aplicació\",\n  \"components.Selector.searchKeywords\": \"Cercar paraules clau…\",\n  \"components.Selector.starttyping\": \"Començar a escriure per a cercar.\",\n  \"components.Selector.searchStudios\": \"Cercar estudis…\",\n  \"components.Selector.showless\": \"Mostrar menys\",\n  \"components.Selector.showmore\": \"Mostrar més\",\n  \"components.Settings.SettingsMain.locale\": \"Idioma de visualització\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Idioma a Descobriu\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrar el contingut per idioma original\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"S'ha produït un error en generar una clau API nova.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"La clau API s'ha generat correctament!\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"S'ha produït un error en desar la configuració.\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Permet sol·licituds parcials de sèries\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"La configuració s'ha desat correctament!\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"L'URL no ha d'acabar amb una barra inclinada final\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Has de proporcionar un títol d'aplicació\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Has de proporcionar un URL vàlid\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Sincronització de disponibilitat de contingut\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Serveis de transmissió de pel·lícules TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Serveis de transmissió de TV TMDB\",\n  \"components.Layout.UserWarnings.emailRequired\": \"És requereix un n correu electrònic.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Es requereix una contrasenya.\",\n  \"components.Login.description\": \"Com que és la primera vegada que inicieu sessió a {applicationName}, es necessita afegir un correu electrònic vàlid.\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Recompte de vots d'usuaris de TMDB\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Nombre de vots entre {minValue} i {maxValue}\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"El correu electrònic no és vàlid.\",\n  \"components.Login.credentialerror\": \"El nom d'usuari o la contrasenya són incorrectes.\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.imdbuserscore\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.tagRequests\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"i18n.collection\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\",\n  \"component.BlocklistBlock.blocklistdate\": \"Data de bloqueig\",\n  \"component.BlocklistBlock.blocklistedby\": \"Blocat per\",\n  \"component.BlocklistModal.blocklisting\": \"Llista de bloqueig\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> no està blocat.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Gestiona la llista de bloqueig.\",\n  \"components.Blocklist.blocklistdate\": \"data\",\n  \"components.Blocklist.blocklistedby\": \"{date} per {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Configuració de les llistes de bloqueig\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Etiquetes de les llistes de bloqueig\",\n  \"components.Blocklist.filterManual\": \"Manual\",\n  \"components.Blocklist.mediaName\": \"Nom\",\n  \"components.Blocklist.mediaTmdbId\": \"ID de tmdb\",\n  \"components.Blocklist.mediaType\": \"Tipus\"\n}\n"
  },
  {
    "path": "src/i18n/locale/cs.json",
    "content": "{\n  \"components.Settings.notificationsettings\": \"Nastavení oznámení\",\n  \"components.Settings.enablessl\": \"Použít SSL\",\n  \"components.Settings.default4k\": \"Výchozí 4K\",\n  \"components.Settings.cancelscan\": \"Zrušit prohledávání\",\n  \"components.Settings.activeProfile\": \"Aktivní profil\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Povolit prohledání\",\n  \"components.Settings.SonarrModal.ssl\": \"Použít SSL\",\n  \"components.Settings.SonarrModal.servername\": \"Název serveru\",\n  \"components.Settings.SonarrModal.server4k\": \"Server 4K\",\n  \"components.Settings.SonarrModal.selecttags\": \"Vyberte štítky\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Složky sezón\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Kořenová složka\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Profil kvality\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Žádné štítky.\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Načítání štítků…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Jazykový profil\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Externí adresa URL\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Výchozí server\",\n  \"components.Settings.SonarrModal.apiKey\": \"Klíč API\",\n  \"components.Settings.SonarrModal.animeTags\": \"Štítky anime\",\n  \"components.Settings.SonarrModal.add\": \"Přidat server\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Uživatelská nastavení\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Výchozí oprávnění\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Neznámá úloha\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Prohledat Sonarr\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Spustit nyní\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Prohledat Radarr\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} spuštěno.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Název úlohy\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} zrušeno.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Vyprázdnit mezipaměť\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Zrušit úlohu\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Velikost hodnoty\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Název mezipaměti\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Celkem žádostí\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Celkem médií\",\n  \"components.Settings.SettingsAbout.timezone\": \"Časové pásmo\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Diskuze na GitHubu\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Zobrazit seznam změn\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Seznam změn {version}\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Aktuální\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Povolit prohledávání\",\n  \"components.Settings.RadarrModal.ssl\": \"Použít SSL\",\n  \"components.Settings.RadarrModal.servername\": \"Název serveru\",\n  \"components.Settings.RadarrModal.server4k\": \"Server 4K\",\n  \"components.Settings.RadarrModal.selecttags\": \"Vyberte štítky\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Kořenová složka\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Profil kvality\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Žádné štítky.\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimální dostupnost\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Načítání štítků…\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Externí adresa URL\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Výchozí server\",\n  \"components.Settings.RadarrModal.apiKey\": \"Klíč API\",\n  \"components.Settings.RadarrModal.add\": \"Přidat server\",\n  \"components.Settings.Notifications.webhookUrl\": \"Adresa URL webhooku\",\n  \"components.Settings.Notifications.smtpPort\": \"Port SMTP\",\n  \"components.Settings.Notifications.smtpHost\": \"Hostitel SMTP\",\n  \"components.Settings.Notifications.senderName\": \"Jméno odesílatele\",\n  \"components.Settings.Notifications.sendSilently\": \"Odesílat potichu\",\n  \"components.Settings.Notifications.pgpPassword\": \"Heslo PGP\",\n  \"components.Settings.Notifications.encryption\": \"Metoda šifrování\",\n  \"components.Settings.Notifications.emailsender\": \"Adresa odesílatele\",\n  \"components.Settings.Notifications.chatId\": \"ID chatu\",\n  \"components.Settings.Notifications.botUsername\": \"Uživatelské jméno bota\",\n  \"components.Settings.Notifications.authUser\": \"Uživatelské jméno SMTP\",\n  \"components.Settings.Notifications.authPass\": \"Heslo SMTP\",\n  \"components.Settings.Notifications.agentenabled\": \"Povolit agenta\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Adresa URL webhooku\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON Payload\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Autorizační hlavička\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Povolit agenta\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Povolit agenta\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Povolit agenta\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Povolit agenta\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Povolit agenta\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Přístupový token\",\n  \"components.Search.searchresults\": \"Výsledky vyhledávání\",\n  \"components.ResetPassword.passwordreset\": \"Obnovení hesla\",\n  \"components.ResetPassword.email\": \"E-mailová adresa\",\n  \"components.ResetPassword.confirmpassword\": \"Potvrďte heslo\",\n  \"components.RequestModal.selectseason\": \"Vyberte sezóny\",\n  \"components.RequestModal.seasonnumber\": \"{number}. sezóna\",\n  \"components.RequestModal.edit\": \"Upravit žádost\",\n  \"components.RequestModal.cancel\": \"Zrušit žádost\",\n  \"components.RequestModal.autoapproval\": \"Automatické schválení\",\n  \"components.RequestModal.alreadyrequested\": \"Již vyžádáno\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Vybrat štítky\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Kořenová složka\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Zažádat jako\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Profil kvality\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Žádné štítky.\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Jazykový profil\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Cílový server\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (výchozí)\",\n  \"components.RequestList.sortModified\": \"Naposledy změněno\",\n  \"components.RequestList.sortAdded\": \"Nejnovější\",\n  \"components.RequestList.RequestItem.editrequest\": \"Upravit žádost\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Odstranit žádost\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Zrušit žádost\",\n  \"components.RequestCard.deleterequest\": \"Odstranit žádost\",\n  \"components.RequestButton.viewrequest\": \"Zobrazit žádost\",\n  \"components.RequestButton.requestmore\": \"Vyžádat více\",\n  \"components.RequestButton.declinerequest\": \"Odmítnout žádost\",\n  \"components.RequestButton.approverequest\": \"Schválit žádost\",\n  \"components.RequestBlock.server\": \"Cílový server\",\n  \"components.RequestBlock.rootfolder\": \"Kořenová složka\",\n  \"components.RequestBlock.requestoverrides\": \"Přepsání žádosti\",\n  \"components.RequestBlock.profilechanged\": \"Profil kvality\",\n  \"components.RegionSelector.regionServerDefault\": \"Výchozí ({region})\",\n  \"components.RegionSelector.regionDefault\": \"Všechny regiony\",\n  \"components.PersonDetails.birthdate\": \"Narozen {birthdate}\",\n  \"components.PersonDetails.ascharacter\": \"jako {character}\",\n  \"components.PermissionEdit.viewrequests\": \"Zobrazit žádosti\",\n  \"components.PermissionEdit.users\": \"Spravovat uživatele\",\n  \"components.PermissionEdit.requestTv\": \"Žádost o seriály\",\n  \"components.PermissionEdit.requestMovies\": \"Žádost o filmy\",\n  \"components.PermissionEdit.request4k\": \"Žádost 4K\",\n  \"components.PermissionEdit.managerequests\": \"Spravovat žádosti\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Automaticky schvalovat seriály\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Automaticky schvalovat filmy\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Oznámení\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Uživatel\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Role\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Vlastník\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Obecné\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Správce\",\n  \"components.UserList.users\": \"Uživatelé\",\n  \"components.UserList.user\": \"Uživatel\",\n  \"components.UserList.totalrequests\": \"Žádosti\",\n  \"components.UserList.role\": \"Role\",\n  \"components.UserList.password\": \"Heslo\",\n  \"components.UserList.owner\": \"Vlastník\",\n  \"components.UserList.creating\": \"Vytváření…\",\n  \"components.UserList.created\": \"Vytvořeno\",\n  \"components.UserList.create\": \"Vytvořit\",\n  \"components.UserList.admin\": \"Správce\",\n  \"components.UserList.accounttype\": \"Typ\",\n  \"components.TvDetails.recommendations\": \"Doporučení\",\n  \"components.TvDetails.overview\": \"Přehled\",\n  \"components.TvDetails.cast\": \"Obsazení\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.Setup.setup\": \"Nastavení\",\n  \"components.Setup.finishing\": \"Dokončování…\",\n  \"components.Setup.continue\": \"Pokračovat\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.services\": \"Služby\",\n  \"components.Settings.serverpreset\": \"Server\",\n  \"components.Settings.serverSecure\": \"zabezpečené\",\n  \"components.Settings.serverRemote\": \"vzdálený\",\n  \"components.Settings.serverLocal\": \"místní\",\n  \"components.Settings.scanning\": \"Synchronizace…\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Oznámení\",\n  \"components.Settings.menuUsers\": \"Uživatelé\",\n  \"components.Settings.menuServices\": \"Služby\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Oznámení\",\n  \"components.Settings.menuLogs\": \"Záznamy\",\n  \"components.Settings.menuGeneralSettings\": \"Obecné\",\n  \"components.Settings.menuAbout\": \"O aplikaci\",\n  \"components.Settings.mediaTypeSeries\": \"seriál\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.email\": \"E-mail\",\n  \"components.Settings.default\": \"Výchozí\",\n  \"components.Settings.address\": \"Adresa\",\n  \"components.Settings.SonarrModal.tags\": \"Štítky\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SettingsUsers.users\": \"Uživatelé\",\n  \"components.Settings.SettingsLogs.time\": \"Časová značka\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Pokračovat\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pozastavit\",\n  \"components.Settings.SettingsLogs.message\": \"Zpráva\",\n  \"components.Settings.SettingsLogs.logs\": \"Záznamy\",\n  \"components.Settings.SettingsLogs.level\": \"Závažnost\",\n  \"components.Settings.SettingsLogs.label\": \"Popisek\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Varování\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Informace\",\n  \"components.Settings.SettingsLogs.filterError\": \"Chyba\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Ladění\",\n  \"components.Settings.SettingsJobsCache.process\": \"Zpracování\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Typ\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Úlohy\",\n  \"components.Settings.SettingsJobsCache.command\": \"Příkaz\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Úspěchy\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Mezipaměť\",\n  \"components.Settings.SettingsAbout.version\": \"Verze\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentace\",\n  \"components.Settings.SettingsAbout.about\": \"O aplikaci\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Vydání\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Nejnovější\",\n  \"components.Settings.RadarrModal.tags\": \"Štítky\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.Notifications.encryptionNone\": \"Žádné\",\n  \"components.Search.search\": \"Vyhledat\",\n  \"components.ResetPassword.password\": \"Heslo\",\n  \"components.RequestModal.season\": \"Sezóna\",\n  \"components.RequestModal.QuotaDisplay.season\": \"sezóna\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Štítky\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Pokročilé\",\n  \"components.RequestList.requests\": \"Žádosti\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Zažádáno\",\n  \"components.RequestList.RequestItem.requested\": \"Zažádáno\",\n  \"components.RequestList.RequestItem.modified\": \"Upraveno\",\n  \"components.QuotaSelector.unlimited\": \"Neomezené\",\n  \"components.PersonDetails.crewmember\": \"Další profese\",\n  \"components.PersonDetails.appearsin\": \"Vystoupení\",\n  \"components.PermissionEdit.request\": \"Žádost\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Automatické schválení 4K seriálů\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Dostávat oznámení, když jsou vaše žádosti o média schváleny.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Dostávat oznámení, když ostatní uživatelé zadají nové žádosti o média, které jsou automaticky schváleny.\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Odesílat oznámení, když uživatelé zadají žádost o média vyžadující schválení.\",\n  \"components.MovieDetails.streamingproviders\": \"Aktuálně streamované na\",\n  \"pages.serviceunavailable\": \"Služba není dostupná\",\n  \"pages.returnHome\": \"Vrátit se domů\",\n  \"pages.pagenotfound\": \"Stránka nebyla nalezena\",\n  \"pages.oops\": \"Jejda\",\n  \"pages.internalservererror\": \"Interní chyba serveru\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"i18n.view\": \"Zobrazit\",\n  \"i18n.usersettings\": \"Uživatelská nastavení\",\n  \"i18n.unavailable\": \"Nedostupné\",\n  \"i18n.tvshows\": \"Seriály\",\n  \"i18n.tvshow\": \"Seriál\",\n  \"i18n.testing\": \"Testování…\",\n  \"i18n.test\": \"Testovat\",\n  \"i18n.status\": \"Stav\",\n  \"i18n.showingresults\": \"Zobrazuji <strong>{from}</strong> do <strong>{to}</strong> z <strong>{total}</strong> výsledků\",\n  \"i18n.settings\": \"Nastavení\",\n  \"i18n.saving\": \"Ukládání…\",\n  \"i18n.save\": \"Uložit změny\",\n  \"i18n.retrying\": \"Opakování…\",\n  \"i18n.retry\": \"Opakovat\",\n  \"i18n.resultsperpage\": \"Zobrazit {pageSize} výsledků na stránku\",\n  \"i18n.requesting\": \"Vyžadování…\",\n  \"i18n.requested\": \"Zažádáno\",\n  \"i18n.request4k\": \"Zažádat ve 4K\",\n  \"i18n.request\": \"Zažádat\",\n  \"i18n.processing\": \"Zpracováváno\",\n  \"i18n.previous\": \"Předchozí\",\n  \"i18n.pending\": \"Čekající\",\n  \"i18n.partiallyavailable\": \"Částečně dostupné\",\n  \"i18n.notrequested\": \"Nebylo zažádáno\",\n  \"i18n.noresults\": \"Žádné výsledky.\",\n  \"i18n.next\": \"Další\",\n  \"i18n.movies\": \"Filmy\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.loading\": \"Načítání…\",\n  \"i18n.failed\": \"Selhalo\",\n  \"i18n.experimental\": \"Experimentální\",\n  \"i18n.edit\": \"Upravit\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.deleting\": \"Odstraňování…\",\n  \"i18n.delete\": \"Odstranit\",\n  \"i18n.declined\": \"Odmítnuto\",\n  \"i18n.decline\": \"Odmítnout\",\n  \"i18n.close\": \"Zavřít\",\n  \"i18n.canceling\": \"Rušení…\",\n  \"i18n.cancel\": \"Zrušit\",\n  \"i18n.back\": \"Zpět\",\n  \"i18n.available\": \"Dostupné\",\n  \"i18n.areyousure\": \"Opravdu to chcete?\",\n  \"i18n.approved\": \"Schváleno\",\n  \"i18n.approve\": \"Schválit\",\n  \"i18n.all\": \"Vše\",\n  \"i18n.advanced\": \"Pokročilé\",\n  \"components.UserProfile.unlimited\": \"Neomezené\",\n  \"components.UserProfile.totalrequests\": \"Celkem žádostí\",\n  \"components.UserProfile.seriesrequest\": \"Žádosti o seriály\",\n  \"components.UserProfile.requestsperdays\": \"Zbývá {limit}\",\n  \"components.UserProfile.recentrequests\": \"Nedávné žádosti\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Oprávnění\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Oznámení\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Obecné\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Heslo\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Vlastní oprávnění nelze upravovat.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Oprávnění byla úspěšně uložena!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Při ukládání nastavení se něco pokazilo.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Oprávnění\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Heslo je příliš krátké; mělo by mít minimálně 8 znaků\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Musíte zadat nové heslo\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Musíte zadat své aktuální heslo\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Hesla se musí shodovat\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Musíte potvrdit nové heslo\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Heslo úspěšně uloženo!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Při ukládání hesla se něco pokazilo. Bylo vaše aktuální heslo zadáno správně?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Při ukládání hesla se něco pokazilo.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Heslo\",\n  \"pages.somethingwentwrong\": \"Něco se pokazilo\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Automatické schvalování 4K filmů\",\n  \"components.PermissionEdit.autoapprove4k\": \"Automatické schválení 4K\",\n  \"components.PermissionEdit.autoapprove\": \"Automatické schválení\",\n  \"components.PermissionEdit.advancedrequest\": \"Pokročilé žádosti\",\n  \"components.PermissionEdit.admin\": \"Správce\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Typy oznámení\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Žádost čeká na schválení\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Odesílat oznámení, když se nepodaří přidat žádosti o média do Radarru nebo Sonarru.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Zpracování žádosti selhalo\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Odesílat oznámení, když jsou žádosti o média odmítnuty.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Žádost odmítnuta\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Odesílat oznámení, když se žádosti o média stanou dostupné.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Žádost je dostupná\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Odesílat oznámení, když jsou žádosti o média ručně schváleny.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Žádost schválena\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Odesílat oznámení, když uživatelé odešlou nové žádosti o média, které jsou automaticky schváleny.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Žádost automaticky schválena\",\n  \"components.MovieDetails.watchtrailer\": \"Sledovat upoutávku\",\n  \"components.MovieDetails.viewfullcrew\": \"Zobrazit kompletní štáb\",\n  \"components.MovieDetails.similar\": \"Podobné tituly\",\n  \"components.MovieDetails.showmore\": \"Zobrazit více\",\n  \"components.MovieDetails.showless\": \"Zobrazit méně\",\n  \"components.MovieDetails.runtime\": \"{minutes} {minutes, plural, one {minuta} few {minuty} other {minut}}\",\n  \"components.MovieDetails.revenue\": \"Výnos\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Datum vydání} other {Data vydání}}\",\n  \"components.MovieDetails.recommendations\": \"Doporučení\",\n  \"components.MovieDetails.play\": \"Přehrát v {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Přehrát v {mediaServerName} ve 4K\",\n  \"components.MovieDetails.overviewunavailable\": \"Přehled není k dispozici.\",\n  \"components.MovieDetails.overview\": \"Přehled\",\n  \"components.MovieDetails.originaltitle\": \"Původní název\",\n  \"components.MovieDetails.originallanguage\": \"Původní jazyk\",\n  \"components.MovieDetails.markavailable\": \"Označit jako dostupné\",\n  \"components.MovieDetails.mark4kavailable\": \"Označit jako dostupné ve 4K\",\n  \"components.MovieDetails.cast\": \"Obsazení\",\n  \"components.MovieDetails.budget\": \"Rozpočet\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Kompletní obsazení\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Kompletní štáb\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Zobrazit více\",\n  \"components.Login.validationpasswordrequired\": \"Musíte zadat heslo\",\n  \"components.Login.validationemailrequired\": \"Musíte zadat platnou e-mailovou adresu\",\n  \"components.Login.signinwithplex\": \"Použijte svůj účet Plex\",\n  \"components.Login.signinwithoverseerr\": \"Použijte svůj účet {applicationTitle}\",\n  \"components.Login.signinheader\": \"Pro pokračování se přihlaste\",\n  \"components.Login.signingin\": \"Přihlašování…\",\n  \"components.Login.signin\": \"Přihlásit se\",\n  \"components.Login.password\": \"Heslo\",\n  \"components.Login.loginerror\": \"Při pokusu o přihlášení se něco pokazilo.\",\n  \"components.Login.forgotpassword\": \"Zapomenuté heslo?\",\n  \"components.Login.email\": \"E-mailová adresa\",\n  \"components.Layout.VersionStatus.streamstable\": \"Stabilní verze Seerr\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Vývojová verze Seerr\",\n  \"components.Layout.VersionStatus.outofdate\": \"Zastaralý\",\n  \"components.Layout.UserDropdown.signout\": \"Odhlásit se\",\n  \"components.Layout.UserDropdown.settings\": \"Nastavení\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Layout.Sidebar.users\": \"Uživatelé\",\n  \"components.Layout.Sidebar.settings\": \"Nastavení\",\n  \"components.Layout.Sidebar.requests\": \"Žádosti\",\n  \"components.Layout.Sidebar.dashboard\": \"Objevit\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Hledat filmy a seriály\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Jazyk zobrazení\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Všechny jazyky\",\n  \"components.LanguageSelector.languageServerDefault\": \"Výchozí ({language})\",\n  \"components.DownloadBlock.estimatedtime\": \"Odhadováno {time}\",\n  \"components.Discover.upcomingtv\": \"Nadcházející seriály\",\n  \"components.Discover.upcomingmovies\": \"Nadcházející filmy\",\n  \"components.Discover.upcoming\": \"Nadcházející filmy\",\n  \"components.Discover.trending\": \"Populární\",\n  \"components.Discover.recentrequests\": \"Nedávné žádosti\",\n  \"components.Discover.recentlyAdded\": \"Nedávno přidané\",\n  \"components.Discover.populartv\": \"Oblíbené seriály\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Seriály: {language}\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Seriály: {genre}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Seriály: {network}\",\n  \"components.Discover.popularmovies\": \"Oblíbené filmy\",\n  \"components.Discover.discover\": \"Objevte\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Žánry seriálů\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Žánry seriálů\",\n  \"components.Discover.StudioSlider.studios\": \"Studia\",\n  \"components.Discover.NetworkSlider.networks\": \"Stanice\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Žánry filmů\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Žánry filmů\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} filmů\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Připojení svazku <code>{appDataPath}</code> nebylo správně nakonfigurováno. Při zastavení nebo opětovném spuštění kontejneru budou všechna data vymazána.\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Filmy: {studio}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Filmy: {language}\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Filmy: {genre}\",\n  \"components.CollectionDetails.requestcollection4k\": \"Zažádat o kolekci ve 4K\",\n  \"components.CollectionDetails.requestcollection\": \"Zažádat o kolekci\",\n  \"components.CollectionDetails.overview\": \"Přehled\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Neúspěchy\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Dostávat oznámení, když jsou vaše žádosti o média odmítnuty.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Dostávat oznámení, když se vaše žádosti o média stanou dostupné.\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {potvrzení} few {potvrzení} other {potvrzení}} za\",\n  \"components.Settings.serverpresetRefreshing\": \"Načítání serverů…\",\n  \"components.Settings.plexsettings\": \"Nastavení Plexu\",\n  \"components.Settings.scan\": \"Synchronizovat knihovny\",\n  \"components.Settings.plexlibraries\": \"Knihovny Plex\",\n  \"components.Settings.notrunning\": \"Není spuštěno\",\n  \"components.Settings.radarrsettings\": \"Nastavení Radarru\",\n  \"components.Settings.startscan\": \"Spustit prohledání\",\n  \"components.Settings.serverpresetManualMessage\": \"Ruční konfigurace\",\n  \"components.Settings.sonarrsettings\": \"Nastavení Sonarru\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.IssueDescription.description\": \"Popis\",\n  \"components.IssueDetails.comments\": \"Komentáře\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Nová frekvence\",\n  \"components.IssueModal.issueOther\": \"Jiný\",\n  \"components.RequestModal.requestadmin\": \"Tato žádost bude schválena automaticky.\",\n  \"components.IssueModal.issueAudio\": \"Zvuk\",\n  \"components.IssueModal.issueSubtitles\": \"Titulky\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.Layout.Sidebar.issues\": \"Problémy\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.RequestModal.numberofepisodes\": \"Počet epizod\",\n  \"components.IssueDetails.issuepagetitle\": \"Problém\",\n  \"components.IssueDetails.leavecomment\": \"Komentář\",\n  \"components.ManageSlideOver.tvshow\": \"seriál\",\n  \"i18n.open\": \"Otevřené\",\n  \"components.IssueDetails.issuetype\": \"Typ\",\n  \"components.IssueList.IssueItem.opened\": \"Otevřeno\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Neznámý\",\n  \"components.IssueList.issues\": \"Problémy\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Žádosti\",\n  \"i18n.resolved\": \"Vyřešeno\",\n  \"components.TvDetails.overviewunavailable\": \"Přehled není dostupný.\",\n  \"components.TvDetails.watchtrailer\": \"Sledovat upoutávku\",\n  \"components.UserList.deleteuser\": \"Odstranit uživatele\",\n  \"components.UserList.email\": \"E-mailová adresa\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Výchozí ({language})\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Odeslat potichu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nové heslo\",\n  \"components.UserProfile.movierequests\": \"Žádosti o filmy\",\n  \"components.UserList.localuser\": \"Místní uživatel\",\n  \"components.Settings.SettingsLogs.extraData\": \"Další údaje\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Obecná nastavení\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Zobrazit problém\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Žádné žádosti.\",\n  \"components.IssueList.IssueItem.issuetype\": \"Typ\",\n  \"components.IssueDetails.problemseason\": \"Ovlivněná sezóna\",\n  \"components.IssueDetails.reopenissue\": \"Znovu otevřít problém\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problém nahlášen\",\n  \"components.PermissionEdit.viewissues\": \"Zobrazit problémy\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Otevřené problémy\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Ovlivněná epizoda\",\n  \"components.IssueDetails.IssueComment.delete\": \"Odstranit komentář\",\n  \"components.IssueDetails.IssueComment.edit\": \"Upravit komentář\",\n  \"components.IssueDetails.allseasons\": \"Všechny sezóny\",\n  \"components.IssueDetails.closeissue\": \"Uzavřít problém\",\n  \"components.ManageSlideOver.downloadstatus\": \"Stahování\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problém vyřešen\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} uživatelem {user}\",\n  \"components.RequestList.showallrequests\": \"Zobrazit všechny žádosti\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Odstranit problém\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Upravit popis\",\n  \"components.IssueDetails.allepisodes\": \"Všechny epizody\",\n  \"components.IssueDetails.deleteissue\": \"Odstranit problém\",\n  \"components.IssueDetails.episode\": \"Epizoda {episodeNumber}\",\n  \"components.IssueDetails.lastupdated\": \"Poslední aktualizace\",\n  \"components.IssueDetails.unknownissuetype\": \"Neznámý\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.RequestButton.declinerequest4k\": \"Odmítnout žádost 4K\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Heslo bylo úspěšně obnoveno!\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Co je špatně?\",\n  \"components.RequestButton.approverequest4k\": \"Schválit žádost 4K\",\n  \"components.RequestButton.viewrequest4k\": \"Zobrazit žádost 4K\",\n  \"components.RequestModal.requestSuccess\": \"O <strong>{title}</strong> bylo úspěšně zažádáno!\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Podrobnosti o záznamu\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.TvDetails.episodeRuntime\": \"Délka epizody\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minut\",\n  \"components.TvDetails.originallanguage\": \"Původní jazyk\",\n  \"components.TvDetails.originaltitle\": \"Původní název\",\n  \"components.UserList.bulkedit\": \"Hromadné úpravy\",\n  \"components.IssueDetails.nocomments\": \"Žádné komentáře.\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Stav\",\n  \"components.IssueDetails.problemepisode\": \"Ovlivněná epizoda\",\n  \"components.IssueDetails.season\": \"Sezóna {seasonNumber}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Ovlivněná epizoda\",\n  \"components.IssueList.IssueItem.viewissue\": \"Zobrazit problém\",\n  \"components.IssueList.sortAdded\": \"Nejnovější\",\n  \"components.IssueList.sortModified\": \"Naposledy změněno\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Všechny epizody\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Všechny sezóny\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Epizoda {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Ovlivněná série\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Sezóna {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Odeslat problém\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Spravovat {mediaType}\",\n  \"components.PermissionEdit.createissues\": \"Nahlásit problémy\",\n  \"components.PermissionEdit.manageissues\": \"Spravovat problémy\",\n  \"components.ResetPassword.emailresetlink\": \"Odkaz na obnovení e-mailu\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Hesla se musí shodovat\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Musíte zadat platnou adresu URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Obnovit do výchozího nastavení\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Musíte zadat platnou adresu URL\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Upravit úlohu\",\n  \"components.Setup.configureservices\": \"Konfigurovat služby\",\n  \"components.Setup.finish\": \"Dokončit nastavení\",\n  \"components.UserList.plexuser\": \"Uživatel Plexu\",\n  \"components.UserList.sortRequests\": \"Počet žádostí\",\n  \"components.UserList.userlist\": \"Seznam uživatelů\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Připojil se {joindate}\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Zobrazit profil\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Upravit nastavení\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Typ účtu\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Jazyk zobrazení\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Místní uživatel\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Jazyk pro objevování\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Uživatel Plexu\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Region pro objevování\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID uživatele\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Nastavení oznámení\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID chatu\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Potvrďte heslo\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Aktuální heslo\",\n  \"components.IssueDetails.toastissuedeleted\": \"Problém úspěšně odstraněn!\",\n  \"components.IssueDetails.toaststatusupdated\": \"Stav problému úspěšně aktualizován!\",\n  \"components.ManageSlideOver.markavailable\": \"Označit jako dostupné\",\n  \"components.IssueDetails.commentplaceholder\": \"Přidat komentář…\",\n  \"components.IssueDetails.openedby\": \"Č. {issueId} otevřeno {relativeTime} uživatelem {username}\",\n  \"components.IssueDetails.openin4karr\": \"Otevřít ve 4K {arr}\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Znovu otevřít s komentářem\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Musíte poskytnout popis\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Vymazat data\",\n  \"components.ManageSlideOver.alltime\": \"Za celou dobu\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Pokročilý\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Tímto nenávratně odeberete všechna data pro tento {mediaType}, včetně všech žádostí. Pokud tato položka existuje ve vaší knihovně {mediaServerName}, informace o médiích budou znovu vytvořeny během příštího prohledání.\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Média\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Média 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Označit všechny sezóny jako dostupné\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Označit všechny sezóny jako dostupné ve 4K\",\n  \"components.ManageSlideOver.openarr\": \"Otevřít v {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Otevřít v {arr} 4K\",\n  \"components.ManageSlideOver.opentautulli\": \"Otevřít v Tautulli\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Dostávat oznámení, když ostatní uživatelé komentují problémy.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Dostávat oznámení, když jsou problémy znovu otevřeny jinými uživateli.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Při aktualizaci stavu problému se něco pokazilo.\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Zveřejněno {relativeTime} uživatelem {username}\",\n  \"components.IssueDetails.playonplex\": \"Přehrát na {mediaServerName}\",\n  \"components.IssueDetails.play4konplex\": \"Přehrát ve 4K na {mediaServerName}\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} uživatelem {user}\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Uveďte prosím podrobné vysvětlení problému, na který jste narazili.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Nahlásit problém\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Při odesílání problému se něco pokazilo.\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Musíte zadat zprávu\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Opravdu chcete odstranit tento komentář?\",\n  \"components.IssueDetails.openinarr\": \"Otevřít v {arr}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Zveřejněno {relativeTime} uživatelem {username} (upraveno)\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Popis problému úspěšně upraven!\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Opravdu chcete odstranit tento problém?\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Při úpravě popisu problému se něco pokazilo.\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Při odstraňování problému se něco pokazilo.\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Speciály\",\n  \"components.IssueList.showallissues\": \"Zobrazit všechny problémy\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Zpráva o problému pro <strong>{title}</strong> úspěšně odeslána!\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Označit jako dostupné ve 4K\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problém znovu otevřen\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Dostávat oznámení, když ostatní uživatelé nahlásí problémy.\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Udělit oprávnění k úpravě pokročilých možností žádostí o média.\",\n  \"components.PermissionEdit.request4kMovies\": \"Žádost o filmy 4K\",\n  \"components.PermissionEdit.usersDescription\": \"Udělit oprávnění ke správě uživatelů. Uživatelé s tímto oprávněním nemohou upravovat uživatele s oprávněním správce nebo jim toto oprávnění udělit.\",\n  \"components.RequestModal.selectmovies\": \"Vyberte filmy\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Odesílání testovacího oznámení Pushover…\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Nastavení oznámení Slack bylo úspěšně uloženo!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Testovací oznámení web push se nepodařilo odeslat.\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Použít STARTTLS, pokud je dostupné\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Soukromý klíč PGP\",\n  \"components.Settings.Notifications.validationEmail\": \"Musíte zadat platnou e-mailovou adresu\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Musíte zadat platný soukromý klíč PGP\",\n  \"components.Settings.Notifications.validationUrl\": \"Musíte zadat platnou adresu URL\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Musíte zadat heslo PGP\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Načítání kořenových složek…\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Test připojení pro načtení profilů kvality\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Musíte vybrat kořenovou složku\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Údaje o vydání jsou aktuálně nedostupné.\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Získání podpory\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Obnovit synchronizaci stahování\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Při ukládání úlohy se něco pokazilo.\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Test připojení pro načtení profilů kvality\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Konfigurace a povolení agentů pro oznámení.\",\n  \"components.Settings.settingUpPlexDescription\": \"Pro nastavení Plexu můžete buď zadat údaje ručně, nebo vybrat server získaný z adresy <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Stisknutím tlačítka vpravo od rozevírací nabídky načtete seznam dostupných serverů.\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Nepodařilo se načíst seznam serverů Plex.\",\n  \"components.TvDetails.play4k\": \"Přehrát v {mediaServerName} ve 4K\",\n  \"components.TvDetails.play\": \"Přehrát v {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtrovat obsah podle regionální dostupnosti\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Povolit agenta\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Nastavení oznámení Gotify se nepodařilo uložit.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Nastavení oznámení Gotify úspěšně uloženo!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Testovací oznámení Gotify se nepodařilo odeslat.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Odesílání testovacího oznámení Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Testovací oznámení Gotify odesláno!\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"Adresa URL nesmí končit lomítkem\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Musíte vybrat alespoň jeden typ oznámení\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Musíte zadat platnou adresu URL\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Testovací oznámení Pushbullet odesláno!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Musíte zadat přístupový token\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Odesílání testovacího oznámení Pushbullet…\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Musíte zadat platnou adresu URL\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"Adresa URL nesmí končit lomítkem\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Úloha úspěšně upravena!\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Základ adresy URL\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Upravit server Sonarr\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Povolit automatické vyhledávání\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Upravit server Sonarr 4K\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Test připojení pro načtení jazykových profilů\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Test připojení pro načtení kořenových složek\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Musíte zadat klíč API\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Musíte zadat platnou adresu URL\",\n  \"components.Settings.deleteserverconfirm\": \"Opravdu chcete odstranit tento server?\",\n  \"components.Settings.menuJobs\": \"Úlohy a mezipaměť\",\n  \"components.TvDetails.similar\": \"Podobné seriály\",\n  \"components.TvDetails.streamingproviders\": \"Aktuálně streamuje na\",\n  \"components.UserList.nouserstoimport\": \"Neexistují žádní uživatelé Plexu k importu.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Nastavení úspěšně uloženo!\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Další spuštění\",\n  \"components.TvDetails.nextAirDate\": \"Další datum vysílání\",\n  \"components.TvDetails.viewfullcrew\": \"Zobrazit celé obsazení\",\n  \"components.UserList.edituser\": \"Upravit oprávnění uživatele\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Odesílat oznámení, když jsou problémy nahlášeny.\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Odesílat oznámení, když jsou problémy znovu otevřeny.\",\n  \"components.RequestModal.pending4krequest\": \"Čekající žádost 4K\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Nastavení oznámení web push se nepodařilo uložit.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Odesílání testovacího oznámení webhooku…\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Odesílání testovacího e-mailového oznámení…\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Musíte zadat platné ID chatu\",\n  \"components.Settings.RadarrModal.hostname\": \"Název hostitele nebo IP adresa\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Načítání profilů kvality…\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Vyberte kořenovou složku\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Používáte <code>vývojovou</code> větev Seerr, která je doporučena pouze těm, kteří se podílejí na vývoji nebo pomáhají s testováním.\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.RequestList.RequestItem.failedretry\": \"Při opakovaném pokusu o zadání žádosti se něco pokazilo.\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Povolit automatické vyhledávání\",\n  \"components.RequestModal.requestCancel\": \"Žádost o <strong>{title}</strong> zrušena.\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Váš 30znakový <UsersGroupsLink>identifikátor uživatele nebo skupiny</UsersGroupsLink>\",\n  \"components.ManageSlideOver.pastdays\": \"Posledních {days, number} {days, plural, one {den} few {dny} other {dní}}\",\n  \"components.ManageSlideOver.playedby\": \"Přehráno uživatelem\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Dostávat oznámení, když jsou problémy vyřešeny jinými uživateli.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Komentář k problému\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Odesílat oznámení, když problémy obdrží nové komentáře.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Dostávat oznámení, když vámi nahlášené problémy obdrží nové komentáře.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Dostávat oznámení, když jsou vámi nahlášené problémy znovu otevřeny.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Dostávat oznámení, když jsou vámi nahlášené problémy vyřešeny.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Dostávat oznámení, když se nepodaří přidat žádosti o média do Radarru nebo Sonarru.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Dostávat oznámení, když ostatní uživatelé zadají nové žádosti o média, které vyžadují schválení.\",\n  \"components.PermissionEdit.adminDescription\": \"Plný přístup správce. Obchází všechny ostatní kontroly oprávnění.\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Udělit automatické schválení žádostí o filmy 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Udělit automatické schválení žádostí o seriály 4K.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Udělit automatické schválení pro žádosti jiné než řady 4K.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Udělit oprávnění k nahlašování problémů s médii.\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Udělit oprávnění ke správě problémů s médii.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Udělit oprávnění ke správě žádostí o média. Všechny žádosti podané uživatelem s tímto oprávněním budou automaticky schváleny.\",\n  \"components.PermissionEdit.request4kDescription\": \"Udělit oprávnění k zadávání žádostí o média 4K.\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Udělit oprávnění k zadávání žádostí o filmy 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"Žádost o seriály 4K\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Udělit oprávnění k zadávání žádostí o filmy jiné než 4K.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Udělit oprávnění k zadávání žádostí o seriály jiné než 4K.\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Udělit oprávnění k zobrazení problémů s médii nahlášených jinými uživateli.\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Udělit oprávnění k zobrazení žádostí o média zadaných jinými uživateli.\",\n  \"components.PersonDetails.alsoknownas\": \"Známý také jako: {names}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} na {quotaDays} {days}</quotaUnits>\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Zbývá málo žádostí o sezónu\",\n  \"components.ResetPassword.gobacklogin\": \"Zpět na stránku pro přihlášení\",\n  \"components.ResetPassword.resetpassword\": \"Obnovit heslo\",\n  \"components.ResetPassword.validationemailrequired\": \"Musíte zadat platnou e-mailovou adresu\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Heslo je příliš krátké; mělo by mít minimálně 8 znaků\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Musíte zadat heslo\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Adresa URL serveru\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Musíte zadat token aplikace\",\n  \"components.Settings.Notifications.botAPI\": \"Autorizační token bota\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Musíte zadat platný název hostitele nebo IP adresu\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Musíte vybrat alespoň jeden typ oznámení\",\n  \"components.Settings.Notifications.enableMentions\": \"Povolit zmínky\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Musíte zadat platné číslo portu\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Zkopírovat do schránky\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Test připojení pro načtení štítků\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Nepodařilo se připojit k Sonarru.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Připojení k Sonarru bylo úspěšně navázáno!\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Základní adresa URL musí začínat lomítkem\",\n  \"components.Settings.manualscanDescription\": \"Obvykle se provádí pouze jednou za 24 hodin. Seerr bude kontrolovat nedávno přidané položky vašeho serveru Plex agresivněji. Pokud Plex konfigurujete poprvé, doporučujeme provést jednorázovou úplnou ruční prohledání knihovny!\",\n  \"components.Settings.urlBase\": \"Základ adresy URL\",\n  \"components.Settings.tautulliSettingsDescription\": \"Volitelně nakonfigurujte nastavení svého serveru Tautulli. Seerr načte data historie sledování pro vaše média Plex z Tautulli.\",\n  \"components.Settings.toastPlexConnecting\": \"Pokus o připojení k Plexu…\",\n  \"components.Settings.validationApiKey\": \"Musíte zadat klíč API\",\n  \"components.Settings.validationHostnameRequired\": \"Musíte zadat platný název hostitele nebo IP adresu\",\n  \"components.Settings.validationPortRequired\": \"Musíte zadat platné číslo portu\",\n  \"components.Settings.validationUrl\": \"Musíte zadat platnou adresu URL\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Základ adresy URL musí začínat lomítkem\",\n  \"components.TvDetails.showtype\": \"Typ seriálu\",\n  \"components.UserList.importfrommediaserver\": \"Import uživatelů z {mediaServerName}\",\n  \"components.UserList.importfromplex\": \"Import uživatelů Plexu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Nastavení oznámení Discordu úspěšně uloženo!\",\n  \"components.RequestButton.requestmore4k\": \"Vyžádat více ve 4K\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Souhrn omezení vašich žádostí si můžete prohlédnout na své <ProfileLink>stránce profilu</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Abyste mohli zažádat o tento seriál, musíte mít alespoň <strong>{seasons}</strong> {seasons, plural, one {zbývající žádost o sezónu} few {zbývající žádosti o sezónu} other {zbývajících žádostí o sezónu}}.\",\n  \"components.RequestModal.requestfrom\": \"Žádost od {username} čeká na schválení.\",\n  \"components.RequestModal.requesterror\": \"Při odesílání žádosti se něco pokazilo.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Testovací e-mailové oznámení odesláno!\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Základ adresy URL\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Výchozí server 4K\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Upravit server Radarr 4K\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Aktuální\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Musíte vybrat profil kvality\",\n  \"components.Settings.currentlibrary\": \"Současná knihovna: {name}\",\n  \"components.IssueDetails.closeissueandcomment\": \"Uzavřít s komentářem\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Nastavení oznámení Telegramu se nepodařilo uložit.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Musíte zadat platný veřejný klíč PGP\",\n  \"components.RequestModal.pendingapproval\": \"Vaše žádost čeká na schválení.\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token API aplikace\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Nastavení oznámení webhooku se nepodařilo uložit.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Nastavení oznámení webhooku bylo úspěšně uloženo!\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Adresa URL avatara bota\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Nastavení oznámení Discord úspěšně uloženo!\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Vytvořit <DiscordWebhookLink>integraci webhooku</DiscordWebhookLink> na vašem serveru\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Nemáte oprávnění měnit heslo tohoto uživatele.\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Vždy použít STARTTLS\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Připojení k Radarru úspěšně navázáno!\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Velikost klíče\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Povolit uživatelům {mediaServerName} přihlašovat se bez předchozího importu\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Musíte zadat platné číslo portu\",\n  \"components.UserList.userfail\": \"Při ukládání uživatelských oprávnění se něco pokazilo.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Odesílat oznámení bez zvuku\",\n  \"components.RequestBlock.languageprofile\": \"Jazykový profil\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Souhrn omezení žádostí tohoto uživatele si můžete prohlédnout na jeho <ProfileLink>stránce profilu</ProfileLink>.\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token aplikace\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Štítek kanálu\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Nastavení oznámení Pushbullet se nepodařilo uložit.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Musíte vybrat alespoň jeden typ oznámení\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Nastavení oznámení Pushover úspěšně uloženo!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Odesílání testovacího oznámení Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Testovací oznámení Slack odesláno!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Nastavení oznámení web push bylo úspěšně uloženo!\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Nápověda k proměnné šablony\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Testovací oznámení Webhook odesláno!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Musíte zadat platné JSON payload\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Povolit certifikáty s vlastním podpisem\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Nastavení oznámení Discord se nepodařilo uložit.\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Použít implicitní TLS\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Odesílání testovacího oznámení Discord…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Testovací oznámení Discord odesláno!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Testovací e-mailové oznámení se nepodařilo odeslat.\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Musíte zadat autorizační token bota\",\n  \"components.Settings.Notifications.validationTypes\": \"Musíte vybrat alespoň jeden typ oznámení\",\n  \"components.Settings.RadarrModal.announced\": \"Oznámeno\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Přidat nový server Radarr 4K\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Vyberte profil kvality\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Test připojení pro načtení kořenových složek\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Základ adresy URL nesmí končit lomítkem\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Musíte zadat název serveru\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Adresář dat\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Zastaralé\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Celkem klíčů\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Synchronizace stahování\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Úlohy a mezipaměť\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Úplné prohledání knihovny Plexu\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Zkopírování zprávy protokolu do schránky.\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Počáteční oprávnění přidělená novým uživatelům\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Globální omezení žádostí o seriály\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Konfigurace globálních a výchozích uživatelských nastavení.\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Profil kvality anime\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Přidat nový server Sonarr 4K\",\n  \"components.Settings.SonarrModal.hostname\": \"Název hostitele nebo IP adresa\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Načítání jazykových profilů…\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"Adresa URL nesmí končit lomítkem\",\n  \"components.Settings.addradarr\": \"Přidat server Radarr\",\n  \"components.Settings.addsonarr\": \"Přidat server Sonarr\",\n  \"components.Settings.externalUrl\": \"Externí adresa URL\",\n  \"components.Settings.hostname\": \"Název hostitele nebo IP adresa\",\n  \"components.Settings.manualscan\": \"Ruční prohledání knihovny\",\n  \"components.Settings.plexlibrariesDescription\": \"Knihovny, ve kterých Seerr vyhledává tituly. Nastavte a uložte nastavení připojení ke svému serveru Plex a poté klikněte na níže uvedené tlačítko, pokud nejsou vypsány žádné knihovny.\",\n  \"components.Settings.serverpresetLoad\": \"Stisknutím tlačítka načtete dostupné servery\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Při ukládání nastavení Tautulli se něco pokazilo.\",\n  \"components.Settings.webAppUrl\": \"Adresa URL <WebAppLink>webové aplikace</WebAppLink>\",\n  \"components.Settings.validationUrlTrailingSlash\": \"Adresa URL nesmí končit lomítkem\",\n  \"components.Settings.webAppUrlTip\": \"Volitelně přesměrujte uživatele na webovou aplikaci na vašem serveru namísto „hostované“ webové aplikace\",\n  \"components.Setup.welcome\": \"Vítejte v Seerr\",\n  \"components.Setup.signinMessage\": \"Začněte přihlášením\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Kompletní štáb seriálu\",\n  \"components.UserList.autogeneratepassword\": \"Automatické generování hesla\",\n  \"components.UserList.autogeneratepasswordTip\": \"Zaslat e-mailem uživateli heslo vygenerované serverem\",\n  \"components.UserList.deleteconfirm\": \"Opravdu chcete odstranit tohoto uživatele? Všechny jeho údaje o žádostech budou trvale odebrány.\",\n  \"components.UserList.localLoginDisabled\": \"Nastavení <strong>Povolit místní přihlášení</strong> je aktuálně zakázáno.\",\n  \"components.UserList.userssaved\": \"Uživatelská oprávnění byla úspěšně uložena!\",\n  \"components.UserList.validationEmail\": \"E-mail je povinný\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID uživatele: {userid}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Omezení žádostí o film\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Omezení žádostí o seriál\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Při ukládání nastavení se něco pokazilo.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Nastavení e-mailových oznámení bylo úspěšně uloženo!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Musíte zadat platné ID chatu\",\n  \"components.UserProfile.limit\": \"{remaining} z {limit}\",\n  \"components.UserProfile.recentlywatched\": \"Nedávno zhlédnuté\",\n  \"i18n.import\": \"Import\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Udělit automatické schválení pro všechny žádosti o média jiná než 4K.\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Udělit automatické schválení pro všechny žádosti o média 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Udělit oprávnění k zadávání žádostí o seriály 4K.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Testovací oznámení Pushbullet se nepodařilo odeslat.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Nastavení oznámení Pushover se nepodařilo uložit.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Testovací oznámení Slack se nepodařilo odeslat.\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Vytvořit bota</CreateBotLink> pro použití se Seerr\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Podepisovat šifrované e-mailové zprávy pomocí <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Odesílat oznámení bez zvuku\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Nastavení oznámení Telegram úspěšně uloženo!\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Musíte zadat platné číslo portu\",\n  \"components.Settings.SettingsLogs.showall\": \"Zobrazit všechny protokoly\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Povolit nové přihlášení k {mediaServerName}\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Kořenová složka anime\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Načítání kořenových složek…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Token API aplikace\",\n  \"components.Settings.RadarrModal.editradarr\": \"Upravit server Radarr\",\n  \"components.Settings.RadarrModal.createradarr\": \"Přidat nový server Radarr\",\n  \"components.Settings.RadarrModal.inCinemas\": \"V kinech\",\n  \"components.Settings.RadarrModal.released\": \"Vydáno\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Vyberte minimální dostupnost\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Zobrazit na GitHubu\",\n  \"components.Settings.librariesRemaining\": \"Zbývající knihovny: {count}\",\n  \"components.Settings.noDefault4kServer\": \"Server {serverType} 4K musí být označen jako výchozí, aby uživatelé mohli odesílat žádosti o {mediaType} 4K.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Pokud máte pouze jeden server {serverType} pro obsah jiný než 4K i 4K (nebo pokud stahujete pouze obsah ve 4K), váš server {serverType} by <strong>NEMĚL</strong> být označen jako server 4K.\",\n  \"components.Settings.noDefaultServer\": \"Aby mohly být zpracovány žádosti o {mediaType}, musí být alespoň jeden server {serverType} označen jako výchozí.\",\n  \"components.Settings.plexsettingsDescription\": \"Konfigurace nastavení připojení k vašemu serveru Plex. Seerr prohledá vaše knihovny Plex, aby zjistil dostupnost obsahu.\",\n  \"components.Settings.toastPlexRefresh\": \"Získání seznamu serverů z Plexu…\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Seznam serverů Plex byl úspěšně načten!\",\n  \"components.UserList.passwordinfodescription\": \"Nakonfigurujte adresu URL aplikace a povolte e-mailová oznámení pro povolení automatického generování hesla.\",\n  \"components.UserList.sortCreated\": \"Datum připojení\",\n  \"components.UserList.sortDisplayName\": \"Zobrazované jméno\",\n  \"components.UserList.usercreatedfailed\": \"Při vytváření uživatele se něco pokazilo.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Zadaná e-mailová adresa je již používána jiným uživatelem.\",\n  \"components.UserList.userdeleteerror\": \"Při odstraňování uživatele se něco pokazilo.\",\n  \"components.RequestModal.requestApproved\": \"Žádost o <strong>{title}</strong> schválena!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Nastavení oznámení Pushbullet úspěšně uloženo!\",\n  \"components.RequestModal.approve\": \"Schválit žádost\",\n  \"components.RequestModal.errorediting\": \"Při úpravě žádosti se něco pokazilo.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Musíte vybrat alespoň jeden typ oznámení\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Vytvoření integrace <WebhookLink>Příchozí webhook</WebhookLink>\",\n  \"components.RequestModal.requestedited\": \"Žádost o <strong>{title}</strong> úspěšně upravena!\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Odesílat oznámení, když jsou problémy vyřešeny.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Musíte zadat platný klíč uživatele nebo skupiny\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Testovací oznámení web push odesláno!\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Udělit automatické schválení žádostí o filmy jiné než 4K.\",\n  \"components.PermissionEdit.requestDescription\": \"Udělit oprávnění k zadávání žádostí o média jiná než 4K.\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Tento seriál je anime.\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Klíč uživatele nebo skupiny\",\n  \"components.RequestCard.failedretry\": \"Při opakovaném pokusu o zadání žádosti se něco pokazilo.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} nenalezeno\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} nenalezeno\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Můžete požádat o <strong>{limit}</strong> {type} každých <strong>{days}</strong> dní.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Tento seriál jsme nedokázali automaticky spárovat. Níže vyberte správnou shodu.\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Základ adresy URL musí začínat lomítkem\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Prohledání nedávno přidaných do Plexu\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Tyto protokoly můžete také zobrazit přímo prostřednictvím <code>stdout</code> nebo v <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Nastavení e-mailových oznámení se nepodařilo uložit.\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Načítání profilů kvality…\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Vyberte kořenovou složku\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Na zadanou e-mailovou adresu bude zaslán odkaz pro obnovení hesla, pokud je spojena s platným uživatelem.\",\n  \"components.RequestModal.pendingrequest\": \"Čekající žádost\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Výchozí server 4K\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Váš 30znakový <UsersGroupsLink>identifikátor uživatele nebo skupiny</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Nastavení oznámení Pushover úspěšně uloženo!\",\n  \"components.RequestModal.requestcancelled\": \"Žádost o <strong>{title}</strong> zrušena.\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Při ukládání nastavení se něco pokazilo.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Testovací oznámení webhooku se nepodařilo odeslat.\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Umožnit uživatelům také zahájit chat s vaším botem a nakonfigurovat si vlastní oznámení\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Nastavení e-mailových oznámení bylo úspěšně uloženo!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Testovací oznámení Pushover odesláno!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Nastavení oznámení Slack se nepodařilo uložit.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Připojení k Plexu bylo úspěšně navázáno!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Vytvořte token ze svého <PushbulletSettingsLink>Nastavení účtu</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.encryptionTip\": \"Ve většině případů používá implicitní TLS port 465 a STARTTLS port 587\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Testovací oznámení Discord se nepodařilo odeslat.\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Globální omezení žádostí o filmy\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"Základ adresy URL nesmí končit lomítkem\",\n  \"components.TvDetails.firstAirDate\": \"Datum prvního vysílání\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Musíte zadat klíč API\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Nepodařilo se připojit k Plexu.\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registrace aplikace</ApplicationRegistrationLink> pro použití s aplikací Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Musíte zadat platný token aplikace\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Testovací oznámení Pushover se nepodařilo odeslat.\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Jazykový profil anime\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON payload úspěšně obnoven!\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Vyberte profil kvality\",\n  \"components.Settings.tautulliApiKey\": \"Klíč API\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Aby bylo možné přijímat oznámení web push, musí být Seerr obsluhován přes HTTPS.\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Musíte vybrat minimální dostupnost\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Základní adresa URL nesmí končit lomítkem\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Musíte vybrat kořenovou složku\",\n  \"components.UserList.createlocaluser\": \"Vytvořit místního uživatele\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Odesílání testovacího oznámení web push…\",\n  \"components.Settings.Notifications.chatIdTip\": \"Spusťte chat s botem, přidejte <GetIdBotLink>@get_id_bot</GetIdBotLink> a zadejte příkaz <code>/my_id</code>\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Nastavení e-mailových oznámení se nepodařilo uložit.\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Musíte vybrat alespoň jeden typ oznámení\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Přidat nový server Sonarr\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Podepisovat šifrované e-mailové zprávy pomocí <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Vyberte jazykový profil\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Nastavení oznámení Telegram se nepodařilo uložit.\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Nepodařilo se připojit k Radarru.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Povolit místní přihlášení\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Povolit uživatelům přihlašovat se pomocí jejich e-mailové adresy a hesla\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Nastavení oznámení Discordu se nepodařilo uložit.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Nastavení oznámení Pushbullet úspěšně uloženo!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Musíte zadat přístupový token\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr ukládá do mezipaměti požadavky na externí koncové body API, aby optimalizoval výkon a zamezil zbytečným voláním API.\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Musíte zadat platný název hostitele nebo IP adresu\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Testovací oznámení Telegram se nepodařilo odeslat.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Odesílání testovacího oznámení Telegram…\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr provádí určité úlohy údržby jako pravidelně naplánované úlohy, ale lze je také spustit ručně níže. Ruční spuštění úlohy nezmění její plán.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Uživatelská nastavení byla úspěšně uložena!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Musíte zadat platný token aplikace\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Testovací oznámení Telegram odesláno!\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Kompletní obsazení seriálu\",\n  \"components.UserList.importfromplexerror\": \"Při importu uživatelů Plexu se něco pokazilo.\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Musíte zadat platný název hostitele nebo IP adresu\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Musíte vybrat profil kvality\",\n  \"components.Settings.serviceSettingsDescription\": \"Níže nakonfigurujte své servery {serverType}. Můžete připojit více serverů {serverType}, ale pouze dva z nich mohou být označeny jako výchozí (jeden jako jiný než 4K a jeden jako 4K). Správci mohou před schválením přepsat server použitý ke zpracování nových žádostí.\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Test připojení pro načtení štítků\",\n  \"components.UserList.validationpasswordminchars\": \"Heslo je příliš krátké; mělo by mít minimálně 8 znaků\",\n  \"components.UserProfile.pastdays\": \"{type} (posledních {days} dnů)\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Mezipaměť {cachename} byla vyprázdněna.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Musíte zadat platné ID uživatele\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Musíte vybrat jazykový profil\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Musíte zadat název serveru\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Zobrazované jméno\",\n  \"components.Settings.tautulliSettings\": \"Nastavení Tautulli\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Nastavení Tautulli úspěšně uloženo!\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Nemáte oprávnění měnit nastavení tohoto uživatele.\",\n  \"components.UserList.newplexsigninenabled\": \"Nastavení <strong>Povolit nové přihlášení Plexu</strong> je aktuálně povoleno. Uživatelé Plexu s přístupem ke knihovně nemusí být importováni, aby se mohli přihlásit.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Musíte zadat platný klíč uživatele nebo skupiny\",\n  \"components.UserList.usercreatedsuccess\": \"Uživatel úspěšně vytvořen!\",\n  \"components.UserList.userdeleted\": \"Uživatel úspěšně odstraněn!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"<FindDiscordIdLink>vícemístné identifikační číslo</FindDiscordIdLink> spojené s vaším uživatelským účtem Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Uživatelské ID Discordu\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Přepsat globální omezení\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Musíte zadat platné ID uživatele Discordu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Veřejný klíč PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Šifrování e-mailových zpráv pomocí <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"<FindDiscordIdLink>Vícemístné identifikační číslo</FindDiscordIdLink> spojené s vaším uživatelským účtem\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Přístupový token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Klíč uživatele nebo skupiny\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Zahajte chat</TelegramBotLink>, přidejte <GetIdBotLink>@get_id_bot</GetIdBotLink> a zadejte příkaz <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Nastavení oznámení Pushbullet se nepodařilo uložit.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Nastavení oznámení Pushover se nepodařilo uložit.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registrace aplikace</ApplicationRegistrationLink> pro použití s {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Nastavení oznámení Telegramu úspěšně uloženo!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Tento uživatelský účet nemá aktuálně nastaveno heslo. Níže nastavte heslo, aby se tento účet mohl přihlašovat jako „místní uživatel“.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Váš účet nemá aktuálně nastaveno heslo. Níže nastavte heslo, abyste se mohli přihlásit jako „místní uživatel“ pomocí své e-mailové adresy.\",\n  \"i18n.importing\": \"Importování…\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Epizoda} few {Epizody} other {Epizod}}\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Sezóna} few {Sezóny} other {Sezón}}\",\n  \"components.TvDetails.productioncountries\": \"{countryCount, plural, one {Země} other {Země}} produkce\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Stanice} other {Stanice}}\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {sezóna} few {sezóny} other {sezón}}\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {přehrání} few {přehrání} other {přehrání}}\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {Země} other {Země}} produkce\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studia}}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {den} few {dny} other {dní}}\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# sezóna} few {# sezóny} other {# sezón}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Sezóna} few {Sezóny} other {Sezón}}\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Aby mohl tento uživatel zažádat o tento seriál, musí mít alespoň <strong>{seasons}</strong> {seasons, plural, one {zbývající žádost o sezónu} few {zbývající žádosti o sezónu} other {zbývajících žádostí o sezónu}}.\",\n  \"components.RequestModal.requestmovies4k\": \"Zažádat o {count} {count, plural, one {film} few {filmy} other {filmů}} ve 4K\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"{jobScheduleHours, plural, one {Každou hodinu} few {Každé {jobScheduleHours} hodiny} other {Každých {jobScheduleHours} hodin}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Sezóna} few {Sezóny} other {Sezón}}\",\n  \"components.RequestButton.approve4krequests\": \"Schválit {requestCount, plural, one {žádost 4K} few {{requestCount} žádosti 4K} other {{requestCount} žádostí 4K}}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Sezóna} few {Sezóny} other {Sezón}}\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Tento uživatel může požádat o <strong>{limit}</strong> {type} každých <strong>{days}</strong> dní.\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} few {filmy} other {filmů}}\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Žádné} other {<strong>#</strong>}} {type} {remaining, plural, one {zbývající žádost} few {zbývající žádosti} other {zbývajících žádostí}}\",\n  \"components.RequestModal.requestseasons\": \"Zažádat o {seasonCount} {seasonCount, plural, one {sezónu} few {sezóny} other {sezón}}\",\n  \"components.RequestModal.requestseasons4k\": \"Zažádat o {seasonCount} {seasonCount, plural, one {sezónu} few {sezóny} other {sezón}} ve 4K\",\n  \"components.UserList.importedfromplex\": \"Úspěšně {userCount, plural, one {importován} few {importováni} other {importováno}} <strong>{userCount}</strong> {userCount, plural, one {uživatel} few {uživatelé} other {uživatelů}} Plexu!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtrovat obsah podle původního jazyka\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Vytvořte token z <PushbulletSettingsLink>Nastavení účtu</PushbulletSettingsLink>\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} few {filmy} other {filmů}}\",\n  \"components.QuotaSelector.seasons\": \"{seasonCount, plural, one {sezóna} few {sezóny} other {sezón}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} za {quotaDays} {days}</quotaUnits>\",\n  \"components.RequestButton.approverequests\": \"Schválit {requestCount, plural, one {žádost} few {{requestCount} žádosti} other {{requestCount} žádostí}}\",\n  \"components.RequestButton.decline4krequests\": \"Odmítnout {requestCount, plural, one {žádost 4K} few {{requestCount} žádosti 4K} other {{requestCount} žádostí 4K}}\",\n  \"components.RequestButton.declinerequests\": \"Odmítnout {requestCount, plural, one {žádost} few {{requestCount} žádosti} other {{requestCount} žádostí}}\",\n  \"components.RequestModal.requestmovies\": \"Zažádat o {count} {count, plural, one {film} few {filmy} other {filmů}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"{jobScheduleMinutes, plural, one {Každou minutu} few {Každé {jobScheduleMinutes} minuty} other {Každých {jobScheduleMinutes} minut}}\",\n  \"components.MovieDetails.digitalrelease\": \"Digitální vydání\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Váš seznam ke zhlédnutí\",\n  \"components.MovieDetails.physicalrelease\": \"Fyzické vydání\",\n  \"components.MovieDetails.managemovie\": \"Spravovat film\",\n  \"components.AirDateBadge.airsrelative\": \"Vysílá se {relativeTime}\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Žádosti o filmy\",\n  \"components.MovieDetails.rtaudiencescore\": \"Skóre publika Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Žádosti o seriály\",\n  \"components.AirDateBadge.airedrelative\": \"Vysíláno {relativeTime}\",\n  \"components.Layout.UserDropdown.requests\": \"Žádosti\",\n  \"components.MovieDetails.reportissue\": \"Nahlásit problém\",\n  \"components.StatusChecker.restartRequired\": \"Je vyžadován restart serveru\",\n  \"components.PermissionEdit.viewrecent\": \"Zobrazit naposledy přidané\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} aktualizováno\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Pro opětovné načtení aplikace klikněte na níže uvedené tlačítko.\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Pro použití aktualizovaných nastavení restartujte server.\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tmdbid\": \"ID TMDB\",\n  \"components.TitleCard.tvdbid\": \"ID TheTVDB\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.PermissionEdit.autorequestMovies\": \"Automatické vyžádání filmů\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Udělit oprávnění k automatickému odesílání žádostí o filmy jiné než 4K prostřednictvím Seznamu ke zhlédnutí Plex.\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Udělte oprávnění k zobrazení seznamu nedávno přidaných médií.\",\n  \"components.Settings.restartrequiredTooltip\": \"Aby se projevily změny tohoto nastavení, musí být Seerr restartován\",\n  \"components.StatusChecker.reloadApp\": \"Znovu načíst {applicationTitle}\",\n  \"components.TitleCard.cleardata\": \"Vyčistit data\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} nenalezeno\",\n  \"components.PermissionEdit.autorequestDescription\": \"Udělit oprávnění k automatickému odesílání žádostí o média jiná než 4K prostřednictvím Seznamu ke zhlédnutí Plex.\",\n  \"components.PermissionEdit.autorequest\": \"Automatické vyžádání\",\n  \"components.PermissionEdit.autorequestSeries\": \"Automatické vyžádání seriálu\",\n  \"components.PermissionEdit.viewwatchlists\": \"Zobrazit Seznamy ke zhlédnutí {mediaServerName}\",\n  \"components.Settings.advancedTooltip\": \"Nesprávná konfigurace tohoto nastavení může vést k narušení funkčnosti\",\n  \"components.Settings.deleteServer\": \"Odstranit server {serverType}\",\n  \"components.Settings.experimentalTooltip\": \"Povolení tohoto nastavení může vést k neočekávanému chování aplikace\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Zobrazit podrobnosti\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Udělit oprávnění k automatickému odesílání žádostí o seriály jiné než 4K prostřednictvím Seznamu ke zhlédnutí Plex.\",\n  \"components.RequestBlock.approve\": \"Schválit žádost\",\n  \"components.RequestBlock.decline\": \"Odmítnout žádost\",\n  \"components.RequestBlock.lastmodifiedby\": \"Naposledy změněno uživatelem\",\n  \"components.RequestBlock.requestdate\": \"Datum žádosti\",\n  \"components.RequestBlock.requestedby\": \"Vyžádáno uživatelem\",\n  \"components.RequestCard.approverequest\": \"Schválit žádost\",\n  \"components.RequestCard.cancelrequest\": \"Zrušit žádost\",\n  \"components.RequestCard.declinerequest\": \"Odmítnout žádost\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Synchronizace seznamu ke zhlédnutí Plex\",\n  \"components.StatusBadge.managemedia\": \"Spravovat {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Otevřít v {arr}\",\n  \"components.StatusBadge.playonplex\": \"Přehrát přes {mediaServerName}\",\n  \"components.TvDetails.manageseries\": \"Spravovat seriál\",\n  \"components.RequestBlock.delete\": \"Odstranit žádost\",\n  \"components.RequestBlock.edit\": \"Upravit žádost\",\n  \"components.RequestCard.editrequest\": \"Upravit žádost\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Pro tento seriál jsme nenašli shodu.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Žádost o kolekci 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Žádost o kolekci\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Žádost o film ve 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Žádost o film\",\n  \"components.RequestModal.requestseries4ktitle\": \"Žádost o seriál ve 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Žádost o seriál\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# epizoda} few {# epizody} other {# epizod}}\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Žádost byla automaticky odeslána\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Dostávat oznámení, když jsou nové žádosti o média automaticky odeslány pro položky na vašem Seznamu ke zhlédnutí.\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Udělit oprávnění k zobrazení Seznamu ke zhlédnutí {mediaServerName} ostatních uživatelů.\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Při načítání údajů o sezóně se něco pokazilo.\",\n  \"i18n.restartRequired\": \"Je vyžadován restart\",\n  \"components.Discover.plexwatchlist\": \"Váš seznam ke zhlédnutí\",\n  \"components.MovieDetails.theatricalrelease\": \"Uvedení v kinech\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Seznam ke zhlédnutí Plex\",\n  \"components.TvDetails.reportissue\": \"Nahlásit problém\",\n  \"components.MovieDetails.tmdbuserscore\": \"Uživatelské skóre TMDB\",\n  \"components.TvDetails.seasonstitle\": \"Sezóny\",\n  \"components.TvDetails.seasonnumber\": \"{seasonNumber}. sezóna\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomatometer Rotten Tomatoes\",\n  \"components.TvDetails.rtaudiencescore\": \"Skóre publika Rotten Tomatoes\",\n  \"components.TvDetails.tmdbuserscore\": \"Uživatelské skóre TMDB\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.Discover.emptywatchlist\": \"Zde se objeví média přidaná do vašeho <PlexWatchlistSupportLink>seznamu ke zhlédnutí Plex</PlexWatchlistSupportLink>.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Automaticky požádat o filmy na vašem <PlexWatchlistSupportLink>seznamu ke zhlédnutí Plexu</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Automaticky požádat o seriál na vašem <PlexWatchlistSupportLink>seznamu ke zhlédnutí Plexu</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Automaticky požádat o seriál\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Automaticky požádat o filmy\",\n  \"components.UserProfile.plexwatchlist\": \"Seznam ke zhlédnutí Plexu\",\n  \"components.UserProfile.emptywatchlist\": \"Zde se zobrazí média přidaná do vašeho <PlexWatchlistSupportLink>seznamu ke zhlédnutí Plexu</PlexWatchlistSupportLink>.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Aktuální frekvence\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"Filmy: {keywordTitle}\",\n  \"components.Discover.networks\": \"Stanice\",\n  \"components.Discover.moviegenres\": \"Žánry filmů\",\n  \"components.Discover.tmdbmoviegenre\": \"Žánr filmu TMDB\",\n  \"components.Discover.tmdbnetwork\": \"Stanice TMDB\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Zadejte vyhledávací dotaz\",\n  \"components.Discover.CreateSlider.starttyping\": \"Začínáte psát pro hledání.\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# aktivní filtr} few {# aktivní filtry} other {# aktivních filtrů}}\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streamovací služby\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Vytvořen nový posuvník a uloženo nastavení přizpůsobení objevování.\",\n  \"components.Discover.createnewslider\": \"Vytvořit nový posuvník\",\n  \"components.Discover.customizediscover\": \"Přizpůsobit objevování\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Musíte zadat hodnotu dat.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Musíte zadat název.\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Nepodařilo se odstranit posuvník.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Posuvník úspěšně odstraněn.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Přepnout viditelnost\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Odebrat\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"Seriály: {keywordTitle}\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Zde se objeví média přidaná do vašeho <PlexWatchlistSupportLink>seznamu ke zhlédnutí Plex</PlexWatchlistSupportLink>.\",\n  \"components.Discover.stopediting\": \"Zastavit úpravy\",\n  \"components.Discover.studios\": \"Studia\",\n  \"components.Discover.tmdbmoviekeyword\": \"Klíčové slovo filmu TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Klíčové slovo seriálu TMDB\",\n  \"components.Discover.tvgenres\": \"Žánry seriálu\",\n  \"components.Discover.updatefailed\": \"Při aktualizaci nastavení přizpůsobení objevování se něco pokazilo.\",\n  \"components.Discover.tmdbtvgenre\": \"Žánr seriálu TMDB\",\n  \"components.Discover.updatesuccess\": \"Nastavení přizpůsobení objevování aktualizováno.\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmy\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Oblíbenost vzestupně\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Oblíbenost sestupně\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Datum vydání vzestupně\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Datum vydání sestupně\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Název (A-Z) vzestupně\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Název (A-Z) sestupně\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Hodnocení TMDB vzestupně\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Hodnocení TMDB sestupně\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Seriály\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Datum prvního vysílání vzestupně\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# aktivní filtr} few {# aktivní filtry} other {# aktivních filtrů}}\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Datum prvního vysílání sestupně\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Oblíbenost vzestupně\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Oblíbenost sestupně\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Název (A-Z) vzestupně\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Název (A-Z) sestupně\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Hodnocení TMDB vzestupně\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Hodnocení TMDB sestupně\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Vymazat aktivní filtry\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtry\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Datum prvního vysílání\",\n  \"components.Discover.FilterSlideover.from\": \"Od\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# aktivní filtr} few {# aktivní filtry} other {# aktivních filtrů}}\",\n  \"components.Discover.FilterSlideover.genres\": \"Žánry\",\n  \"components.Discover.FilterSlideover.keywords\": \"Klíčová slova\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Původní jazyk\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Hodnocení mezi {minValue} a {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Datum vydání\",\n  \"components.Discover.FilterSlideover.runtime\": \"Délka\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minut délky\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Uživatelské hodnocení TMDB\",\n  \"components.Discover.FilterSlideover.to\": \"Do\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Váš seznam ke zhlédnutí\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Sezóna {seasonNumber} Epizoda {episodeNumber}\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Nedávno přidané\",\n  \"components.Discover.resetfailed\": \"Při obnovení nastavení přizpůsobení objevování se něco pokazilo.\",\n  \"components.Discover.resetsuccess\": \"Nastavení přizpůsobení objevování úspěšně obnoveno.\",\n  \"components.Discover.resettodefault\": \"Obnovit na výchozí\",\n  \"components.Discover.resetwarning\": \"Obnovit všechny posuvníky na výchozí hodnoty. Toto také odstraní všechny vlastní posuvníky!\",\n  \"components.Discover.tmdbsearch\": \"Hledání TMDB\",\n  \"components.Discover.tmdbstudio\": \"Studio TMDB\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmy\",\n  \"components.Layout.Sidebar.browsetv\": \"Seriály\",\n  \"components.Discover.CreateSlider.addSlider\": \"Přidat posuvník\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Vytvořit vlastní posuvník\",\n  \"components.Discover.CreateSlider.addfail\": \"Nepodařilo se vytvořit nový posuvník.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Upravit posuvník\",\n  \"components.Discover.CreateSlider.editfail\": \"Nepodařilo se upravit posuvník.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Upraven posuvník a uloženo nastavení přizpůsobení objevování.\",\n  \"components.Discover.CreateSlider.needresults\": \"Musíte mít alespoň 1 výsledek.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Žádné výsledky.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Zadejte ID žánru TMDB\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Zadejte ID klíčového slova TMDB\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Zadejte ID stanice TMDB\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Zadejte ID studia TMDB\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Hledat žánry…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Hledat klíčová slova…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Hledat studia…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Název posuvníku\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Nový klíč API byl úspěšně vygenerován!\",\n  \"components.TvDetails.Season.noepisodes\": \"Seznam epizod není dostupný.\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Celková velikost mezipaměti\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Musíte zadat platnou adresu URL\",\n  \"components.Selector.starttyping\": \"Začínáte psát pro vyhledávání.\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"Adresa URL nesmí končit lomítkem\",\n  \"components.Selector.searchStudios\": \"Hledat studia…\",\n  \"components.RequestCard.unknowntitle\": \"Neznámý název\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Neznámý název\",\n  \"components.Selector.searchGenres\": \"Vyberte žánry…\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"{jobScheduleSeconds, plural, one {Každou sekundu} few {Každé {jobScheduleSeconds} sekundy} other {Každých {jobScheduleSeconds} sekund}}\",\n  \"components.Settings.SettingsMain.apikey\": \"Klíč API\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Název aplikace\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Adresa URL aplikace\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Povolit ukládání obrázků do mezipaměti\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Ukládat obrázky z externích zdrojů do mezipaměti (vyžaduje značné množství místa na disku)\",\n  \"components.Settings.SettingsMain.general\": \"Obecné\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Obecná nastavení\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Konfigurace globálních a výchozích nastavení pro Seerr.\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Skrýt dostupná média\",\n  \"components.Settings.SettingsMain.locale\": \"Jazyk zobrazení\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Jazyk objevování\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrovat obsah podle původního jazyka\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Povolit částečné požadavky na seriály\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Obrázky v mezipaměti\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Mezipaměť obrázků\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Pokud je toto povoleno v nastavení, bude Seerr využívat proxy a ukládat do mezipaměti obrázky z předem nakonfigurovaných externích zdrojů. Obrázky v mezipaměti jsou uloženy do vaší složky s konfigurací. Soubory naleznete v <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Musíte zadat název aplikace\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Při generování nového klíče API se něco pokazilo.\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Při ukládání nastavení se něco pokazilo.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Nastavení úspěšně uloženo!\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Vyčištění mezipaměti obrázků\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Selector.searchKeywords\": \"Klíčová slova pro vyhledávání…\",\n  \"components.Selector.showless\": \"Zobrazit méně\",\n  \"components.Selector.showmore\": \"Zobrazit více\",\n  \"components.Selector.nooptions\": \"Žádné výsledky.\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Počet hlasů mezi {minValue} a {maxValue}\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Automaticky přidat dodatečné štítky s ID uživatele a zobrazovaným jménem žadatele\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Požadavky na štítek\",\n  \"i18n.collection\": \"Kolekce\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Štítkování požadavků\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Synchronizace dostupnosti médií\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Počet hlasů uživatelů TMDB\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Streamovací služby filmu TMDB\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Automaticky přidat dodatečný štítek s ID uživatele a zobrazovaným jménem žadatele\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Streamovací služby seriálu TMDB\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Zvuk oznámení\",\n  \"components.MovieDetails.imdbuserscore\": \"Uživatelské skóre IMDB– hlasy: {formattedCount}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Zvuk oznámení\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Typ seriálu anime\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Výchozí zařízení\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Výchozí zařízení\",\n  \"components.Settings.SonarrModal.seriesType\": \"Typ seriálu\",\n  \"components.Login.servertype\": \"Typ serveru\",\n  \"components.Login.validationEmailFormat\": \"Neplatný e-mail\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"Základ adresy URL musí začínat lomítkem\",\n  \"components.Login.validationEmailRequired\": \"Musíte zadat e-mail\",\n  \"components.Login.validationPortRequired\": \"Musíte zadat platné číslo portu\",\n  \"components.Login.back\": \"Vrátit se\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"Základ adresy URL nesmí končit lomítkem\",\n  \"components.Setup.back\": \"Vrátit se\",\n  \"components.Login.validationusernamerequired\": \"Uživatelské jméno je povinné\",\n  \"components.Setup.configemby\": \"Konfigurovat Emby\",\n  \"components.Login.signinwithjellyfin\": \"Použijte svůj účet {mediaServerName}\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Vyžadovat e-mail uživatele\",\n  \"components.TitleCard.addToWatchList\": \"Přidat na seznam ke zhlédnutí\",\n  \"components.TvDetails.removefromwatchlist\": \"Odebrat ze seznamu ke zhlédnutí\",\n  \"components.Login.credentialerror\": \"Nesprávné uživatelské jméno nebo heslo.\",\n  \"components.Setup.servertype\": \"Zvolte typ serveru\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Obvykle se provádí pouze jednou za 24 hodin. Seerr bude kontrolovat nedávno přidané položky vašeho {mediaServerName} serveru agresivněji. Pokud nastavujete Seerr poprvé, doporučujeme provést jednorázovou úplnou ruční prohledání knihovny!\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Toto nenávratně odebere tento {mediaType} z {arr}, včetně všech souborů.\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> úspěšně odebráno ze seznamu ke zhlédnutí!\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Musíte zadat platné ID role Discord\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Heslo je povinné.\",\n  \"components.Selector.searchStatus\": \"Vyberte stav…\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> úspěšně přidáno na seznam ke zhlédnutí!\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> úspěšně odebráno ze seznamu ke zhlédnutí!\",\n  \"components.Discover.FilterSlideover.status\": \"Stav\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"E-mailová adresa je neplatná.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"E-mailová adresa je povinná.\",\n  \"components.Login.emailtooltip\": \"Adresa nemusí být asociována s vaší instancí {mediaServerName}.\",\n  \"components.Login.enablessl\": \"Používat SSL\",\n  \"components.Login.initialsignin\": \"Připojit\",\n  \"components.Login.initialsigningin\": \"Připojování…\",\n  \"components.Login.invalidurlerror\": \"Nelze se připojit k serveru {mediaServerName}.\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.save\": \"Přidat\",\n  \"components.Login.saving\": \"Přidávání…\",\n  \"components.Login.username\": \"Uživatelské jméno\",\n  \"components.Login.validationemailformat\": \"Je požadován platný e-mail\",\n  \"components.Login.validationhostformat\": \"Je požadována platná adresa URL\",\n  \"components.Login.validationhostrequired\": \"Je požadována adresa URL {mediaServerName}\",\n  \"components.Login.validationservertyperequired\": \"Vyberte typ serveru\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.urlBase\": \"Základ adresy URL\",\n  \"components.Login.validationUrlTrailingSlash\": \"Adresa URL nesmí končit lomítkem\",\n  \"components.ManageSlideOver.removearr\": \"Odebrat z {arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"Odebrat z {arr} 4K\",\n  \"components.MovieDetails.addtowatchlist\": \"Přidat na seznam ke zhlédnutí\",\n  \"components.MovieDetails.downloadstatus\": \"Stav stahování\",\n  \"components.MovieDetails.openradarr\": \"Otevřít film v Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"Otevřít film v Radarr 4K\",\n  \"components.MovieDetails.removefromwatchlist\": \"Odebrat ze seznamu ke zhlédnutí\",\n  \"components.MovieDetails.watchlistError\": \"Něco se pokazilo. Zkuste to znovu.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> úspěšně přidáno do seznamu ke zhlédnutí!\",\n  \"components.RequestList.RequestItem.profileName\": \"Profil\",\n  \"components.RequestList.RequestItem.removearr\": \"Odebrat z {arr}\",\n  \"components.RequestList.sortDirection\": \"Přepnout směr řazení\",\n  \"components.Selector.canceled\": \"Zrušeno\",\n  \"components.Selector.inProduction\": \"V produkci\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Prohledání nedávno přidaných do Jellyfinu\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Úplné prohledání knihovny Jellyfinu\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Obnovovací token Plexu\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filtrovat obsah podle dostupnosti v regionu\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Region streamování\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Zobrazit streamovací služby podle dostupnosti v regionu\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Region objevování\",\n  \"components.Settings.apiKey\": \"Klíč API\",\n  \"components.Settings.invalidurlerror\": \"Nelze se připojit k serveru {mediaServerName}.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Adresa URL pro zapomenuté heslo\",\n  \"components.Settings.jellyfinSettings\": \"Nastavení {mediaServerName}\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"Nastavení {mediaServerName} bylo úspěšně uloženo!\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Něco se pokazilo při synchronizaci knihoven\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Nebyly nalezeny žádné knihovny\",\n  \"components.Settings.jellyfinlibraries\": \"Knihovny {mediaServerName}\",\n  \"components.Settings.jellyfinsettings\": \"Nastavení {mediaServerName}\",\n  \"components.Settings.manualscanJellyfin\": \"Ruční prohledání knihovny\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"Knihovny, ve kterých {mediaServerName} hledá tituly. Pokud nejsou vypsány žádné knihovny, klikněte na níže uvedené tlačítko.\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Konfigurace nastavení vašeho serveru {mediaServerName}. {mediaServerName} prohledává vaše knihovny {mediaServerName} pro zjištění dostupnosti obsahu.\",\n  \"components.Settings.save\": \"Uložit změny\",\n  \"components.Settings.saving\": \"Ukládání…\",\n  \"components.Settings.syncJellyfin\": \"Synchronizovat knihovny\",\n  \"components.Settings.syncing\": \"Synchronizace\",\n  \"components.Settings.tip\": \"Tip\",\n  \"components.Setup.configjellyfin\": \"Konfigurovat Jellyfin\",\n  \"components.Setup.configplex\": \"Konfigurovat Plex\",\n  \"components.Setup.configuremediaserver\": \"Konfigurovat mediální server\",\n  \"components.Setup.signin\": \"Přihlásit se\",\n  \"components.Setup.signinWithEmby\": \"Zadejte údaje k Emby\",\n  \"components.Setup.signinWithJellyfin\": \"Zadejte údaje k Jellyfinu\",\n  \"components.Setup.signinWithPlex\": \"Zadejte údaje k Plexu\",\n  \"components.Setup.subtitle\": \"Začněte výběrem mediálního serveru\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.TitleCard.watchlistError\": \"Něco se pokazilo. Zkuste to znovu.\",\n  \"components.TvDetails.addtowatchlist\": \"Přidat na seznam ke zhlédnutí\",\n  \"components.TitleCard.watchlistCancel\": \"seznam ke zhlédnutí pro <strong>{title}</strong> zrušen.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> úspěšně přidáno na seznam ke zhlédnutí!\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> úspěšně odebráno ze seznamu ke zhlédnutí!\",\n  \"components.TvDetails.watchlistError\": \"Něco se pokazilo. Zkuste to znovu.\",\n  \"components.UserList.importfromJellyfin\": \"Import uživatelů z {mediaServerName}\",\n  \"components.UserList.importfromJellyfinerror\": \"Něco se pokazilo během importování uživatelů z {mediaServerName}.\",\n  \"components.UserList.mediaServerUser\": \"Uživatel {mediaServerName}\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Neexistují žádní uživatelé {mediaServerName} k importu.\",\n  \"components.UserList.username\": \"Uživatelské jméno\",\n  \"components.UserList.validationUsername\": \"Musíte zadat uživatelské jméno\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Region pro objevování\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Filtrovat obsah podle regionální dostupnosti\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Uživatel {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Uložit změny\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Ukládání…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Region streamování\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Zobrazit streamovací služby podle regionální dostupnosti\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Tento e-mail je již používán!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Toto uživatelské jméno již používá jiný uživatel. Musíte si nastavit e-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Je požadován platný e-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"E-mail je povinný\",\n  \"components.UserProfile.localWatchlist\": \"Seznam ke zhlédnutí uživatele {username}\",\n  \"components.Login.title\": \"Přidat e-mail\",\n  \"components.Login.adminerror\": \"Musíte se přihlásit administrátorským účtem.\",\n  \"components.Login.description\": \"Protože je toto vaše první přihlášení do {applicationName}, musíte přidat platnou e-mailovou adresu.\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Něco se pokazilo při ukládání nastavení {mediaServerName}.\",\n  \"components.Settings.timeout\": \"Časový limit\",\n  \"components.Selector.ended\": \"Ukončeno\",\n  \"components.Selector.returningSeries\": \"Vracející se seriál\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Uživatelské avatary\",\n  \"i18n.specials\": \"Speciály\",\n  \"components.Discover.FilterSlideover.certification\": \"Hodnocení obsahu\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Vyloučit klíčová slova\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Popis problému\",\n  \"components.Login.loginwithapp\": \"Přihlásit se pomocí {appName}\",\n  \"components.Login.noadminerror\": \"Na serveru nebyl nalezen žádný uživatel s právy správce.\",\n  \"components.Login.orsigninwith\": \"Nebo se přihlaste pomocí\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Vyberte poskytovatele metadat\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Nepodařilo se načíst certifikace\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Maximální hodnocení\",\n  \"components.Selector.CertificationSelector.minRating\": \"Minimální hodnocení\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Nejsou dostupné žádné volby\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Vyberte certifikaci\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Vyberte zemi\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Začínáte psát pro vyhledávání.\",\n  \"components.Selector.pilot\": \"Úvodní díl\",\n  \"components.Selector.planned\": \"Plánováno\",\n  \"components.Selector.searchUsers\": \"Vyberte uživatele…\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Priorita\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Musíte nastavit číslo priority\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Povolit agenta\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Vložit plakát\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Nastavení oznámení ntfy se nepodařilo uložit.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Nastavení oznámení ntfy úspěšně uloženo!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Heslo\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Testovací oznámení ntfy se nepodařilo odeslat.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Odesílání testovacího oznámení ntfy…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Testovací oznámení ntfy odesláno!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Ověřování pomocí tokenu\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Téma\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Kořenová adresa URL serveru\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Uživatelské jméno\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Ověřování pomocí uživatelského jména a hesla\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Musíte zadat téma\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Musíte zadat platnou adresu URL\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Musíte vybrat alespoň jeden typ oznámení\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Vložit plakát\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Vložit plakát\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Podporovat proměnné adres URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Dostupné proměnné jsou zdokumentovány v části proměnné šablon webhooku\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"Adresa URL testovacího oznámení je nastavena na {testUrl} namísto skutečné adresy URL webhooku.\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Vložit plakát\",\n  \"components.Settings.Notifications.embedPoster\": \"Vložit plakát\",\n  \"components.Settings.Notifications.messageThreadId\": \"ID vlákna nebo tématu\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Pokud má váš skupinový chat povolena témata, můžete sem zadat ID vlákna nebo tématu\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"ID vlákna nebo tématu musí být kladné celé číslo\",\n  \"components.Settings.Notifications.webhookRoleId\": \"ID role oznámení\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"ID role zmíněné ve zprávě webhooku. Pro zakázání zmínek ponechte pole prázdné\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Podmínky\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Určuje podmínky před použitím změn parametrů. Každé pole musí být ověřeno, aby mohla být pravidla použita (operace AND). Pole je považováno za ověřené, pokud se shoduje některá z jeho vlastností (operace OR).\",\n  \"components.Settings.OverrideRuleModal.create\": \"Vytvořit pravidlo\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Nové pravidlo přepsání\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Upravit pravidlo přepsání\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Žánry\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Klíčová slova\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Jazyky\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Žádné štítky.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Profil kvality\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Kořenová složka\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Pravidlo přepsání bylo úspěšně vytvořeno!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Pravidlo přepsání bylo úspěšně aktualizováno!\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Vyberte profil kvality\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Vyberte kořenovou složku\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Vyberte službu\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Vyberte štítky\",\n  \"components.Settings.OverrideRuleModal.service\": \"Služba\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Použít toto pravidlo na vybranou službu.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Nastavení\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Určuje, která nastavení se změní, když jsou splněny výše uvedené podmínky.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Štítky\",\n  \"components.Settings.OverrideRuleModal.users\": \"Uživatelé\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Podmínky\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Žánr\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Klíčová slova\",\n  \"components.Settings.OverrideRuleTile.language\": \"Jazyk\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Profil kvality\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Kořenová složka\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Nastavení\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Štítky\",\n  \"components.Settings.OverrideRuleTile.users\": \"Uživatelé\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"Mezipaměť DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr ukládá vyhledávání DNS do mezipaměti, aby optimalizoval výkon a zabránil zbytečným voláním API.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Globální statistiky mezipaměti DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Tyto statistiky jsou agregovány ze všech záznamů v mezipaměti DNS.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Aktivní adresa\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Stáří\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"Mezipaměť DNS {hostname} byla vyprázdněna.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Úspěchy\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Neúspěchy\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Název hostitele\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"{jobScheduleDays, plural, one {Každý den} few {Každé {jobScheduleDays} dny} other {Každých {jobScheduleDays} dní}}\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Selhání\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Vyprázdnit mezipaměť DNS\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Míra úspěšnosti\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Úspěchy\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"Záložní IPv4\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Neúspěchy\",\n  \"components.Settings.SettingsJobsCache.size\": \"Velikost\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"Klíč API zkopírován do schránky.\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Povolit žádosti o speciální epizody\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Skrýt dostupná média ze stránek objevování, ale ne z výsledků vyhledávání\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Musíte zadat platnou adresu URL\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"Adresa URL nesmí končit lomítkem\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"Adresa URL YouTube\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"Základní adresa URL pro videa na YouTube, pokud je použita vlastní hostovaná instance YouTube.\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Povolit ochranu CSRF\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"NEPOVOLUJTE toto nastavení, pokud nerozumíte tomu, co děláte!\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Nastavit externí přístup k API na pouze pro čtení (vyžaduje HTTPS)\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"Mezipaměť DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"Maximální TTL mezipaměti DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"Minimální TTL mezipaměti DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"Toto NEPOVOLUJTE, pokud máte problémy s vyhledáváním DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Povolit ukládání do mezipaměti vyhledávání DNS pro optimalizaci výkonu a zabránění zbytečným voláním API\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Vynutit nejprve překlad na IPv4\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Vynutit, aby Seerr nejprve překládal adresy na IPv4 namísto IPv6\",\n  \"components.Settings.SettingsNetwork.network\": \"Síť\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Měly by být použity parametry sítě z vašeho kontejneru nebo systému namísto těchto nastavení. Více informací naleznete v {docs}.\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Nastavení sítě\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Konfigurovat nastavení sítě pro vaši instanci Seerr.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Adresy ignorované proxy serverem\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Použijte použijte „,“ jako oddělovač a „*.“ jako zástupný znak pro subdomény\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Obejít proxy pro místní adresy\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"Proxy HTTP(S)\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Název hostitele proxy\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Heslo proxy\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Port proxy\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Použít SSL pro proxy\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Uživatelské jméno proxy\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Při ukládání nastavení se něco pokazilo.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Nastavení byla úspěšně uložena!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Povolit podporu proxy\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Povolit, aby Seerr správně registroval IP adresy klientů za proxy serverem\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Musíte zadat platný port\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Musí být vybrána alespoň jedna metoda ověření.\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Metody přihlášení\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Konfigurace metod přihlášení pro uživatele.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Povolit přihlášení pomocí {mediaServerName}\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Povolit uživatelům přihlašovat se pomocí jejich účtu {mediaServerName}\",\n  \"components.Settings.addrule\": \"Nové pravidlo přepsání\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Všichni vybraní poskytovatelé metadat jsou funkční\",\n  \"components.Settings.animeMetadataProvider\": \"Poskytovatel metadat anime\",\n  \"components.Settings.chooseProvider\": \"Zvolte poskytovatele metadat pro různé typy obsahu\",\n  \"components.Settings.clickTest\": \"Klikněte na tlačítko „Testovat“ pro kontrolu připojení k poskytovatelům metadat\",\n  \"components.Settings.connectionTestFailed\": \"Test připojení selhal\",\n  \"components.Settings.failed\": \"Nefunguje\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Nepodařilo se uložit nastavení poskytovatele metadat\",\n  \"components.Settings.general\": \"Obecné\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} není klíčové slovo TMDB.\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Volitelně nakonfigurujte interní a externí koncové body pro váš server {mediaServerName}. Ve většině případů se externí adresa URL liší od interní. Pro přihlášení k {mediaServerName} lze také nastavit vlastní adresu URL pro obnovení hesla, pokud chcete přesměrovat na jinou stránku pro obnovení hesla. Můžete také změnit klíč API Jellyfin, který byl dříve automaticky vygenerován.\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Vlastní ověřování s automatickým seskupováním knihoven není podporováno\",\n  \"components.Settings.menuMetadataProviders\": \"Poskytovatelé metadat\",\n  \"components.Settings.menuNetwork\": \"Síť\",\n  \"components.Settings.metadataProviderSelection\": \"Výběr poskytovatele metadat\",\n  \"components.Settings.metadataProviderSettings\": \"Poskytovatelé metadat\",\n  \"components.Settings.metadataSettings\": \"Nastavení pro poskytovatele metadat\",\n  \"components.Settings.metadataSettingsSaved\": \"Nastavení poskytovatele metadat bylo uloženo\",\n  \"components.Settings.no\": \"Ne\",\n  \"components.Settings.noSpecialCharacters\": \"Konfigurace musí být seznamem identifikátorů klíčových slov TMDB oddělených čárkami a nesmí začínat ani končit čárkou.\",\n  \"components.Settings.nooptions\": \"Žádné výsledky.\",\n  \"components.Settings.notTested\": \"Netestováno\",\n  \"components.Settings.operational\": \"Funkční\",\n  \"components.Settings.overrideRules\": \"Pravidla přepsání\",\n  \"components.Settings.overrideRulesDescription\": \"Pravidla přepsání umožňují určit vlastnosti, které budou nahrazeny, pokud žádost odpovídá pravidlu.\",\n  \"components.Settings.providerStatus\": \"Stav poskytovatele metadat\",\n  \"components.Settings.scanbackground\": \"Prohledávání poběží na pozadí. Mezitím můžete pokračovat v nastavování.\",\n  \"components.Settings.searchKeywords\": \"Hledat klíčová slova…\",\n  \"components.Settings.seriesMetadataProvider\": \"Poskytovatel metadat seriálu\",\n  \"components.Settings.settings\": \"Nastavení\",\n  \"components.Settings.starttyping\": \"Začněte psát pro vyhledání.\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"Poskytovatel metadat TMDB nefunguje, vyberte jiného poskytovatele metadat\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"Poskytovatel TVDB nefunguje, vyberte jiného poskytovatele metadat\",\n  \"components.Settings.valueRequired\": \"Musíte zadat hodnotu.\",\n  \"components.Settings.yes\": \"Ano\",\n  \"components.Setup.librarieserror\": \"Ověření selhalo. Přepněte znovu knihovny pro pokračování.\",\n  \"components.UserList.importedfromJellyfin\": \"Úspěšně {userCount, plural, one {importován} few {importováni} other {importováno}} <strong>{userCount}</strong> {userCount, plural, one {uživatel} few {uživatelé} other {uživatelů}}!\",\n  \"components.UserList.newJellyfinsigninenabled\": \"Nastavení <strong>Povolit nové přihlášení {mediaServerName}</strong> je aktuálně povoleno. Uživatelé {mediaServerName} s přístupem ke knihovně nemusí být importováni, aby se mohli přihlásit.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Zadejte své přihlašovací údaje k {mediaServerName} pro propojení vašeho účtu s {applicationName}.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Tento účet je již propojen s uživatelem {applicationName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Nepodařilo se připojit k {mediaServerName} pomocí vašich přihlašovacích údajů\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Došlo k neznámé chybě\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Heslo\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Musíte zadat heslo\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Propojit\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Přidávání…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Propojit účet {mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Uživatelské jméno\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Musíte zadat uživatelské jméno\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Nelze odstranit propojený účet.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Došlo k neznámé chybě\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Propojené účty\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Tyto externí účty jsou propojeny s vaším účtem {applicationName}.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Nemáte žádné externí účty propojené s vaším účtem.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Nemáte oprávnění upravovat propojené účty tohoto uživatele.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Tento účet je již propojen s uživatelem Plexu\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Nelze se připojit k Plexu pomocí vašich přihlašovacích údajů\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Prohlížeč\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Vytvořeno\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Odstranit předplatné\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Zařízení\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Zakázat web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Při zakazování web push se něco pokazilo.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Povolit web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Při povolování web push se něco pokazilo.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Modul\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Spravovat zařízení\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Nemáte žádná předplatná web push k zobrazení.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Operační systém\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Předplatné odstraněno.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Při odstraňování předplatného uživatele se něco pokazilo.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"typ\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Neznámý\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Web push bylo zakázáno.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Web push bylo povoleno.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Nepodařilo se uložit nastavení oznámení web push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Nastavení oznámení web push úspěšně uloženo!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"ID vlákna nebo tématu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Pokud má váš skupinový chat povolená témata, můžete sem zadat ID vlákna nebo tématu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"ID vlákna nebo tématu musí být kladné celé číslo\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Propojené účty\",\n  \"i18n.completed\": \"Dokončeno\",\n  \"i18n.deleted\": \"Odstraněno\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Nadcházející seriály\",\n  \"components.Settings.SettingsNetwork.docs\": \"dokumentace\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"A aplikaci Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Přispět\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Podpořit Seerr\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Musíte zadat platné maximální TTL\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Musíte zadat platné minimální TTL\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Aktivní předplatné\",\n  \"component.BlocklistBlock.blocklistdate\": \"Datum zablokování\",\n  \"component.BlocklistBlock.blocklistedby\": \"Zablokoval\",\n  \"component.BlocklistModal.blocklisting\": \"Blokování\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> není zablokováno.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Spravovat zablokovaná média.\",\n  \"components.Blocklist.blocklistdate\": \"datum\",\n  \"components.Blocklist.blocklistedby\": \"{date} uživatelem {user}\",\n  \"components.Blocklist.filterManual\": \"Ručně\",\n  \"components.Blocklist.mediaName\": \"Název\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb Id\",\n  \"components.Blocklist.mediaType\": \"Typ\",\n  \"components.Blocklist.showAllBlocklisted\": \"Zobrazit všechna zablokovaná média\",\n  \"components.Blocklist.blocklistsettings\": \"Nastavení blokování\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Štítky blokování\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Nelze se připojit k {services}. Některé informace mohou být nedostupné.\",\n  \"components.Discover.timeWindowDay\": \"Denně\",\n  \"components.Discover.timeWindowWeek\": \"Týdně\",\n  \"components.Layout.Sidebar.blocklist\": \"Seznam blokovaných\",\n  \"components.PermissionEdit.blocklistedItems\": \"Zablokovat média\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Udělit oprávnění k zablokování médií.\",\n  \"components.PermissionEdit.manageblocklist\": \"Spravovat blokované\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Udělit oprávnění ke správě zablokovaných médií.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Zobrazit zablokovaná média\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Udělit oprávnění k zobrazení zablokovaných médií.\",\n  \"components.RequestList.unableToConnect\": \"Nepodařilo se připojit k {services}. Některé informace mohou být nedostupné.\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Priorita\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"Musíte zadat prioritu mezi 1 a 5\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Vlastní hlavičky\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Přidat hlavičku\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Nelze použít jak autorizační hlavičku, tak vlastní autorizační hlavičku. Jednu odeberte.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Všechny hlavičky musí mít jak název, tak hodnotu\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Název hlavičky\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Odebrat\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Přidat vlastní hlavičky HTTP, které se mají zahrnout do požadavků webhooku\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Hodnota hlavičky\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Zatím nebyla uložena do mezipaměti žádná vyhledávání DNS.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Zpracovat štítky blokování\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Zablokovat obsah pomocí štítků\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Omezit obsah zablokovaný na štítek\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"Úloha „Zpracovat štítky blokování“ zablokuje tento počet stránek v každém třídění. Větší čísla vytvoří přesnější seznam zablokovaných, ale také zaberou více místa.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Automaticky přidat obsah se štítky do seznamu zablokovaných pomocí úlohy „Zpracovat štítky blokování“\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Skrýt zablokované položky\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Skrýt zablokované položky ze stránek objevování pro všechny uživatele s oprávněním „Spravovat zablokované“\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Níže vložte konfiguraci štítku blokování.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Importovat konfiguraci štítku blokování\",\n  \"components.Settings.blocklistedTagsText\": \"Štítky blokování\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Opravdu chcete vymazat štítky blokování?\",\n  \"components.Settings.copyBlocklistedTags\": \"Štítky blokování zkopírovány do schránky.\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Není co kopírovat\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Kopírovat konfiguraci štítku blokování\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Importovat konfiguraci štítku blokování\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> již bylo zablokováno.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> bylo úspěšně zablokováno.\",\n  \"i18n.blocklisted\": \"Zablokováno\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"Časový limit požadavku API\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Maximální doba (v sekundách) čekání na odpovědi od externích služeb, jako jsou Radarr nebo Sonarr. Nastavte na 0, pokud nechcete časový limit.\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Odesílat VŠECHNY odchozí požadavky HTTP a HTTPS přes proxy server (hostitel/port). NEPOVOLUJE konfiguraci HTTPS, SSL ani certifikátů.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Musíte zadat platnou hodnotu časového limitu\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Monitorovat nové sezóny\",\n  \"i18n.addToBlocklist\": \"Přidat na seznam zablokovaných\",\n  \"i18n.blocklist\": \"Zablokováno\",\n  \"i18n.blocklistError\": \"Něco se pokazilo. Zkuste to znovu.\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> bylo úspěšně odebráno ze seznamu zablokovaných.\",\n  \"i18n.removefromBlocklist\": \"Odebrat se seznamu zablokovaných\"\n}\n"
  },
  {
    "path": "src/i18n/locale/da.json",
    "content": "{\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Se mere\",\n  \"components.Login.validationpasswordrequired\": \"Du skal angive en adgangskode\",\n  \"components.Login.validationemailrequired\": \"Du skal angive en gyldig email-adresse\",\n  \"components.Login.signinwithplex\": \"Brug din Plex-konto\",\n  \"components.Login.signinheader\": \"Log ind for at fortsætte\",\n  \"components.Login.signingin\": \"Logerer ind…\",\n  \"components.Login.signin\": \"Log ind\",\n  \"components.Login.password\": \"Adgangskode\",\n  \"components.Login.loginerror\": \"Noget gik galt under forsøget på at logge ind.\",\n  \"components.Login.forgotpassword\": \"Glemt adgangskode?\",\n  \"components.Login.email\": \"Email-adresse\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Udvikler\",\n  \"components.Layout.VersionStatus.outofdate\": \"Opdatering tilgængelig\",\n  \"components.Layout.UserDropdown.signout\": \"Log ud\",\n  \"components.Layout.UserDropdown.settings\": \"Indstillinger\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Layout.Sidebar.users\": \"Brugere\",\n  \"components.Layout.Sidebar.settings\": \"Indstillinger\",\n  \"components.Layout.Sidebar.requests\": \"Anmodninger\",\n  \"components.Layout.Sidebar.dashboard\": \"Udforsk\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Søg efter film og serier\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Visningssprog\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Alle sprog\",\n  \"components.LanguageSelector.languageServerDefault\": \"Standard ({language})\",\n  \"components.Discover.upcomingtv\": \"Kommende serier\",\n  \"components.Discover.upcomingmovies\": \"Kommende film\",\n  \"components.Discover.upcoming\": \"Kommende film\",\n  \"components.Discover.trending\": \"Aktuelle\",\n  \"components.Discover.recentrequests\": \"Seneste anmodninger\",\n  \"components.Discover.recentlyAdded\": \"Senest tilføjede\",\n  \"components.Discover.populartv\": \"Populære serier\",\n  \"components.Discover.popularmovies\": \"Populære film\",\n  \"components.Discover.discover\": \"Udforsk\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Seriegenrer\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Seriegenrer\",\n  \"components.Discover.NetworkSlider.networks\": \"Tjenester/netværk\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Filmgenrer\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Filmgenrer\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio}-film\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network}-serier\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language}e film\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre}-film\",\n  \"components.CollectionDetails.requestcollection4k\": \"Anmod om samling i 4K\",\n  \"components.CollectionDetails.requestcollection\": \"Anmod om samling\",\n  \"components.CollectionDetails.overview\": \"Overblik\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.MovieDetails.originaltitle\": \"Originaltitel\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Volumenmounten <code>{appDataPath}</code> blev ikke konfigureret korrekt. Alle data slettes, når containeren stoppes eller genstartes.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} film\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre}-serier\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language}e serier\",\n  \"components.Discover.StudioSlider.studios\": \"Studier\",\n  \"components.DownloadBlock.estimatedtime\": \"Estimeret {time}\",\n  \"components.MovieDetails.mark4kavailable\": \"Markér som tilgængelig i 4K\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} bagud\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stabil\",\n  \"components.MovieDetails.markavailable\": \"Markér som tilgængelig\",\n  \"components.MovieDetails.originallanguage\": \"Originalsprog\",\n  \"components.Login.signinwithoverseerr\": \"Brug din {applicationTitle}-konto\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Fuld rolleliste\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Filmstab\",\n  \"components.MovieDetails.budget\": \"Budget\",\n  \"components.MovieDetails.overview\": \"Overblik\",\n  \"components.MovieDetails.recommendations\": \"Anbefalinger\",\n  \"components.MovieDetails.overviewunavailable\": \"Overblik ikke tilgængelig.\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Udgivelsesdato} other {Udgivelsesdatoer}}\",\n  \"components.MovieDetails.revenue\": \"Omsætning\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutter\",\n  \"components.MovieDetails.similar\": \"Lignende titler\",\n  \"components.MovieDetails.streamingproviders\": \"Kan streames på\",\n  \"components.MovieDetails.viewfullcrew\": \"Vis filmstab\",\n  \"components.MovieDetails.watchtrailer\": \"Se trailer\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Giv tilladelse til at ændre avancerede medieanmodningsindstillinger.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Auto-godkend 4K-serier\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Giv automatisk godkendelse til anmodninger om 4K-film.\",\n  \"components.PermissionEdit.managerequests\": \"Administrere anmodninger\",\n  \"components.PermissionEdit.request4k\": \"Anmode om 4K\",\n  \"components.PermissionEdit.request4kMovies\": \"Anmode om 4K-film\",\n  \"components.PermissionEdit.request4kTv\": \"Anmode om 4K-serier\",\n  \"components.PermissionEdit.requestMovies\": \"Anmode om film\",\n  \"components.PermissionEdit.request\": \"Anmode\",\n  \"components.PersonDetails.ascharacter\": \"som {character}\",\n  \"components.PersonDetails.birthdate\": \"Født {birthdate}\",\n  \"components.RequestButton.approverequest4k\": \"Godkend 4K-anmodning\",\n  \"components.RequestButton.approverequests\": \"Godkend {requestCount, plural, one {anmodning} other {{requestCount} anmodninger}}\",\n  \"components.RequestList.RequestItem.editrequest\": \"Redigér anmodning\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} ikke fundet\",\n  \"components.RequestList.RequestItem.modified\": \"Ændret\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} af {user}\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Anmodet\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Sæson} other {Sæsoner}}\",\n  \"components.RequestList.requests\": \"Anmodninger\",\n  \"components.ResetPassword.resetpassword\": \"Nulstil din adgangskode\",\n  \"components.PermissionEdit.users\": \"Administrere brugere\",\n  \"components.PermissionEdit.usersDescription\": \"Giv tilladelse til at administrere brugere. Brugere med denne tilladelse kan ikke ændre brugere med eller give administratorrettigheder.\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Giv tilladelse til at se medieproblemer rapporteret af andre brugere.\",\n  \"components.PermissionEdit.viewrequests\": \"Se anmodninger\",\n  \"components.PersonDetails.alsoknownas\": \"Også kendt som: {names}\",\n  \"components.PersonDetails.appearsin\": \"Medvirket i\",\n  \"components.PersonDetails.crewmember\": \"Stabsmedlem\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} pr. {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {sæson} other {sæsoner}}\",\n  \"components.QuotaSelector.unlimited\": \"Ubegrænset\",\n  \"components.RequestBlock.profilechanged\": \"Kvalitetsprofil\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Sæson} other {Sæsoner}}\",\n  \"components.RequestButton.approve4krequests\": \"Godkend {requestCount, plural, one {4K-anmodning} other {{requestCount} 4K-anmodninger}}\",\n  \"components.RequestButton.approverequest\": \"Godkend anmodning\",\n  \"components.RequestButton.decline4krequests\": \"Afvis {requestCount, plural, one {4K-anmodning} other {{requestCount} 4K-anmodninger}}\",\n  \"components.RequestButton.declinerequest4k\": \"Afvis 4K-anmodning\",\n  \"components.RequestButton.requestmore4k\": \"Anmod om mere i 4K\",\n  \"components.RequestButton.viewrequest\": \"Vis anmodning\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.ResetPassword.password\": \"Adgangskode\",\n  \"components.Search.searchresults\": \"Søgeresultater\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Er du sikker på, at du vil slette denne kommentar?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Slet kommentar\",\n  \"components.IssueDetails.IssueComment.edit\": \"Redigér kommentar\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Indsendt {relativeTime} af {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Indsendt {relativeTime} af {username} (Redigeret)\",\n  \"components.IssueDetails.problemepisode\": \"Berørt episode\",\n  \"components.ManageSlideOver.downloadstatus\": \"Downloads\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Ingen anmodninger.\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {film}}\",\n  \"components.RequestButton.requestmore\": \"Anmod om mere\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Du kan se en oversigt over denne brugers anmodningsgrænser på deres <ProfileLink>profilside</ProfileLink>.\",\n  \"components.RequestModal.selectseason\": \"Vælg sæson(er)\",\n  \"components.ResetPassword.confirmpassword\": \"Bekræft adgangskode\",\n  \"components.ResetPassword.email\": \"Email-adresse\",\n  \"components.ResetPassword.gobacklogin\": \"Tilbage til login-siden\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Slet problem\",\n  \"components.IssueDetails.IssueDescription.description\": \"Beskrivelse\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Redigér beskrivelse\",\n  \"components.IssueDetails.allepisodes\": \"Alle episoder\",\n  \"components.IssueDetails.allseasons\": \"Alle sæsoner\",\n  \"components.IssueDetails.closeissue\": \"Luk problem\",\n  \"components.IssueDetails.closeissueandcomment\": \"Luk med kommentar\",\n  \"components.IssueDetails.comments\": \"Kommentarer\",\n  \"components.IssueDetails.deleteissue\": \"Slet problem\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Er du sikker på, at du vil slette dette problem?\",\n  \"components.IssueDetails.episode\": \"Episode {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Problem\",\n  \"components.IssueDetails.lastupdated\": \"Sidst opdateret\",\n  \"components.IssueDetails.leavecomment\": \"Kommentér\",\n  \"components.IssueDetails.openinarr\": \"Åbn i {arr}\",\n  \"components.IssueDetails.season\": \"Sæson {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Noget gik galt under redigering af problembeskrivelsen.\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Noget gik galt under sletningen af problemet.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Noget gik galt under opdateringen af problemstatus.\",\n  \"components.IssueDetails.unknownissuetype\": \"Ukendt\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Berørt episode\",\n  \"components.PermissionEdit.viewissues\": \"Vis problemer\",\n  \"components.RequestBlock.server\": \"Destinationsserver\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Ekstramateriale\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Berørt sæson\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Giv venligst en detaljeret forklaring af det problem, du stødte på.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Rapportér et problem\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Sæson {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Noget gik galt under indsendelsen af problemet.\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Vis problem\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Du skal angive en beskrivelse\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Giv tilladelse til at se medieanmodninger indsendt af andre brugere.\",\n  \"components.RequestButton.declinerequest\": \"Afvis anmodning\",\n  \"components.IssueDetails.playonplex\": \"Afspil i {mediaServerName}\",\n  \"components.IssueDetails.problemseason\": \"Berørt sæson\",\n  \"components.IssueDetails.issuetype\": \"Type\",\n  \"components.IssueDetails.nocomments\": \"Ingen kommentarer.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} åbnet {relativeTime} af {username}\",\n  \"components.IssueDetails.openin4karr\": \"Åbn i 4K {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Afspil i 4K i {mediaServerName}\",\n  \"components.IssueDetails.reopenissue\": \"Genåbn problem\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Genåbn med kommentar\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Problembeskrivelsen er redigeret!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Problemet er slettet!\",\n  \"components.IssueDetails.toaststatusupdated\": \"Problemstatus er blevet opdateret!\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Episode} other {Episoder}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Status\",\n  \"components.IssueList.IssueItem.issuetype\": \"Type\",\n  \"components.IssueList.IssueItem.opened\": \"Åbnet\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} af {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Berørt episode\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Sæson} other {Sæsoner}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Ukendt\",\n  \"components.IssueList.IssueItem.viewissue\": \"Vis problem\",\n  \"components.IssueList.issues\": \"Problemer\",\n  \"components.IssueList.showallissues\": \"Vis alle problemer\",\n  \"components.IssueList.sortAdded\": \"Seneste\",\n  \"components.IssueList.sortModified\": \"Sidst ændret\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Alle episoder\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Alle sæsoner\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episode {episodeNumber}\",\n  \"components.IssueModal.issueSubtitles\": \"Undertekster\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.Layout.Sidebar.issues\": \"Problemer\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Ryd data\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Dette vil uigenkaldeligt fjerne alle data for denne {mediaType}, herunder eventuelle anmodninger. Hvis dette element findes i dit {mediaServerName}-bibliotek, vil medieoplysningerne blive genskabt under den næste scanning.\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Hvad er der galt?\",\n  \"components.IssueModal.issueAudio\": \"Lyd\",\n  \"components.IssueModal.issueOther\": \"Andet\",\n  \"components.ManageSlideOver.tvshow\": \"serie\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studie} other {Studier}}\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Få besked, når andre brugere kommenterer på problemer.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Send notifikationer, når brugere indsender nye medieanmodninger, som automatisk godkendes.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Anmodninger\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Administrér {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Markér som tilgængelig i 4K\",\n  \"components.ManageSlideOver.markavailable\": \"Markér som tilgængelig\",\n  \"components.ManageSlideOver.openarr\": \"Åbn i {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Åbn i 4K {arr}\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Auto-godkend film\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Auto-godkend serier\",\n  \"components.PermissionEdit.autoapprove4k\": \"Auto-godkend 4K\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Auto-godkend 4K-film\",\n  \"components.PermissionEdit.requestTv\": \"Anmode om serier\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Giv automatisk godkendelse til anmodninger om film, der ikke er i 4K.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Giv tilladelse til at indsende anmodninger om serier, der ikke er i 4K.\",\n  \"components.RegionSelector.regionServerDefault\": \"Standard ({region})\",\n  \"components.RequestCard.deleterequest\": \"Slet anmodning\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} ikke fundet\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Sæson} other {Sæsoner}}\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Annullér anmodning\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Slet anmodning\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (standard)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Destinationsserver\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestList.RequestItem.requested\": \"Anmodet\",\n  \"components.RequestList.showallrequests\": \"Vis alle anmodninger\",\n  \"components.RequestList.sortAdded\": \"Seneste\",\n  \"components.RequestList.sortModified\": \"Sidst ændret\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avanceret\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Denne serie er en anime.\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Vælg tags\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Sprogprofil\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Ingen tags.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Anmod som\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Rodmappe\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Tags\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {film}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Ikke nok sæsonanmodninger tilbage\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Du kan se en oversigt over dine anmodningsgrænser på din <ProfileLink>profilside</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Du kan anmode om<strong>{limit}</strong> {type} hver <strong>{days}</strong> dage.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Denne bruger kan anmode om <strong>{limit}</strong> {type} hver <strong>{days}</strong> dage.\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Du skal indtaste en besked\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Åbne problemer\",\n  \"components.MovieDetails.showless\": \"Vis mindre\",\n  \"components.MovieDetails.cast\": \"Roller\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Indsend problem\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Problemrapport for <strong>{title}</strong> indsendt!\",\n  \"components.MovieDetails.showmore\": \"Vis mere\",\n  \"components.PermissionEdit.autoapprove\": \"Auto-godkendelse\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {dag} other {dage}}\",\n  \"components.RequestBlock.requestoverrides\": \"Anmodningstilsidesættelser\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} pr. {quotaDays} {days}</quotaUnits>\",\n  \"components.RequestButton.declinerequests\": \"Afvis {requestCount, plural, one {anmodning} other {{requestCount} anmodninger}}\",\n  \"components.RegionSelector.regionDefault\": \"Alle regioner\",\n  \"components.RequestBlock.rootfolder\": \"Rodmappe\",\n  \"components.RequestButton.viewrequest4k\": \"Vis 4K-anmodning\",\n  \"components.RequestModal.seasonnumber\": \"Sæson {number}\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Send beskeder, når medieanmodninger afvises.\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"For at modtage push-notifikationer på nettet skal Seerr benytte HTTPS.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Anmodning tilgængelig\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Anmodningsbehandling mislykkedes\",\n  \"components.PermissionEdit.admin\": \"Administrator\",\n  \"components.PermissionEdit.adminDescription\": \"Fuld administratoradgang. Omgår alle andre tilladelseskontroller.\",\n  \"components.PermissionEdit.advancedrequest\": \"Avancerede anmodninger\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Giv automatisk godkendelse til anmodninger om 4K-serier.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Giv tilladelse til at administrere medieanmodninger. Alle anmodninger fra en bruger med denne tilladelse vil blive automatisk godkendt.\",\n  \"components.PermissionEdit.request4kDescription\": \"Giv tilladelse til at indsende anmodninger om 4K-medier.\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Giv tilladelse til at indsende anmodninger om 4K-film.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Giv tilladelse til at indsende anmodninger om 4K-serier.\",\n  \"components.PermissionEdit.requestDescription\": \"Giv tilladelse til at indsende anmodninger om ikke-4K-medier.\",\n  \"components.RequestList.RequestItem.failedretry\": \"Noget gik galt under nyt forsøg på anmodning.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Du skal have mindst <strong>{seasons}</strong> {seasons, plural, one {sæsonanmodning} other {sæsonanmodninger}} tilbage for at indsende en anmodning om denne serie.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Denne bruger skal have mindst <strong>{seasons}</strong> {seasons, plural, one {sæsonanmodning} other {sæsonanmodninger}} tilbage for at indsende en anmodning om denne serie.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"sæson\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {sæson} other {sæsoner}}\",\n  \"components.RequestModal.alreadyrequested\": \"Allerede anmodet\",\n  \"components.RequestModal.cancel\": \"Annullér anmodning\",\n  \"components.RequestModal.edit\": \"Redigér anmodning\",\n  \"components.RequestModal.errorediting\": \"Noget gik galt under redigeringen af anmodningen.\",\n  \"components.RequestModal.numberofepisodes\": \"Antal episoder\",\n  \"components.RequestModal.pending4krequest\": \"Ventende 4K-anmodning\",\n  \"components.RequestModal.pendingapproval\": \"Din anmodning afventer godkendelse.\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Nulstilling af adgangskode er gennemført!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet-testnotifikationen kunne ikke sendes.\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registrér en applikation</ApplicationRegistrationLink> til brug med Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Indstillinger for Pushover-notifikationer gemt!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Kunne ikke sende en Pushover-testmeddelelse.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Du skal angive et gyldigt applikationstoken\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Du skal vælge mindst én notifikationstype\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Opret en <WebhookLink>indgående webhook</WebhookLink>-integration\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Aktivér agent\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON-indhold\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Nulstil til standard\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Du skal angive en gyldig URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Indstillinger for webhook-notifikationer kunne ikke gemmes.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Indstillinger for webhook-notifikationer er gemt!\",\n  \"components.Settings.Notifications.agentenabled\": \"Aktivér agent\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Få besked, når problemer genåbnes af andre brugere.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Få besked, når problemer er løst af andre brugere.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problem genåbnet\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Send notifikationer, når problemer genåbnes.\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Send notifikationer, når medieanmodninger ikke kan tilføjes til Radarr eller Sonarr.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Anmodning afventer godkendelse\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Få besked, når problemer, du har rapporteret, får nye kommentarer.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Få besked, når andre brugere rapporterer problemer.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Få besked, når problemer, du har rapporteret, genåbnes.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Få besked, når de problemer, du har rapporteret, er løst.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Få besked, når andre brugere indsender nye medieanmodninger, som automatisk godkendes.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Få besked, når dine medieanmodninger godkendes.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Få besked, når dine medieanmodninger bliver tilgængelige.\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Giv tilladelse til at indsende anmodninger om film, der ikke er i 4K.\",\n  \"components.RequestModal.requestCancel\": \"Anmodning om <strong>{title}</strong> annulleret.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> er blevet anmodet!\",\n  \"components.RequestModal.requestadmin\": \"Denne anmodning vil blive godkendt automatisk.\",\n  \"components.RequestModal.requestcancelled\": \"Anmodning om <strong>{title}</strong> annulleret.\",\n  \"components.RequestModal.requestedited\": \"Anmodning om <strong>{title}</strong> redigeret med succes!\",\n  \"components.RequestModal.requesterror\": \"Noget gik galt under indsendelsen af anmodningen.\",\n  \"components.RequestModal.requestfrom\": \"{username}s anmodning afventer godkendelse.\",\n  \"components.RequestModal.requestseasons\": \"Anmod om {seasonCount} {seasonCount, plural, one {sæson} other {sæsoner}}\",\n  \"components.RequestModal.season\": \"Sæson\",\n  \"components.ResetPassword.passwordreset\": \"Nulstilling af adgangskode\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Et link til nulstilling af adgangskode vil blive sendt til den angivne email-adresse, hvis den er knyttet til en gyldig bruger.\",\n  \"components.ResetPassword.validationemailrequired\": \"Du skal angive en gyldig email-adresse\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Adgangskoder skal stemme overens\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Adgangskoden er for kort; skal være mindst 8 tegn lang\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Du skal angive en adgangskode\",\n  \"components.Search.search\": \"Søg\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Adgangstoken\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Opret en token fra dine <PushbulletSettingsLink>kontoindstillinger</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Aktivér agent\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Indstillingerne for Pushbullet-notifikationer kunne ikke gemmes.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Indstillinger for Pushbullet-notifikationer er gemt!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Sender Pushbullet-testnotifikation…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet-testnotifikation sendt!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Du skal angive et adgangstoken\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Du skal vælge mindst én notifikationstype\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Applikations-API-token\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Aktivér agent\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Indstillinger for Pushover-notifikationer kunne ikke gemmes.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Sender Pushover-testnotifikation…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Notifikation om Pushover-test sendt!\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Sender web-push-testnotifikation…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Web-push-testmeddelelsen kunne ikke sendes.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Indstillinger for web-push-notifikationer kunne ikke gemmes.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Web-push-testmeddelelse sendt!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Indstillinger for web-push-notifikationer er gemt!\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Autorisations-header\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON-indhold er nulstillet!\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Hjælp til skabelonvariabler\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Webhook-testnotifikationen kunne ikke sendes.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Sender webhook-testnotifikation…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook-testnotifikation sendt!\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Få besked, når dine medieanmodninger afvises.\",\n  \"components.RequestModal.autoapproval\": \"Automatisk godkendelse\",\n  \"components.ResetPassword.emailresetlink\": \"Send email med gendannelseslink\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Anmodning godkendt automatisk\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Send notifikationer, når brugere indsender nye medieanmodninger, der kræver godkendelse.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Notifikationstyper\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Aktivér agent\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Anmodning godkendt\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Kommentar til problem\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Send notifikationer, når der kommer nye kommentarer til problemer.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problem rapporteret\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Send notifikationer, når der rapporteres problemer.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problem løst\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Send notifikationer, når problemer er løst.\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Send notifikationer, når medieanmodninger godkendes manuelt.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Send notifikationer, når medieanmodninger bliver tilgængelige.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Anmodning afvist\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Få besked, når medieanmodninger ikke kan føjes til Radarr eller Sonarr.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Få besked, når andre brugere indsender nye medieanmodninger, der kræver godkendelse.\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Giv automatisk godkendelse til alle 4K-medieanmodninger.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Giv automatisk godkendelse til alle ikke-4K-medieanmodninger.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Giv automatisk godkendelse til anmodninger om ikke-4K-serier.\",\n  \"components.PermissionEdit.createissues\": \"Rapportere problemer\",\n  \"components.PermissionEdit.createissuesDescription\": \"Giv tilladelse til at rapportere medieproblemer.\",\n  \"components.PermissionEdit.manageissues\": \"Administrere problemer\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Giv tilladelse til at administrere medieproblemer.\",\n  \"components.RequestCard.failedretry\": \"Noget gik galt under nyt forsøg på anmodning.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Ingen} other {<strong>#</strong>}} {type} {remaining, plural, one {anmodning} other {anmodninger}} tilbage\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Vi kunne ikke automatisk matche denne serie. Vælg venligst det korrekte match nedenfor.\",\n  \"components.RequestModal.pendingrequest\": \"Ventende anmodning\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Bruger- eller gruppenøgle\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Dit <UsersGroupsLink>bruger- eller gruppe-ID</UsersGroupsLink> på 30 tegn\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Du skal angive en gyldig bruger- eller gruppenøgle\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Aktivér agent\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Indstillinger for Slack-notifikationer kunne ikke gemmes.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Indstillinger for Slack-notifikationer er gemt!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack-testnotifikationen kunne ikke sendes.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack-testnotifikation sendt!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Sender Slack-testnotifikation…\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Du skal vælge mindst én notifikationstype\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Du skal angive en gyldig URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Du skal angive gyldigt JSON-indhold\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Du skal vælge mindst én notifikationstype\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Tillad selvsignerede certifikater\",\n  \"components.Settings.Notifications.authPass\": \"SMTP-adgangskode\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Bot Avatar-URL\",\n  \"components.Settings.Notifications.botUsername\": \"Bot-brugernavn\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Tillad brugerne også at starte en chat med din bot og konfigurere deres egne notifikationer\",\n  \"components.Settings.Notifications.encryptionTip\": \"I de fleste tilfælde bruger Implicit TLS port 465, og STARTTLS bruger port 587\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP privat nøgle\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Send notifikationer uden lyd\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP-vært\",\n  \"components.Settings.Notifications.senderName\": \"Afsendernavn\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord-testnotifikationen kunne ikke sendes.\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Du skal angive et gyldigt værtsnavn eller en gyldig IP-adresse\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Du skal angive en gyldig PGP-privatnøgle\",\n  \"components.Settings.Notifications.validationUrl\": \"Du skal angive en gyldig URL\",\n  \"components.Settings.Notifications.validationTypes\": \"Du skal vælge mindst én notifikationstype\",\n  \"components.Settings.RadarrModal.add\": \"Tilføj server\",\n  \"components.Settings.RadarrModal.apiKey\": \"API-nøgle\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Indlæser kvalitetsprofiler…\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Ingen tags.\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Test forbindelsen for at indlæse rodmapper\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Test forbindelsen for at indlæse kvalitetsprofiler\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Du skal angive en gyldig URL\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL'en må ikke slutte med en efterfølgende skråstreg\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL-basen må ikke slutte med en efterfølgende skråstreg\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Du skal angive et gyldigt værtsnavn eller en gyldig IP-adresse\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL-basen skal have en indledende skråstreg\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Du skal angive et gyldigt portnummer\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Du skal vælge en kvalitetsprofil\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Nyeste\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version}-ændringslog\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Udgivelser\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Samlet antal medier\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Samlet antal anmodninger\",\n  \"components.Settings.SettingsAbout.timezone\": \"Tidszone\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Opdateret\",\n  \"components.Settings.SettingsAbout.version\": \"Version\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr cacher anmodninger til eksterne API-slutpunkter for at optimere ydeevnen og undgå unødvendige API-kald.\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Nøglestørrelse\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Missere\",\n  \"components.Settings.RadarrModal.tags\": \"Tags\",\n  \"components.Settings.Notifications.chatId\": \"Chat-ID\",\n  \"components.Settings.Notifications.chatIdTip\": \"Start en chat med din bot, tilføj <GetIdBotLink>@get_id_bot</GetIdBotLink>, og send kommandoen <code>/my_id</code> command\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Signér krypterede e-mails med <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Indlæser tags…\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Aktivér scanning\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Du skal vælge en minimumstilgængelighed\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Du skal vælge en rodmappe\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Du skal angive et servernavn\",\n  \"components.Settings.SettingsJobsCache.command\": \"Kommando\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Nulstil downloadsynkronisering\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Opret en bot</CreateBotLink> til brug med Seerr\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Indstillinger for Discord-notifikationer kunne ikke gemmes.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Indstillinger for Discord-notifikationer er gemt!\",\n  \"components.Settings.Notifications.emailsender\": \"Afsenderadresse\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Indstillinger for email-notifikationer kunne ikke gemmes.\",\n  \"components.Settings.Notifications.encryptionNone\": \"Ingen\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Brug altid STARTTLS\",\n  \"components.Settings.RadarrModal.selecttags\": \"Vælg tags\",\n  \"components.Settings.RadarrModal.server4k\": \"4K-server\",\n  \"components.Settings.RadarrModal.servername\": \"Servernavn\",\n  \"components.Settings.RadarrModal.ssl\": \"Brug SSL\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Test forbindelsen for at indlæse tags\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Kunne ikke oprette forbindelse til Radarr.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr-forbindelse etableret!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Du skal angive en API-nøgle\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Aktuel\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Udgivelsesdata er i øjeblikket ikke tilgængelige.\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Vis ændringslog\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Vis på GitHub\",\n  \"components.Settings.SettingsAbout.about\": \"Om\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentation\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Få hjælp\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub-diskussioner\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Du kører <code>develop</code>-udgaven af Seerr, som kun anbefales til dem, der bidrager til udviklingen eller hjælper med at teste de nyeste funktioner.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename}-cachen er tømt.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Træffere\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Samlet antal nøgler\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Cachenavn\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Værdistørrelse\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Annullér job\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Downloadsynkronisering\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Redigér job\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Ny frekvens\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Hver {jobScheduleHours}. time\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Hvert {jobScheduleMinutes}. minut\",\n  \"components.Settings.Notifications.authUser\": \"SMTP-brugernavn\",\n  \"components.Settings.Notifications.botAPI\": \"Bot-autorisationstoken\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Brug implicit TLS\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram-testnotifikation sendt!\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Du skal angive et gyldigt chat-ID\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Du skal angive et bot-autorisationstoken\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Aktivér automatisk søgning\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Vælg kvalitetsprofil\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Vælg rodmappe\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Opdatering tilgængelig\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Tøm cache\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Indstillinger for email-notifikationer er gemt!\",\n  \"components.Settings.Notifications.encryption\": \"Krypteringsmetode\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Brug STARTTLS, hvis tilgængelig\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP-adgangskode\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Signér krypterede e-mails med <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.sendSilently\": \"Send lydløst\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP-port\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegram-notifikationsindstillingerne kunne ikke gemmes.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram-notifikationsindstillinger gemt!\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Sender Discord-testnotifikation…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord-testnotifikation sendt!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Email-testnotifikationen kunne ikke sendes.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Sender email-testnotifikation…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram-testnotifikationen kunne ikke sendes.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Sender Telegram-testnotifikation…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Email-testnotifikation sendt!\",\n  \"components.Settings.Notifications.validationEmail\": \"Du skal angive en gyldig email-adresse\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Du skal angive en PGP-adgangskode\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Du skal angive et gyldigt portnummer\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Opret en <DiscordWebhookLink>webhook-integration</DiscordWebhookLink> til din server\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL-base\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Tilføj ny 4K Radarr-server\",\n  \"components.Settings.RadarrModal.createradarr\": \"Tilføj ny Radarr-server\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Standard 4K-server\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Standard server\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Redigér 4K Radarr-server\",\n  \"components.Settings.RadarrModal.editradarr\": \"Redigér Radarr-server\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Ekstern URL\",\n  \"components.Settings.RadarrModal.hostname\": \"Værtsnavn eller IP-adresse\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Indlæser rodmapper…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimum tilgængelighed\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Rodmappe\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Vælg minimum tilgængelighed\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Ukendt job\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Redigér 4K Sonarr-server\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Redigér Sonarr-server\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Ingen tags.\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Basis-URL'en skal have en indledende skråstreg\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL'en må ikke slutte med en efterfølgende skråstreg\",\n  \"components.Settings.activeProfile\": \"Aktiv profil\",\n  \"components.Settings.cancelscan\": \"Annullér scanning\",\n  \"components.Settings.default\": \"Standard\",\n  \"components.Settings.default4k\": \"Standard 4K\",\n  \"components.Settings.deleteserverconfirm\": \"Er du sikker på, at du vil slette denne server?\",\n  \"components.Settings.notificationsettings\": \"Notifikationsindstillinger\",\n  \"components.Settings.plexlibraries\": \"Plex-biblioteker\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plex - Senest tilføjet-scanning\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} annulleret.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Type\",\n  \"components.Settings.SettingsLogs.logs\": \"Logfiler\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Aktivér scanning\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Sæson-mapper\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Noget gik galt under lagring af jobbet.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Jobnavn\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Jobs\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr kører visse vedligeholdelsesopgaver som regelmæssigt planlagte jobs, men de kan også udløses manuelt nedenfor. Manuel kørsel af et job vil ikke ændre dets tidsplan.\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Du kan også se disse logfiler direkte via <code>stdout</code>, eller i <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Konfigurer globale og standardbrugerindstillinger.\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime-tags\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime-sprogprofil\",\n  \"components.Settings.SonarrModal.apiKey\": \"API-nøgle\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Vælg rodmappe\",\n  \"components.Settings.SonarrModal.selecttags\": \"Vælg tags\",\n  \"components.Settings.SonarrModal.server4k\": \"4K-server\",\n  \"components.Settings.SonarrModal.servername\": \"Servernavn\",\n  \"components.Settings.SonarrModal.ssl\": \"Brug SSL\",\n  \"components.Settings.SonarrModal.tags\": \"Tags\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Test forbindelsen for at indlæse sprogprofiler\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Test forbindelsen for at indlæse tags\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Basis-URL'en må ikke slutte med en efterfølgende skråstreg\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Du skal angive et gyldigt værtsnavn eller en gyldig IP-adresse\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Du skal vælge en sprogprofil\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Du skal angive et servernavn\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Du skal angive et gyldigt portnummer\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Du skal vælge en kvalitetsprofil\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Du skal vælge en rodmappe\",\n  \"components.Settings.address\": \"Adresse\",\n  \"components.Settings.addsonarr\": \"Tilføj Sonarr-server\",\n  \"components.Settings.currentlibrary\": \"Nuværende bibliotek: {name}\",\n  \"components.Settings.email\": \"Email\",\n  \"components.Settings.enablessl\": \"Brug SSL\",\n  \"components.Settings.librariesRemaining\": \"Tilbageværende biblioteker: {count}\",\n  \"components.Settings.manualscanDescription\": \"Normalt vil dette kun blive kørt én gang i døgnet. Seerr vil tjekke din Plex-servers senest tilføjede mere aggressivt. Hvis dette er første gang, du konfigurerer Plex, anbefales en engangs fuld manuel biblioteksscanning!\",\n  \"components.Settings.menuGeneralSettings\": \"Generelt\",\n  \"components.Settings.menuJobs\": \"Jobs & cache\",\n  \"components.Settings.menuLogs\": \"Logfiler\",\n  \"components.Settings.menuNotifications\": \"Notifikationer\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Tjenester\",\n  \"components.Settings.menuUsers\": \"Brugere\",\n  \"components.Settings.noDefault4kServer\": \"En 4K {serverType}-server skal markeres som standard, for at brugerne kan indsende 4K {mediaType}-anmodninger.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Hvis du kun har en enkelt {serverType}-server til både ikke-4K og 4K-medier (eller du kun downloader 4K-medier), skal din {serverType}-server <strong>IKKE</strong> sættes som en 4K-server.\",\n  \"components.Settings.noDefaultServer\": \"Mindst én {serverType}-server skal markeres som standard for at {mediaType}-anmodninger kan behandles.\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Konfigurér og aktivér notifikationsagenter.\",\n  \"components.Settings.notifications\": \"Notifikationer\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Jobbet er redigeret!\",\n  \"components.Settings.hostname\": \"Værtsnavn eller IP-adresse\",\n  \"components.Settings.menuAbout\": \"Om\",\n  \"components.Settings.SettingsLogs.label\": \"Label\",\n  \"components.Settings.SettingsLogs.level\": \"Alvorlighed\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Logoplysninger\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL-base\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Tilføj ny 4K Sonarr-server\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Indlæser kvalitetsprofiler…\",\n  \"components.Settings.manualscan\": \"Manuel biblioteksscanning\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.mediaTypeSeries\": \"serie\",\n  \"components.Settings.notrunning\": \"Kører ikke\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Jobs & cache\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Aktivér nyt {mediaServerName}-login\",\n  \"components.Settings.SettingsUsers.users\": \"Brugere\",\n  \"components.Settings.addradarr\": \"Tilføj Radarr-server\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} startet.\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Næste kørsel\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plex - Fuld biblioteksscanning\",\n  \"components.Settings.SettingsJobsCache.process\": \"Proces\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr-scanning\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Kør nu\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr-scanning\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Kopierede logmeddelelse til udklipsholder.\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Kopiér til udklipsholder\",\n  \"components.Settings.SettingsLogs.extraData\": \"Yderligere data\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Fejlfinding\",\n  \"components.Settings.SettingsLogs.filterError\": \"Fejl\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Advarsel\",\n  \"components.Settings.SettingsLogs.message\": \"Besked\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pause\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Genoptag\",\n  \"components.Settings.SettingsLogs.showall\": \"Vis alle logfiler\",\n  \"components.Settings.SettingsLogs.time\": \"Tidsstempel\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Standardtilladelser\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Indledende tilladelser som tildeles nye brugere\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Aktivér lokal login\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Tillad brugere at logge ind med deres email-adresse og adgangskode\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Global grænse for filmanmodninger\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Tillad {mediaServerName}-brugere til at logge ind uden først at blive importeret\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Noget gik galt under lagring af indstillingerne.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Brugerindstillinger gemt!\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Global grænse for serieanmodninger\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Brugerindstillinger\",\n  \"components.Settings.SonarrModal.add\": \"Tilføj server\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime-kvalitetsprofil\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime-rodmappe\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Tilføj ny Sonarr-server\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Standard 4K-server\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Standard server\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Aktivér automatisk søgning\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Ekstern URL\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Indlæser rodmapper…\",\n  \"components.Settings.SonarrModal.hostname\": \"Værtsnavn eller IP-adresse\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Sprogprofil\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Indlæser tags…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Indlæser sprogprofiler…\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Rodmappe\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Vælg sprogprofil\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Vælg kvalitetsprofil\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Test forbindelsen for at indlæse kvalitetsprofiler\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Test forbindelsen for at indlæse rodmapper\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Kunne ikke oprette forbindelse til Sonarr.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr-forbindelse etableret!\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Du skal angive en API-nøgle\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Du skal angive en gyldig URL\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Ejer\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Notifikationsindstillinger\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.serverpreset\": \"Server\",\n  \"components.Settings.sonarrsettings\": \"Sonarr-indstillinger\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Start scanning\",\n  \"components.Settings.webAppUrlTip\": \"Du kan eventuelt dirigere brugere til webappen på din server i stedet for den \\\"hostede\\\" webapp\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Webapp</WebAppLink>-URL\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Setup.welcome\": \"Velkommen til Seerr\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.cast\": \"Roller\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutter\",\n  \"components.TvDetails.originallanguage\": \"Originalsprog\",\n  \"components.TvDetails.originaltitle\": \"Originaltitel\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {user} other {users}} importeret.\",\n  \"components.UserList.localLoginDisabled\": \"Indstillingen <strong>Aktivér lokal login</strong> er i øjeblikket deaktiveret.\",\n  \"components.UserList.validationpasswordminchars\": \"Adgangskoden er for kort; skal være mindst 8 tegn lang\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Redigér indstillinger\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Kontotype\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Vist navn\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Tilsidesæt global grænse\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtrér indhold efter originalsprog\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rolle\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Indstillinger for Discord-notifikationer er gemt!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Indstillinger for email-notifikationer er gemt!\",\n  \"components.Settings.toastPlexConnecting\": \"Forsøger at oprette forbindelse til Plex…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Bruger- eller gruppenøgle\",\n  \"components.Setup.signinMessage\": \"Kom i gang ved at logge ind\",\n  \"components.TvDetails.episodeRuntime\": \"Episodens spilletid\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Netværk} other {Netværk}}\",\n  \"components.TvDetails.similar\": \"Lignende serier\",\n  \"components.UserList.user\": \"Bruger\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Indstillingerne for Pushbullet-notifikationer kunne ikke gemmes.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Indstillinger for Pushover-notifikationer kunne ikke gemmes.\",\n  \"components.Settings.plexlibrariesDescription\": \"Bibliotekerne, Seerr scanner efter titler. Opsæt og gem dine Plex-forbindelsesindstillinger, og klik derefter på knappen nedenfor, hvis der ikke er angivet nogen biblioteker.\",\n  \"components.Settings.plexsettingsDescription\": \"Konfigurér indstillingerne for din Plex-server. Seerr scanner dine Plex-biblioteker for at afgøre tilgængeligheden af indhold.\",\n  \"components.Settings.radarrsettings\": \"Radarr-indstillinger\",\n  \"components.TvDetails.nextAirDate\": \"Næste udsendelsesdato\",\n  \"components.TvDetails.recommendations\": \"Anbefalinger\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# sæson} andre {# sæsoner}}\",\n  \"components.TvDetails.streamingproviders\": \"Kan streames på\",\n  \"components.TvDetails.viewfullcrew\": \"Vis hele stab\",\n  \"components.TvDetails.watchtrailer\": \"Se trailer\",\n  \"components.UserList.accounttype\": \"Type\",\n  \"components.UserList.admin\": \"Administrator\",\n  \"components.UserList.autogeneratepassword\": \"Generér automatisk adgangskode\",\n  \"components.UserList.autogeneratepasswordTip\": \"Send en servergenereret adgangskode til brugeren via email\",\n  \"components.UserList.bulkedit\": \"Masseredigering\",\n  \"components.UserList.create\": \"Opret\",\n  \"components.UserList.created\": \"Tilmeldt\",\n  \"components.UserList.createlocaluser\": \"Opret lokal bruger\",\n  \"components.UserList.creating\": \"Opretter…\",\n  \"components.UserList.importfromplexerror\": \"Noget gik galt under import af Plex-brugere.\",\n  \"components.UserList.sortRequests\": \"Antal anmodninger\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Grænse for serieanmodninger\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Indstillinger gemt!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Bruger\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Bruger-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"Det <FindDiscordIdLink>flercifrede ID-nummer</FindDiscordIdLink>, der er knyttet til din brugerkonto\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Indstillinger for Discord-notifikationer kunne ikke gemmes.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Kryptér e-mails med <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Adgangstoken\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Opret en token fra dine <PushbulletSettingsLink>kontoindstillinger</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Indstillinger for Pushbullet-notifikationer er gemt!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Applikations-API-token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registrér en applikation</ApplicationRegistrationLink> til brug med {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Dit <UsersGroupsLink>bruger- eller gruppe-ID</UsersGroupsLink> på 30 tegn\",\n  \"components.Settings.scan\": \"Synkronisér biblioteker\",\n  \"components.Settings.scanning\": \"Synkroniserer…\",\n  \"components.Settings.serverLocal\": \"lokal\",\n  \"components.Settings.serverRemote\": \"fjern\",\n  \"components.Settings.serverSecure\": \"sikker\",\n  \"components.Settings.serverpresetLoad\": \"Tryk på knappen for at indlæse tilgængelige servere\",\n  \"components.Settings.services\": \"Tjenester\",\n  \"components.Settings.webpush\": \"Web-push\",\n  \"components.UserList.userlist\": \"Brugerliste\",\n  \"components.Settings.plexsettings\": \"Plex-indstillinger\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Fuld serie-rolleliste\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtrér indhold efter regional tilgængelighed\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Noget gik galt under lagring af indstillinger.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notifikationer\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Indstillinger for email-notifikationer kunne ikke gemmes.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"PGP offentlig nøgle\",\n  \"components.TvDetails.showtype\": \"Serietype\",\n  \"components.UserList.sortCreated\": \"Tilmeldingsdato\",\n  \"components.UserList.deleteconfirm\": \"Er du sikker på, at du vil slette denne bruger? Alle deres anmodningsdata vil blive fjernet permanent.\",\n  \"components.Settings.serverpresetManualMessage\": \"Manuel konfiguration\",\n  \"components.Settings.serverpresetRefreshing\": \"Henter servere…\",\n  \"components.Settings.serviceSettingsDescription\": \"Konfigurer din(e) {serverType}-server(e) nedenfor. Du kan forbinde flere {serverType}-servere, men kun to af dem kan markeres som standard(én ikke-4K og én 4K). Administratorer kan tilsidesætte den server, der bruges til at behandle nye anmodninger, før de godkendes.\",\n  \"components.Settings.settingUpPlexDescription\": \"For at konfigurere Plex kan du enten indtaste oplysningerne manuelt eller vælge en server hentet fra <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Tryk på knappen til højre for rullemenuen for at hente listen over tilgængelige servere.\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Kunne ikke oprette forbindelse til Plex.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex-forbindelse oprettet!\",\n  \"components.Settings.toastPlexRefresh\": \"Henter serverliste fra Plex…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Kunne ikke hente Plex-serverlisten.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Plex-serverliste hentet!\",\n  \"components.Settings.validationHostnameRequired\": \"Du skal angive et gyldigt værtsnavn eller en gyldig IP-adresse\",\n  \"components.Settings.validationPortRequired\": \"Du skal angive et gyldigt portnummer\",\n  \"components.Setup.configureservices\": \"Konfigurér tjenester\",\n  \"components.Setup.continue\": \"Fortsæt\",\n  \"components.Setup.finish\": \"Færdiggør opsætning\",\n  \"components.Setup.finishing\": \"Færdiggør…\",\n  \"components.Setup.setup\": \"Opsætning\",\n  \"components.TvDetails.firstAirDate\": \"Første udsendelsesdato\",\n  \"components.TvDetails.overview\": \"Oversigt\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Fuld serie-stab\",\n  \"components.TvDetails.overviewunavailable\": \"Oversigt ikke tilgængelig.\",\n  \"components.UserList.localuser\": \"Lokal bruger\",\n  \"components.UserList.deleteuser\": \"Slet bruger\",\n  \"components.UserList.nouserstoimport\": \"Der er ingen Plex-brugere at importere.\",\n  \"components.UserList.edituser\": \"Redigér brugertilladelser\",\n  \"components.UserList.email\": \"Email-adresse\",\n  \"components.UserList.importfrommediaserver\": \"Importér {mediaServerName}-brugere\",\n  \"components.UserList.importfromplex\": \"Importér Plex-brugere\",\n  \"components.UserList.owner\": \"Ejer\",\n  \"components.UserList.password\": \"Adgangskode\",\n  \"components.UserList.passwordinfodescription\": \"Konfigurér en applikations-URL og aktivér email-notifikationer for at tillade automatisk generering af adgangskoder.\",\n  \"components.UserList.plexuser\": \"Plex-bruger\",\n  \"components.UserList.role\": \"Rolle\",\n  \"components.UserList.sortDisplayName\": \"Vist navn\",\n  \"components.UserList.totalrequests\": \"Anmodninger\",\n  \"components.UserList.usercreatedfailed\": \"Noget gik galt under oprettelsen af brugeren.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Den angivne email-adresse er allerede i brug af en anden bruger.\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Vis profil\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Bruger-ID: {userid}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrator\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Brugerfladesprog\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Generelt\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Generelle indstillinger\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Standard ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Lokal bruger\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Grænse for filmanmodninger\",\n  \"components.UserList.usercreatedsuccess\": \"Bruger oprettet!\",\n  \"components.UserList.userdeleted\": \"Brugeren er slettet!\",\n  \"components.UserList.userdeleteerror\": \"Noget gik galt under sletningen af brugeren.\",\n  \"components.UserList.userfail\": \"Noget gik galt under lagring af brugertilladelser.\",\n  \"components.UserList.users\": \"Brugere\",\n  \"components.UserList.userssaved\": \"Brugertilladelser gemt!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Sprog til Udforsk-siden\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex-bruger\",\n  \"components.UserList.validationEmail\": \"Email påkrævet\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Tilmeldt {joindate}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Region til Udforsk-siden\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Indstillinger for Pushover-notifikationer gemt!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram-notifikationsindstillinger gemt!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web-push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chat-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Start en chat</TelegramBotLink>, tilføj <GetIdBotLink>@get_id_bot</GetIdBotLink> og benyt <code>/my_id</code>-kommandoen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Nuværende adgangskode\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Telegram-notifikationsindstillingerne kunne ikke gemmes.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Du skal angive et adgangstoken\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Du skal angive et gyldigt applikationstoken\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Du skal angive en gyldig bruger- eller gruppenøgle\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Du skal angive et gyldigt chat-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Du skal angive et gyldigt bruger-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Du skal angive en gyldig offentlig PGP-nøgle\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Bekræft adgangskode\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Ny adgangskode\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Denne brugerkonto har i øjeblikket ikke en adgangskode angivet. Konfigurer en adgangskode nedenfor for at aktivere denne konto til at logge ind som en \\\"lokal bruger\\\".\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Der er i øjeblikket ikke angivet en adgangskode til din konto. Konfigurer en adgangskode nedenfor for at aktivere login som en \\\"lokal bruger\\\" ved hjælp af din e-mailadresse.\",\n  \"i18n.next\": \"Næste\",\n  \"pages.oops\": \"Ups\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Send notifikationer uden lyd\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Adgangskoden er gemt!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Du skal bekræfte den nye adgangskode\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Du skal angive en ny adgangskode\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Tilladelser\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Generelt\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notifikationer\",\n  \"components.UserProfile.movierequests\": \"Filmanmodninger\",\n  \"components.UserProfile.limit\": \"{remaining} ud af {limit}\",\n  \"i18n.available\": \"Tilgængelig\",\n  \"i18n.experimental\": \"Eksperimentel\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.edit\": \"Redigér\",\n  \"i18n.failed\": \"Mislykkedes\",\n  \"i18n.noresults\": \"Ingen resultater.\",\n  \"i18n.notrequested\": \"Ikke anmodet\",\n  \"i18n.settings\": \"Indstillinger\",\n  \"i18n.usersettings\": \"Brugerindstillinger\",\n  \"i18n.tvshows\": \"Serier\",\n  \"i18n.unavailable\": \"Ikke tilgængelig\",\n  \"i18n.view\": \"Vis\",\n  \"components.UserProfile.unlimited\": \"Ubegrænset\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Adgangskode\",\n  \"i18n.request\": \"Anmod\",\n  \"i18n.processing\": \"Behandler\",\n  \"i18n.request4k\": \"Anmod i 4K\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Send lydløst\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Du har ikke tilladelse til at ændre denne brugers adgangskode.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Adgangskode\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Noget gik galt under lagring af adgangskoden.\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Tilladelser\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Du har ikke tilladelse til at ændre denne brugers indstillinger.\",\n  \"components.UserProfile.pastdays\": \"{type} (seneste {days} dage)\",\n  \"components.UserProfile.recentrequests\": \"Seneste anmodninger\",\n  \"components.UserProfile.requestsperdays\": \"{limit} tilbage\",\n  \"components.UserProfile.totalrequests\": \"Samlede anmodninger\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Noget gik galt under lagring af adgangskoden. Blev din nuværende adgangskode indtastet korrekt?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Adgangskoder skal stemme overens\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Du skal angive din nuværende adgangskode\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Adgangskoden er for kort; skal være mindst 8 tegn lang\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Noget gik galt under lagring af indstillingerne.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Tilladelser gemt!\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Du kan ikke ændre dine egne tilladelser.\",\n  \"components.UserProfile.seriesrequest\": \"Serieanmodninger\",\n  \"i18n.declined\": \"Afvist\",\n  \"i18n.delete\": \"Slet\",\n  \"i18n.deleting\": \"Sletter…\",\n  \"i18n.loading\": \"Indlæser…\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.movies\": \"Film\",\n  \"i18n.open\": \"Åbent\",\n  \"i18n.partiallyavailable\": \"Delvist tilgængelig\",\n  \"i18n.pending\": \"Ventende\",\n  \"i18n.requesting\": \"Anmoder…\",\n  \"i18n.resolved\": \"Løst\",\n  \"i18n.resultsperpage\": \"Vis {pageSize} resultater pr. side\",\n  \"i18n.retry\": \"Prøv igen\",\n  \"i18n.retrying\": \"Prøver igen…\",\n  \"i18n.save\": \"Gem ændringer\",\n  \"i18n.previous\": \"Forrige\",\n  \"i18n.approve\": \"Godkend\",\n  \"i18n.approved\": \"Godkendt\",\n  \"i18n.areyousure\": \"Er du sikker?\",\n  \"i18n.back\": \"Tilbage\",\n  \"i18n.cancel\": \"Annullér\",\n  \"i18n.canceling\": \"Annullerer…\",\n  \"i18n.close\": \"Luk\",\n  \"i18n.decline\": \"Afvis\",\n  \"i18n.showingresults\": \"Viser <strong>{from}</strong> til <strong>{to}</strong> af <strong>{total}</strong> resultater\",\n  \"i18n.status\": \"Status\",\n  \"i18n.testing\": \"Tester…\",\n  \"i18n.tvshow\": \"Serie\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"Intern serverfejl\",\n  \"pages.pagenotfound\": \"Siden blev ikke fundet\",\n  \"pages.returnHome\": \"Gå hjem\",\n  \"i18n.all\": \"Alle\",\n  \"i18n.advanced\": \"Avanceret\",\n  \"i18n.requested\": \"Anmodet\",\n  \"pages.serviceunavailable\": \"Tjenesten er ikke tilgængelig\",\n  \"pages.somethingwentwrong\": \"Noget gik galt\",\n  \"i18n.saving\": \"Gemmer…\",\n  \"i18n.test\": \"Test\",\n  \"components.RequestModal.requestseasons4k\": \"Anmod om {seasonCount} {seasonCount, plural, one {sæson} other {sæsoner}} i 4K\",\n  \"components.IssueDetails.commentplaceholder\": \"Tilføj en kommentar…\",\n  \"components.RequestModal.approve\": \"Godkend anmodning\",\n  \"components.RequestModal.requestApproved\": \"Anmodning om <strong>{title}</strong> godkendt!\",\n  \"components.RequestModal.requestmovies4k\": \"Anmod om {count} {count, plural, one {film} other {film}} i 4K\",\n  \"components.RequestModal.selectmovies\": \"Vælg film\",\n  \"components.MovieDetails.productioncountries\": \"Produktions{countryCount, plural, one {land} other {lande}}\",\n  \"components.TvDetails.productioncountries\": \"Produktions{countryCount, plural, one {land} other {lande}}\",\n  \"components.RequestModal.requestmovies\": \"Anmod om {count} {count, plural, one {film} other {film}}\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Aktivér agent\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Server-URL\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Markér alle sæsoner som tilgængelige\",\n  \"components.ManageSlideOver.pastdays\": \"Sidste {days, number} dage\",\n  \"components.ManageSlideOver.opentautulli\": \"Åben i Tautulli\",\n  \"components.ManageSlideOver.playedby\": \"Afspillet af\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify-notifikationsindstillinger er gemt!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify-testnotifikationen kunne ikke sendes.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Sender Gotify-testnotifikation…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify-testnotifikation sendt!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Applikationstoken\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Du skal vælge mindst én notifikationstype\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Du skal angive en gyldig URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL'en må ikke slutte med en efterfølgende skråstreg\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Markér alle sæsoner som tilgængelige i 4K\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avanceret\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Du skal angive et applikationstoken\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify-notifikationsindstillingerne kunne ikke gemmes.\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL'en må ikke slutte med en efterfølgende skråstreg\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Medier\",\n  \"components.Settings.RadarrModal.released\": \"Udgivet\",\n  \"components.Settings.tautulliApiKey\": \"API-nøgle\",\n  \"components.Settings.tautulliSettings\": \"Tautulli-indstillinger\",\n  \"components.Settings.tautulliSettingsDescription\": \"Konfigurér eventuelt indstillingerne for din Tautulli-server. Seerr henter visningshistorikdata for dine Plex-medier fra Tautulli.\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Noget gik galt under lagring af Tautulli-indstillinger.\",\n  \"components.Settings.validationApiKey\": \"Du skal angive en API-nøgle\",\n  \"components.UserProfile.recentlywatched\": \"Senest set\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli-indstillinger gemt!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord-bruger-ID\",\n  \"components.Settings.validationUrl\": \"Du skal angive en gyldig URL\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL-basen skal have en indledende skråstreg\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Det <FindDiscordIdLink>flercifrede ID-nummer</FindDiscordIdLink> der er knyttet til din Discord-brugerkonto\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"URL-basen må ikke slutte med en efterfølgende skråstreg\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Du skal angive et gyldigt Discord-bruger-ID\",\n  \"i18n.import\": \"Importér\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K-medier\",\n  \"components.Settings.externalUrl\": \"Ekstern URL\",\n  \"components.Settings.RadarrModal.announced\": \"Annonceret\",\n  \"components.Settings.RadarrModal.inCinemas\": \"I biograferne\",\n  \"components.Settings.urlBase\": \"URL-base\",\n  \"components.UserList.newplexsigninenabled\": \"Indstillingen <strong>Aktivér nyt Plex-login</strong> er i øjeblikket aktiveret. Plex-brugere med biblioteksadgang behøver ikke at være importeret for at logge ind.\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Datamappe\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Kanal-tag\",\n  \"i18n.importing\": \"Importerer…\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Nuværende frekvens\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Oprydning af billedcache\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Billedcache\",\n  \"components.Settings.experimentalTooltip\": \"Aktivering af denne indstilling kan resultere i uventet applikationsadfærd\",\n  \"components.TvDetails.Season.noepisodes\": \"Episodelisten er ikke tilgængelig.\",\n  \"components.RequestBlock.edit\": \"Redigér anmodning\",\n  \"components.TitleCard.tmdbid\": \"TMDB-ID\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Din Se senere-liste\",\n  \"components.Layout.UserDropdown.requests\": \"Anmodninger\",\n  \"components.MovieDetails.physicalrelease\": \"Fysisk udgivelse\",\n  \"components.PermissionEdit.autorequestSeries\": \"Auto-anmodning om serier\",\n  \"components.RequestCard.cancelrequest\": \"Annullér anmodning\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB-ID\",\n  \"components.RequestModal.requestcollectiontitle\": \"Anmod om samling\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Når det er aktiveret i indstillingerne, vil Seerr proxy- og cachelagre billeder fra forudkonfigurerede eksterne kilder. Cachelagrede billeder gemmes i din konfigurationsmappe. Du kan finde filerne i <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Cachelagrede billeder\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Se detaljer\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Samlet cachestørrelse\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} opdateret\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Klik venligst på knappen nedenfor for at genindlæse applikationen.\",\n  \"components.StatusChecker.reloadApp\": \"Genindlæs {applicationTitle}\",\n  \"components.TitleCard.cleardata\": \"Ryd data\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB-ID\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Anmod om film i 4K\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr skal genstartes for at ændringer af denne indstilling træder i kraft\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Genstart venligst serveren for at anvende de opdaterede indstillinger.\",\n  \"components.UserProfile.emptywatchlist\": \"Medier, der er føjet til din <PlexWatchlistSupportLink>Plex Se senere-liste</PlexWatchlistSupportLink>, vises her.\",\n  \"components.MovieDetails.theatricalrelease\": \"Biografpremiere\",\n  \"components.PermissionEdit.viewrecent\": \"Se senest tilføjede\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Giv tilladelse til at se listen over senest tilføjede medier.\",\n  \"components.RequestCard.tmdbid\": \"TMDB-ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB-ID\",\n  \"components.StatusChecker.restartRequired\": \"Genstart af server påkrævet\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB-ID\",\n  \"components.MovieDetails.digitalrelease\": \"Digital udgivelse\",\n  \"components.PermissionEdit.autorequest\": \"Auto-anmodning\",\n  \"components.PermissionEdit.autorequestMovies\": \"Auto-anmodning om film\",\n  \"components.Settings.deleteServer\": \"Slet {serverType}-server\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Auto-anmod om film\",\n  \"components.ManageSlideOver.alltime\": \"Al tid\",\n  \"components.Settings.Notifications.enableMentions\": \"Aktivér omtaler\",\n  \"components.TvDetails.manageseries\": \"Administrér serie\",\n  \"components.MovieDetails.reportissue\": \"Rapportér et problem\",\n  \"components.MovieDetails.managemovie\": \"Administrér film\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Giv tilladelse til automatisk at indsende anmodninger om ikke-4K-film via Plex Se senere-liste.\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Giv tilladelse til automatisk at indsende anmodninger om ikke-4K-serier via Plex Se senere-liste.\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} ikke fundet\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex Se senere-liste\",\n  \"components.Discover.plexwatchlist\": \"Din Se senere-liste\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Anmodning indsendt automatisk\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Få besked, når der automatisk indsendes nye medieanmodninger til elementer på din Se senere-liste.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Se {mediaServerName} Se senere-lister\",\n  \"components.Settings.advancedTooltip\": \"Forkert konfiguration af denne indstilling kan resultere i funktionsfejl\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Anmod automatisk om serier på din <PlexWatchlistSupportLink>Plex Se senere-liste</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.plexwatchlist\": \"Plex Se senere-liste\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Filmanmodninger\",\n  \"components.AirDateBadge.airedrelative\": \"Sendt {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Sendes {relativeTime}\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes-publikumsscore\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Giv tilladelse til at se andre brugeres {mediaServerName} Se senere-liste.\",\n  \"components.RequestBlock.approve\": \"Godkend anmodning\",\n  \"components.RequestBlock.decline\": \"Afvis anmodning\",\n  \"components.RequestBlock.lastmodifiedby\": \"Sidst ændret af\",\n  \"components.RequestBlock.requestdate\": \"Anmodningsdato\",\n  \"components.RequestCard.declinerequest\": \"Afvis anmodning\",\n  \"components.RequestCard.editrequest\": \"Redigér anmodning\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex - Synkronisering af Se senere-liste\",\n  \"components.StatusBadge.managemedia\": \"Administrér {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Åbn i {arr}\",\n  \"components.StatusBadge.playonplex\": \"Afspil i {mediaServerName}\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Noget gik galt under hentning af sæsondata.\",\n  \"components.TvDetails.reportissue\": \"Rapportér et problem\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# episode} other {# episoder}}\",\n  \"components.TvDetails.rtaudiencescore\": \"Rotten Tomatoes-publikumsscore\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.RequestBlock.languageprofile\": \"Sprogprofil\",\n  \"i18n.restartRequired\": \"Genstart påkrævet\",\n  \"components.Discover.emptywatchlist\": \"Medier, der er føjet til din <PlexWatchlistSupportLink>Plex Se senere-liste</PlexWatchlistSupportLink>, vises her.\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB-brugerscore\",\n  \"components.RequestBlock.delete\": \"Slet anmodning\",\n  \"components.RequestBlock.requestedby\": \"Anmodet af\",\n  \"components.RequestCard.approverequest\": \"Godkend anmodning\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Vi kunne ikke finde et match for denne serie.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Anmod om samling i 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Anmod om film\",\n  \"components.RequestModal.requestseries4ktitle\": \"Anmod om serie i 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Anmod om serie\",\n  \"components.TvDetails.seasonnumber\": \"Sæson {seasonNumber}\",\n  \"components.TvDetails.seasonstitle\": \"Sæsoner\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB-brugerscore\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Serieanmodninger\",\n  \"components.PermissionEdit.autorequestDescription\": \"Giv tilladelse til automatisk at indsende anmodninger om ikke-4K-medier via Plex Se senere-liste.\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {afspilning} other {afspilninger}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Anmod automatisk om film på din <PlexWatchlistSupportLink>Plex Se senere-liste</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Auto-anmod om serier\",\n  \"components.Discover.studios\": \"Studier\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB-filmgenre\",\n  \"components.Settings.SettingsMain.apikey\": \"API-nøgle\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Applikationstitel\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Applikations-URL\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Aktivér billedcachelagring\",\n  \"components.Settings.SettingsMain.locale\": \"Brugerfladesprog\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrér indhold efter originalsprog\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Sprog til Udforsk-siden\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Søg efter studier…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Slidernavn\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle}-film\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Slideren kunne ikke slettes.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Slider slettet.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Slå synlighed til/fra\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Fjern\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle}-serier\",\n  \"components.Discover.CreateSlider.needresults\": \"Du skal have mindst ét resultat.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Ingen resultater.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Angiv et TMDB-genre-ID\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Angiv et TMDB-søgeords-ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Angiv TMDB-netværks-ID\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Angiv en søgeforespørgsel\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Angiv TMDB Studio ID\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Søg efter genrer…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Søg efter nøgleord…\",\n  \"components.Discover.CreateSlider.starttyping\": \"Begynd at skrive for at søge.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Du skal angive en titel.\",\n  \"components.Discover.CreateSlider.addSlider\": \"Tilføj slider\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Opret brugerdefineret slider\",\n  \"components.Discover.CreateSlider.addfail\": \"Kunne ikke oprette en ny slider.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Du skal angive en dataværdi.\",\n  \"components.Discover.createnewslider\": \"Opret ny slider\",\n  \"components.Discover.customizediscover\": \"Tilpas Udforsk-siden\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Medier, der er føjet til din <PlexWatchlistSupportLink>Plex Se senere-liste</PlexWatchlistSupportLink>, vises her.\",\n  \"components.Discover.resetwarning\": \"Nulstil alle skydere til standard. Dette vil også slette alle brugerdefinerede sliders!\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Lagr eksternt hentede billeder i cache (anvender en betydelig mængde diskplads)\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Generelle indstillinger\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Ny API-nøgle genereret!\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Noget gik galt under lagring af indstillingerne.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Indstillinger gemt!\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Sæson {seasonNumber} Episode {episodeNumber}\",\n  \"components.RequestCard.unknowntitle\": \"Ukendt titel\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Ukendt titel\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Oprettede en ny slider og gemte indstillinger for tilpasning af Udforsk.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Rediger slider\",\n  \"components.Discover.CreateSlider.editfail\": \"Kunne ikke redigere slideren.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Redigerede slider og gemte indstillinger for tilpasning af Udforsk.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Din Se senere-liste\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Senest tilføjede\",\n  \"components.Discover.moviegenres\": \"Filmgenrer\",\n  \"components.Discover.networks\": \"Tjenester/netværk\",\n  \"components.Discover.resetfailed\": \"Noget gik galt under nulstilling af tilpasningsindstillingerne for Udforsk.\",\n  \"components.Discover.resetsuccess\": \"Indstillinger for tilpasning af Udforsk-siden er nulstillet.\",\n  \"components.Discover.resettodefault\": \"Nulstil til standard\",\n  \"components.Discover.stopediting\": \"Stop redigering\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB-filmnøgleord\",\n  \"components.Discover.tmdbnetwork\": \"TMDB-netværk\",\n  \"components.Discover.tmdbsearch\": \"TMDB-søgning\",\n  \"components.Discover.tmdbstudio\": \"TMDB-studie\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB-seriegenre\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB-serienøgleord\",\n  \"components.Discover.tvgenres\": \"Seriegenrer\",\n  \"components.Discover.updatefailed\": \"Noget gik galt under opdateringen af tilpasningsindstillingerne for Udforsk.\",\n  \"components.Discover.updatesuccess\": \"Opdaterede indstillinger for tilpasning af Udforsk.\",\n  \"components.Settings.SettingsMain.general\": \"Generelt\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Konfigurér globale og standardindstillinger for Seerr.\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Skjul tilgængelige medier\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Tillad anmodninger om delvise serier\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Noget gik galt under genereringen af en ny API-nøgle.\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Du skal angive en applikationstitel\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Du skal angive en gyldig URL\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL'en må ikke slutte med en efterfølgende skråstreg\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularitet, stigende\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularitet, faldende\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Udgivelsesdato, stigende\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Film\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# aktivt filter} other {# aktive filtre}}\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Udgivelsesdato, faldende\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Titel (A-Å), stigende\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Titel (Å-A), faldende\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB-bedømmelse, stigende\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB-bedømmelse, faldende\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# aktivt filter} other {# aktive filtre}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Serier\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Første udsendelsesdato, stigende\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Første udsendelsesdato, faldende\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Titel (A-Å), stigende\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB-bedømmelse, stigende\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB-bedømmelse, faldende\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# aktivt filter} other {# aktive filtre}}\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Ryd aktive filtre\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtre\",\n  \"components.Discover.FilterSlideover.from\": \"Fra\",\n  \"components.Discover.FilterSlideover.genres\": \"Genrer\",\n  \"components.Discover.FilterSlideover.keywords\": \"Nøgleord\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Originalsprog\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Bedømmelser mellem {minValue} og {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Udgivelsesdato\",\n  \"components.Discover.FilterSlideover.runtime\": \"Spilletid\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minuttes spilletid\",\n  \"components.Discover.FilterSlideover.studio\": \"Studie\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB-brugerscore\",\n  \"components.Layout.Sidebar.browsemovies\": \"Film\",\n  \"components.Layout.Sidebar.browsetv\": \"Serier\",\n  \"components.Selector.nooptions\": \"Ingen resultater.\",\n  \"components.Selector.searchGenres\": \"Vælg genrer…\",\n  \"components.Selector.searchKeywords\": \"Søg efter nøgleord…\",\n  \"components.Selector.starttyping\": \"Begynd at skrive for at søge.\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularitet, faldende\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularitet, stigende\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Titel (Å-A), faldende\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Første udsendelsesdato\",\n  \"components.Selector.searchStudios\": \"Søg efter studier…\",\n  \"components.Discover.FilterSlideover.to\": \"Til\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streamingtjenester\",\n  \"components.Selector.showless\": \"Vis mindre\",\n  \"components.Selector.showmore\": \"Vis mere\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Hvert {jobScheduleSeconds, plural, one {sekund} other {{jobScheduleSeconds} sekunder}}\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB filmstreamingtjenester\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TV-streamingtjenester\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Synkronisering af medietilgængelighed\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB-brugerstemmeantal\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Antal stemmer mellem {minValue} og {maxValue}\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Giv anmodninger tags\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Giv anmodninger tags\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Tilføj automatisk et ekstra tag med anmoderens bruger-ID og visningsnavn\",\n  \"i18n.collection\": \"Samling\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Tilføj automatisk et ekstra tag med anmoderens bruger-ID og visningsnavn\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB-brugerscore – stemmer: {formattedCount}\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Anime-serietype\",\n  \"components.Settings.SonarrModal.seriesType\": \"Serietype\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Enhedsstandard\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Notifikationslyd\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Enhedsstandard\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Notifikationslyd\",\n  \"components.UserList.validationUsername\": \"Du skal angive et brugernavn\",\n  \"components.Login.signinwithjellyfin\": \"Brug din {mediaServerName}-konto\",\n  \"components.Login.username\": \"Brugernavn\",\n  \"components.Login.validationEmailFormat\": \"Ugyldig email\",\n  \"components.Login.validationEmailRequired\": \"Du skal angive en email\",\n  \"components.Login.validationusernamerequired\": \"Brugernavn påkrævet\",\n  \"components.UserList.username\": \"Brugernavn\",\n  \"components.Login.credentialerror\": \"Brugernavnet eller adgangskoden er forkert.\",\n  \"components.Login.initialsigningin\": \"Forbinder…\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"URL-basen skal have en indledende skråstreg\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Vælg en metadataudbyder\",\n  \"i18n.specials\": \"Sær-episoder\",\n  \"components.Settings.Notifications.messageThreadId\": \"Tråd-/emne-ID\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName}-indstillinger gemt!\",\n  \"components.Settings.noSpecialCharacters\": \"Konfigurationen skal være en kommasepareret liste over TMDB-søgeords-id'er og må ikke starte eller slutte med et komma.\",\n  \"components.Settings.saving\": \"Gemmer…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Noget gik galt under deaktivering af web-push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"type\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Ekskludér søgeord\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Kommende serier\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Problembeskrivelse\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Email-adressen er ugyldig.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"En email-adresse er påkrævet.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Der kræves en adgangskode.\",\n  \"components.Login.adminerror\": \"Du skal bruge en administratorkonto for at logge ind.\",\n  \"components.Login.back\": \"Gå tilbage\",\n  \"components.Login.description\": \"Da dette er første gang, du logger ind på {applicationName}, skal du tilføje en gyldig email-adresse.\",\n  \"components.Login.emailtooltip\": \"Adressen behøver ikke at være knyttet til din {mediaServerName}-instans.\",\n  \"components.Login.enablessl\": \"Brug SSL\",\n  \"components.Login.hostname\": \"{mediaServerName}-URL\",\n  \"components.Login.initialsignin\": \"Forbind\",\n  \"components.Login.invalidurlerror\": \"Kunne ikke oprette forbindelse til {mediaServerName}-server.\",\n  \"components.Login.loginwithapp\": \"Log ind med {appName}\",\n  \"components.Login.noadminerror\": \"Ingen administratorbruger fundet på serveren.\",\n  \"components.Login.orsigninwith\": \"Eller log ind med\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.save\": \"Tilføj\",\n  \"components.Login.saving\": \"Tilføjer…\",\n  \"components.Login.servertype\": \"Servertype\",\n  \"components.Login.title\": \"Tilføj email\",\n  \"components.Login.urlBase\": \"URL-base\",\n  \"components.Login.validationPortRequired\": \"Du skal angive et gyldigt portnummer\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"URL-basen må ikke slutte med en efterfølgende skråstreg\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL'en må ikke slutte med en efterfølgende skråstreg\",\n  \"components.Login.validationemailformat\": \"Gyldig email påkrævet\",\n  \"components.Login.validationhostformat\": \"Gyldig URL påkrævet\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName}-URL påkrævet\",\n  \"components.Login.validationservertyperequired\": \"Vælg venligst en servertype\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Dette vil uigenkaldeligt fjerne denne {mediaType} fra {arr}, inklusive alle filer.\",\n  \"components.ManageSlideOver.removearr\": \"Fjern fra {arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"Fjern fra 4K {arr}\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.MovieDetails.downloadstatus\": \"Downloadstatus\",\n  \"components.MovieDetails.openradarr\": \"Åbn film i Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"Åbn film i 4K Radarr\",\n  \"components.MovieDetails.play\": \"Afspil i {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Afspil i 4K i {mediaServerName}\",\n  \"components.MovieDetails.watchlistError\": \"Noget gik galt. Prøv venligst igen.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> tilføjet til Se senere-liste!\",\n  \"components.RequestList.RequestItem.profileName\": \"Profil\",\n  \"components.RequestList.RequestItem.removearr\": \"Fjern fra {arr}\",\n  \"components.RequestList.sortDirection\": \"Skift sorteringsretning\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Kunne ikke indlæse certificeringer\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Ingen tilgængelige muligheder\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Vælg en certificering\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Vælg et land\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Begynd at skrive for at søge.\",\n  \"components.Selector.canceled\": \"Aflyst\",\n  \"components.Selector.ended\": \"Afsluttet\",\n  \"components.Selector.inProduction\": \"I produktion\",\n  \"components.Selector.pilot\": \"Pilot\",\n  \"components.Selector.planned\": \"Planlagt\",\n  \"components.Selector.returningSeries\": \"Tilbagevendende serie\",\n  \"components.Selector.searchUsers\": \"Vælg brugere…\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Prioritet\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Du skal angive et prioritetsnummer\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Aktivér agent\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Integrér plakat\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Ntfy-notifikationsindstillingerne kunne ikke gemmes.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Ntfy-notifikationsindstillinger er gemt!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Adgangskode\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Ntfy-testnotifikationen kunne ikke sendes.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Sender ntfy-testnotifikation…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Ntfy-testnotifikation sendt!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Token-godkendelse\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Emne\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Serverens rod-URL\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Brugernavn\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Brugernavn + adgangskode-godkendelse\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Du skal angive et emne\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Du skal angive en gyldig URL\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Du skal vælge mindst én notifikationstype\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Integrér plakat\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Integrér plakat\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Understøttede URL-variabler\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Tilgængelige variabler er dokumenteret i afsnittet om webhook-skabelonvariabler\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"URL'en for testnotifikation er indstillet til {testUrl} i stedet for den faktiske webhook-URL.\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Integrér plakat\",\n  \"components.Settings.Notifications.embedPoster\": \"Integrér plakat\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Kræv brugerens email\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"Tråd-/emne-ID'et skal være et positivt heltal\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Du skal angive et gyldigt Discord-rolle-ID\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Hvis din gruppechat har emner aktiveret, kan du angive et tråd-/emne-ID her\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Meddelelsesrolle-ID\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"Rolle-ID'et, der skal nævnes i webhook-beskeden. Lad feltet stå tomt for at deaktivere omtaler\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Betingelser\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Angiver betingelser før parameterændringer anvendes. Hvert felt skal valideres, for at reglerne kan anvendes (OG-operationen). Et felt betragtes som verificeret, hvis nogen af dets egenskaber matcher (ELLER-operation).\",\n  \"components.Settings.OverrideRuleModal.create\": \"Opret regel\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Ny tilsidesættelsesregel\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Redigér tilsidesættelsesregel\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Genrer\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Nøgleord\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Ingen tags.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Rodmappe\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Tilsidesættelsesregel er oprettet!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Tilsidesættelsesregel opdateret!\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Vælg kvalitetsprofil\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Vælg rodmappe\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Vælg tjeneste\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Vælg tags\",\n  \"components.Settings.OverrideRuleModal.service\": \"Tjeneste\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Anvend denne regel på den valgte tjeneste.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Indstillinger\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Angiver hvilke indstillinger der skal ændres, når ovenstående betingelser er opfyldt.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleModal.users\": \"Brugere\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Betingelser\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Genre\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Nøgleord\",\n  \"components.Settings.OverrideRuleTile.language\": \"Sprog\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Rodmappe\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Indstillinger\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleTile.users\": \"Brugere\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNS-cache\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Global DNS-cachestatistik\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Disse statistikker aggregeres på tværs af alle DNS-cacheposter.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Aktiv adresse\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Alder\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"{hostname}-dns-cache tømt.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Træffere\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Missere\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Værtsnavn\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Hver {jobScheduleDays}. dag\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Fejl\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Tøm DNS-cache\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Træfferate\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Træffere\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4-reserver\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Missere\",\n  \"components.Settings.SettingsJobsCache.size\": \"Størrelse\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Brugernes avatarer\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"API-nøgle kopieret til udklipsholder.\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filtrér indhold efter regional tilgængelighed\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex - Opdatér token\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Tillad anmodninger om særlige episoder\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Skjul tilgængelige medier fra Udforsk-siderne, men ikke fra søgeresultaterne\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Streamingregion\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Vis streamingsider efter regional tilgængelighed\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Du skal angive en gyldig URL\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URL'en må ikke slutte med en efterfølgende skråstreg\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube-URL\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"Basis-URL til YouTube-videoer, hvis en selvhostet YouTube-instans bruges.\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Aktivér CSRF-beskyttelse\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"Aktiver IKKE denne indstilling, medmindre du forstår, hvad du laver!\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Indstil ekstern API-adgang til skrivebeskyttet (kræver HTTPS)\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNS-cache\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"DNS-cache Maksimal TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"Minimum TTL for DNS-cache\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"Aktivér IKKE dette, hvis du oplever problemer med DNS-opslag\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Aktivér caching af DNS-opslag for at optimere ydeevnen og undgå unødvendige API-kald\",\n  \"components.Settings.SettingsNetwork.docs\": \"dokumentationen\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Tving IPv4-løsning først\",\n  \"components.Settings.SettingsNetwork.network\": \"Netværk\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Netværksparametre fra din container/system bør bruges i stedet for disse indstillinger. Se {docs} for mere information.\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Netværksindstillinger\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Proxy-ignorerede adresser\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Brug ',' som separator og '*.' som jokertegn for underdomæner\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Omgå proxy for lokale adresser\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Proxy-adgangskode\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Proxyport\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Brug SSL til proxy\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Proxy-brugernavn\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Noget gik galt under lagring af indstillingerne.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Indstillinger gemt!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Aktivér proxy-understøttelse\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Du skal angive en gyldig port\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Mindst én godkendelsesmetode skal vælges.\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Loginmetoder\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Konfigurer loginmetoder for brugere.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Aktivér {mediaServerName}-login\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Tillad brugere at logge ind med deres {mediaServerName}-konto\",\n  \"components.Settings.addrule\": \"Ny tilsidesættelsesregel\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Alle valgte metadataudbydere er operationelle\",\n  \"components.Settings.animeMetadataProvider\": \"Udbyder af anime-metadata\",\n  \"components.Settings.chooseProvider\": \"Vælg metadataudbydere til forskellige indholdstyper\",\n  \"components.Settings.clickTest\": \"Klik på knappen \\\"Test\\\" for at kontrollere forbindelsen med metadataudbydere\",\n  \"components.Settings.connectionTestFailed\": \"Forbindelsestest mislykkedes\",\n  \"components.Settings.failed\": \"Virker ikke\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Kunne ikke gemme indstillinger for metadataudbyder\",\n  \"components.Settings.general\": \"Generelt\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} er ikke et TMDB-nøgleord.\",\n  \"components.Settings.invalidurlerror\": \"Kunne ikke oprette forbindelse til {mediaServerName}-server.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Glemt adgangskode-URL\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName}-indstillinger\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Konfigurér eventuelt de interne og eksterne slutpunkter for din {mediaServerName}-server. I de fleste tilfælde er den eksterne URL forskellig fra den interne URL. En brugerdefineret URL til nulstilling af adgangskode kan også indstilles for {mediaServerName}-login, hvis du ønsker at omdirigere til en anden side til nulstilling af adgangskode. Du kan også ændre Jellyfin API-nøglen, som blev genereret automatisk tidligere.\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Noget gik galt under lagringen {mediaServerName}-indstillinger.\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Brugerdefineret godkendelse med automatisk biblioteksgruppering understøttes ikke\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Noget gik galt under synkronisering af biblioteker\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Der blev ikke fundet nogen biblioteker\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName}-biblioteker\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"Bibliotekerne {mediaServerName} scanner efter titler. Klik på knappen nedenfor, hvis der ikke er angivet nogen biblioteker.\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName}-indstillinger\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Konfigurer indstillingerne for din {mediaServerName}-server. {mediaServerName} scanner dine {mediaServerName}-biblioteker for at se, hvilket indhold der er tilgængeligt.\",\n  \"components.Settings.manualscanJellyfin\": \"Manuel biblioteksscanning\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.menuMetadataProviders\": \"Metadataudbydere\",\n  \"components.Settings.menuNetwork\": \"Netværk\",\n  \"components.Settings.metadataProviderSelection\": \"Valg af metadataudbyder\",\n  \"components.Settings.metadataProviderSettings\": \"Metadataudbydere\",\n  \"components.Settings.metadataSettings\": \"Indstillinger for metadataudbyder\",\n  \"components.Settings.metadataSettingsSaved\": \"Indstillinger for metadataudbyder gemt\",\n  \"components.Settings.no\": \"Ingen\",\n  \"components.Settings.nooptions\": \"Ingen resultater.\",\n  \"components.Settings.notTested\": \"Ikke testet\",\n  \"components.Settings.operational\": \"Operationel\",\n  \"components.Settings.overrideRules\": \"Tilsidesættelsesregler\",\n  \"components.Settings.overrideRulesDescription\": \"Tilsidesættelsesregler giver dig mulighed for at angive egenskaber, der skal erstattes, hvis en anmodning matcher reglen.\",\n  \"components.Settings.providerStatus\": \"Status for metadataudbyder\",\n  \"components.Settings.scanbackground\": \"Scanningen vil køre i baggrunden. Du kan fortsætte opsætningsprocessen i mellemtiden.\",\n  \"components.Settings.searchKeywords\": \"Søg efter nøgleord…\",\n  \"components.Settings.seriesMetadataProvider\": \"Udbyder af seriemetadata\",\n  \"components.Settings.settings\": \"Indstillinger\",\n  \"components.Settings.starttyping\": \"Begynd at skrive for at søge.\",\n  \"components.Settings.syncJellyfin\": \"Synkronisér biblioteker\",\n  \"components.Settings.syncing\": \"Synkronisering\",\n  \"components.Settings.timeout\": \"Timeout\",\n  \"components.Settings.tip\": \"Tip\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"TMDB-udbyderen virker ikke, vælg venligst en anden metadataudbyder\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"TVDB-udbyderen virker ikke, vælg venligst en anden metadataudbyder\",\n  \"components.Settings.valueRequired\": \"Du skal angive en værdi.\",\n  \"components.Settings.yes\": \"Ja\",\n  \"components.Setup.back\": \"Gå tilbage\",\n  \"components.Setup.configemby\": \"Konfigurér Emby\",\n  \"components.Setup.configjellyfin\": \"Konfigurér Jellyfin\",\n  \"components.Setup.configplex\": \"Konfigurér Plex\",\n  \"components.Setup.configuremediaserver\": \"Konfigurér medieserver\",\n  \"components.Setup.librarieserror\": \"Validering mislykkedes. Slå venligst bibliotekerne til/fra igen for at fortsætte.\",\n  \"components.Setup.servertype\": \"Vælg servertype\",\n  \"components.Setup.signin\": \"Log ind\",\n  \"components.Setup.signinWithEmby\": \"Indtast dine Emby-oplysninger\",\n  \"components.Setup.signinWithJellyfin\": \"Indtast dine Jellyfin-oplysninger\",\n  \"components.Setup.signinWithPlex\": \"Indtast dine Plex-oplysninger\",\n  \"components.Setup.subtitle\": \"Kom i gang ved at vælge din medieserver\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.TitleCard.watchlistError\": \"Noget gik galt. Prøv venligst igen.\",\n  \"components.TvDetails.play\": \"Afspil i {mediaServerName}\",\n  \"components.TvDetails.play4k\": \"Afspil i 4K i {mediaServerName}\",\n  \"components.TvDetails.watchlistError\": \"Noget gik galt. Prøv venligst igen.\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {bruger} other {brugere}} importeret.\",\n  \"components.TvDetails.addtowatchlist\": \"Føj til Se senere-liste\",\n  \"components.UserList.importfromJellyfin\": \"Importér {mediaServerName}-brugere\",\n  \"components.UserList.importfromJellyfinerror\": \"Noget gik galt under importen af {mediaServerName}-brugere.\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName}-bruger\",\n  \"components.UserList.newJellyfinsigninenabled\": \"<strong>Aktivér nyt {mediaServerName}-login</strong>-indstillingen er i øjeblikket aktiveret. {mediaServerName}-brugere med biblioteksadgang behøver ikke at være importeret for at logge ind.\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Der er ingen {mediaServerName}-brugere at importere.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Indtast dine {mediaServerName}-loginoplysninger for at forbinde din konto til {applicationName}.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Denne konto er allerede knyttet til en {applicationName}-bruger\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Kan ikke oprette forbindelse til {mediaServerName} ved hjælp af dine loginoplysninger\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Der opstod en ukendt fejl\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Adgangskode\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Du skal angive en adgangskode\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Forbind\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Tilføjer…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Forbind {mediaServerName}-konto\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Brugernavn\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Du skal angive et brugernavn\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Filtrér indhold efter regional tilgængelighed\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName}-bruger\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Gem ændringer\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Gemmer…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Streamingregion\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Vis streamingsider efter regional tilgængelighed\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Denne email er allerede taget!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"En anden bruger har allerede dette brugernavn. Du skal indstille en email\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Gyldig email påkrævet\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Email påkrævet\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Den tilknyttede konto kunne ikke slettes.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Der opstod en ukendt fejl\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Tilknyttede konti\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Disse eksterne konti er knyttet til din {applicationName}-konto.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Du har ingen eksterne konti knyttet til din konto.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Du har ikke tilladelse til at ændre denne brugers tilknyttede konti.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Denne konto er allerede knyttet til en Plex-bruger\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Kan ikke oprette forbindelse til Plex ved hjælp af dine loginoplysninger\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Browser\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Oprettet\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Slet abonnement\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Enhed\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Deaktiver web-push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Aktivér web-push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Noget gik galt under aktivering af web-push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Engine\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Administrér enheder\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Du har ingen web-push-abonnementer at vise.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Operativsystem\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Abonnement slettet.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Noget gik galt under sletning af brugerabonnementet.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Ukendt\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Web-push er blevet deaktiveret.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Web-push er blevet aktiveret.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Indstillinger for web-push-notifikationer kunne ikke gemmes.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Indstillinger for web-push-notifikationer er gemt!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Tråd-/emne-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"Tråd-/emne-ID'et skal være et positivt heltal\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Tilknyttede konti\",\n  \"i18n.completed\": \"Færdiggjort\",\n  \"i18n.deleted\": \"Slettet\",\n  \"components.UserProfile.localWatchlist\": \"{username}s Se senere-liste\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Hvis din gruppechat har emner aktiveret, kan du angive et tråd-/emne-ID her\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Jellyfin - Senest tilføjet-scanning\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Jellyfin - Fuld biblioteksscanning\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Tving Seerr til at løse IPv4-adresser først i stedet for IPv6\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Maksimal bedømmelse\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr cacher DNS-opslag for at optimere ydeevnen og undgå unødvendige API-kald.\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Konfigurér netværksindstillinger for din Seerr-instans.\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Tillad Seerr at registrere klient-IP-adresser korrekt bag en proxy\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalt vil dette kun blive kørt én gang i døgnet. Seerr vil tjekke din {mediaServerName}-server for senest tilføjede mere aggressivt. Hvis dette er første gang, du konfigurerer Seerr, anbefales en engangs fuld manuel biblioteksscanning!\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Region til Udforsk-siden\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Region til Udforsk-siden\",\n  \"components.Discover.FilterSlideover.certification\": \"Indholdsbedømmelse\",\n  \"components.Selector.CertificationSelector.minRating\": \"Minimumsbedømmelse\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> fjernet fra Se senere-liste!\",\n  \"components.MovieDetails.removefromwatchlist\": \"Fjern fra Se senere-liste\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> fjernet fra Se senere-liste!\",\n  \"components.TitleCard.addToWatchList\": \"Føj til Se senere-liste\",\n  \"components.TitleCard.watchlistCancel\": \"Se senere-liste for <strong>{title}</strong> annulleret.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> føjet til Se senere-liste!\",\n  \"components.MovieDetails.addtowatchlist\": \"Føj til Se senere-liste\",\n  \"components.TvDetails.removefromwatchlist\": \"Fjern fra Se senere-liste\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> fjernet fra Se senere-liste!\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> tilføjet til Se senere-liste!\",\n  \"components.Settings.apiKey\": \"API-nøgle\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Sprog\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S)-proxy\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Proxy-værtsnavn\",\n  \"components.Settings.save\": \"Gem ændringer\",\n  \"components.Selector.searchStatus\": \"Vælg status...\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Om Seer\",\n  \"components.Settings.SettingsAbout.contribute\": \"Giv et bidrag\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Støt Seerr\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Du skal angive en gyldig maksimum-TLL\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Du skal angive en gyldig minimum-TLL\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Aktivt abonnement\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Kunne ikke forbinde til {services}. Nogle informationer kan være utilgængelige.\",\n  \"components.RequestList.unableToConnect\": \"Kunne ikke forbinde til {services}. Nogle informationer kan være utilgængelige.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Ingen DNS-opslag er blevet cachet endnu.\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Send ALLE udgående HTTP-/HTTPS-forespørgsler gennem en proxyserver (vært/port). Aktiverer IKKE HTTPS, SSL eller certifikatkonfiguration.\",\n  \"component.BlocklistBlock.blocklistdate\": \"Skjult dato\",\n  \"component.BlocklistBlock.blocklistedby\": \"Skjult af\",\n  \"component.BlocklistModal.blocklisting\": \"Skjul\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> er ikke skjult.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Administrere skjulte medier.\",\n  \"components.Blocklist.blocklistdate\": \"dato\",\n  \"components.Blocklist.blocklistedby\": \"{date} af {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Skjulningsindstillinger\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Skjulnings-tags\",\n  \"components.Blocklist.filterManual\": \"Manuel\",\n  \"components.Blocklist.mediaName\": \"Navn\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb-ID\",\n  \"components.Blocklist.mediaType\": \"Type\",\n  \"components.Blocklist.showAllBlocklisted\": \"Vis alle skjulte medier\",\n  \"components.Layout.Sidebar.blocklist\": \"Skjulning\",\n  \"components.PermissionEdit.blocklistedItems\": \"Skjule medier.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Giv adgang til at skjule medier.\",\n  \"components.PermissionEdit.manageblocklist\": \"Administrere skjulningsliste\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Giv adgang til at administrere skjulte medier.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Se skjulte medier.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Giv adgang til at se skjulte medier.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Behandl skjulnings-tags\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Skjul indhold med tags\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Begræns indhold der skjules pr. tag\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"Jobbet “Behandl skjulnings-tags” vil skjule dette antal sider i hver sortering. Større tal giver en mere præcis skjulning, men bruger mere lagerplads.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Tilføj automatisk indhold med bestemte tags til skjulningslisten via jobbet “Behandl skjulnings-tags”\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Skjul elementer\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Skjul elementer der fremgår på skjulningslisten fra Udforsk-siderne for alle brugere med \\\"Administrere skjulning\\\"-tilladelsen\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Indsæt konfigurationen for skjulnings-tags herunder.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Importér konfiguration for skjulnings-tags\",\n  \"components.Settings.blocklistedTagsText\": \"Skjulnings-tags\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Er du sikker på, at du vil rydde alle skjulnings-tags?\",\n  \"components.Settings.copyBlocklistedTags\": \"Skjulnings-tags blev kopieret til Udklipsholder.\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Intet at kopiere\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Kopiér konfiguration for skjulnings-tags\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Importér konfiguration for skjulnings-tags\",\n  \"i18n.addToBlocklist\": \"Skjul\",\n  \"i18n.blocklist\": \"Skjulning\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> er allerede blevet skjult.\",\n  \"i18n.blocklistError\": \"Noget gik galt. Prøv venligst igen.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> blev skjult.\",\n  \"i18n.blocklisted\": \"Skjult\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> blev fjernet fra skjulningslisten.\",\n  \"i18n.removefromBlocklist\": \"Fjern fra skjulningslisten\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"Timeout for API-anmodning\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Maksimal tid (i sekunder) at vente på svar fra eksterne tjenester som Radarr/Sonarr. Sæt til 0 for ingen timeout.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Du skal angive en gyldig timeout-værdi\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Overvåg nye sæsoner\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Prioritet\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"Angiv en prioritet mellem 1 og 5\",\n  \"components.Discover.timeWindowDay\": \"Dagligt\",\n  \"components.Discover.timeWindowWeek\": \"Ugentligt\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Brugerdefinerede headers\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Tilføj header\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Du kan ikke bruge både Authorization-headeren og en brugerdefineret Authorization-header. Fjern venligst den ene.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Alle headers skal have både navn og værdi\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Header-navn\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Fjern\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Tilføj brugerdefinerede HTTP-headers, som skal inkluderes i webhook-anmodninger\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Header-værdi\"\n}\n"
  },
  {
    "path": "src/i18n/locale/de.json",
    "content": "{\n  \"components.AirDateBadge.airedrelative\": \"Ausgestrahlt {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Ausstrahlung {relativeTime}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Die <code>{appDataPath}</code> Volume Einbindung wurde nicht korrekt konfiguriert. Alle Daten werden gelöscht, wenn dieser Container gestoppt oder neugestartet wird.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Filme\",\n  \"components.CollectionDetails.overview\": \"Übersicht\",\n  \"components.CollectionDetails.requestcollection\": \"Sammlung anfragen\",\n  \"components.CollectionDetails.requestcollection4k\": \"Sammlung in 4K anfragen\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre}-Filme\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Filme auf {language}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network}-Serien\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio}-Filme\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre}-Serien\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Serien auf {language}\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Deine Merkliste\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex Merkliste\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Film-Genres\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Film-Genres\",\n  \"components.Discover.NetworkSlider.networks\": \"Sender\",\n  \"components.Discover.StudioSlider.studios\": \"Filmstudios\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Serien-Genres\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Serien-Genres\",\n  \"components.Discover.discover\": \"Entdecken\",\n  \"components.Discover.emptywatchlist\": \"Hier erscheinen deine zur <PlexWatchlistSupportLink>Plex Merkliste</PlexWatchlistSupportLink> hinzugefügten Medien.\",\n  \"components.Discover.plexwatchlist\": \"Deine Merkliste\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Kürzlich hinzugefügt\",\n  \"components.Discover.popularmovies\": \"Beliebte Filme\",\n  \"components.Discover.populartv\": \"Beliebte Serien\",\n  \"components.Discover.recentlyAdded\": \"Kürzlich hinzugefügt\",\n  \"components.Discover.recentrequests\": \"Letzte Anfragen\",\n  \"components.Discover.trending\": \"Im Trend\",\n  \"components.Discover.upcoming\": \"Demnächst erscheinende Filme\",\n  \"components.Discover.upcomingmovies\": \"Demnächst erscheinende Filme\",\n  \"components.Discover.upcomingtv\": \"Demnächst erscheinende Serien\",\n  \"components.DownloadBlock.estimatedtime\": \"Geschätzt {time}\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Staffel {seasonNumber} Folge {episodeNumber}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Soll dieser Kommentar wirklich gelöscht werden?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Kommentar löschen\",\n  \"components.IssueDetails.IssueComment.edit\": \"Kommentar bearbeiten\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Verfasst {relativeTime} von {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Verfasst {relativeTime} von {username} (Bearbeitet)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Du musst eine Nachricht eingeben\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Problem löschen\",\n  \"components.IssueDetails.IssueDescription.description\": \"Beschreibung\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Beschreibung bearbeiten\",\n  \"components.IssueDetails.allepisodes\": \"Alle Folgen\",\n  \"components.IssueDetails.allseasons\": \"Alle Staffeln\",\n  \"components.IssueDetails.closeissue\": \"Problem schließen\",\n  \"components.IssueDetails.closeissueandcomment\": \"Schließen mit Kommentar\",\n  \"components.IssueDetails.commentplaceholder\": \"Kommentar hinzufügen…\",\n  \"components.IssueDetails.comments\": \"Kommentare\",\n  \"components.IssueDetails.deleteissue\": \"Problem löschen\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Soll dieses Problem wirklich gelöscht werden?\",\n  \"components.IssueDetails.episode\": \"Folge {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Problem\",\n  \"components.IssueDetails.issuetype\": \"Art\",\n  \"components.IssueDetails.lastupdated\": \"Letzte Änderung\",\n  \"components.IssueDetails.leavecomment\": \"Kommentar\",\n  \"components.IssueDetails.nocomments\": \"Es gibt keine Kommentare.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} geöffnet {relativeTime} von {username}\",\n  \"components.IssueDetails.openin4karr\": \"In {arr} 4K öffnen\",\n  \"components.IssueDetails.openinarr\": \"In {arr} öffnen\",\n  \"components.IssueDetails.play4konplex\": \"Auf {mediaServerName} in 4K abspielen\",\n  \"components.IssueDetails.playonplex\": \"Auf {mediaServerName} abspielen\",\n  \"components.IssueDetails.problemepisode\": \"Betroffene Folge\",\n  \"components.IssueDetails.problemseason\": \"Betroffene Staffel\",\n  \"components.IssueDetails.reopenissue\": \"Problem erneut öffnen\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Mit Kommentar wieder öffnen\",\n  \"components.IssueDetails.season\": \"Staffel {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Beim Bearbeiten der Problembeschreibung ist ein Fehler aufgetreten.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Problembeschreibung erfolgreich bearbeitet!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Problem erfolgreich gelöscht!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Beim Löschen des Problems ist ein Fehler aufgetreten.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Status des Problems erfolgreich aktualisiert!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Beim Aktualisieren des Status des Problems ist ein Fehler aufgetreten.\",\n  \"components.IssueDetails.unknownissuetype\": \"Unbekannt\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Folge} other {Folgen}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Status\",\n  \"components.IssueList.IssueItem.issuetype\": \"Typ\",\n  \"components.IssueList.IssueItem.opened\": \"Geöffnet\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} von {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Betroffene Folge\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Staffel} other {Staffeln}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Unbekannt\",\n  \"components.IssueList.IssueItem.viewissue\": \"Problem anzeigen\",\n  \"components.IssueList.issues\": \"Probleme\",\n  \"components.IssueList.showallissues\": \"Alle Probleme anzeigen\",\n  \"components.IssueList.sortAdded\": \"Neueste\",\n  \"components.IssueList.sortModified\": \"Zuletzt geändert\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Alle Folgen\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Alle Staffeln\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Folge {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extras\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Betroffene Folge\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Betroffene Staffel\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Gib eine detaillierte Erklärung des Problems an.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Ein Problem melden\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Staffel {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Problem melden\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Beim Senden des Problems ist ein Fehler aufgetreten.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Problembericht für <strong>{title}</strong> erfolgreich übermittelt!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Problem ansehen\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Du musst eine Beschreibung eingeben\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Was ist das Problem?\",\n  \"components.IssueModal.issueAudio\": \"Ton\",\n  \"components.IssueModal.issueOther\": \"Sonstige\",\n  \"components.IssueModal.issueSubtitles\": \"Untertitel\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.LanguageSelector.languageServerDefault\": \"Standard ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Alle Sprachen\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Anzeigesprache\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Nach Filmen & Serien suchen\",\n  \"components.Layout.Sidebar.dashboard\": \"Entdecken\",\n  \"components.Layout.Sidebar.issues\": \"Probleme\",\n  \"components.Layout.Sidebar.requests\": \"Anfragen\",\n  \"components.Layout.Sidebar.settings\": \"Einstellungen\",\n  \"components.Layout.Sidebar.users\": \"Benutzer\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Filmanfragen\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Serienanfragen\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Layout.UserDropdown.requests\": \"Anfragen\",\n  \"components.Layout.UserDropdown.settings\": \"Einstellungen\",\n  \"components.Layout.UserDropdown.signout\": \"Abmelden\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {Version} other {Versionen}} hinterher\",\n  \"components.Layout.VersionStatus.outofdate\": \"Veraltet\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr (Entwicklung)\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr (Stabil)\",\n  \"components.Login.email\": \"E-Mail-Adresse\",\n  \"components.Login.forgotpassword\": \"Passwort vergessen?\",\n  \"components.Login.loginerror\": \"Beim Anmelden ist etwas schief gelaufen.\",\n  \"components.Login.password\": \"Passwort\",\n  \"components.Login.signin\": \"Anmelden\",\n  \"components.Login.signingin\": \"Anmelden…\",\n  \"components.Login.signinheader\": \"Anmelden, um fortzufahren\",\n  \"components.Login.signinwithoverseerr\": \"Verwende dein {applicationTitle}-Konto\",\n  \"components.Login.signinwithplex\": \"Benutze dein Plex-Konto\",\n  \"components.Login.validationemailrequired\": \"Du musst eine gültige E-Mail Adresse angeben\",\n  \"components.Login.validationpasswordrequired\": \"Du musst ein Passwort angeben\",\n  \"components.ManageSlideOver.alltime\": \"Gesamte Zeit\",\n  \"components.ManageSlideOver.downloadstatus\": \"Downloads\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Erweitert\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Daten löschen\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Dadurch werden alle Daten für diesen {mediaType} unwiderruflich entfernt, einschließlich aller Anfragen. Wenn dieses Element in deiner {mediaServerName}-Bibliothek existiert, werden die Medieninformationen beim nächsten Scan neu erstellt.\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Offene Probleme\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Medien\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K Medien\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Keine Anfragen.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Anfragen\",\n  \"components.ManageSlideOver.manageModalTitle\": \"{mediaType} verwalten\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Als in 4K verfügbar markieren\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Alle Staffeln als in 4K verfügbar markieren\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Alle Staffeln als verfügbar markieren\",\n  \"components.ManageSlideOver.markavailable\": \"Als verfügbar markieren\",\n  \"components.ManageSlideOver.movie\": \"Film\",\n  \"components.ManageSlideOver.openarr\": \"In {arr} öffnen\",\n  \"components.ManageSlideOver.openarr4k\": \"In 4K {arr} öffnen\",\n  \"components.ManageSlideOver.opentautulli\": \"In Tautulli öffnen\",\n  \"components.ManageSlideOver.pastdays\": \"Vergangene {days, number} Tage\",\n  \"components.ManageSlideOver.playedby\": \"Abgespielt von\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {abgespielt} other {abgespielt}}\",\n  \"components.ManageSlideOver.tvshow\": \"Serie\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Mehr anschauen\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Komplette Besetzung\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Komplette Crew\",\n  \"components.MovieDetails.budget\": \"Budget\",\n  \"components.MovieDetails.cast\": \"Besetzung\",\n  \"components.MovieDetails.digitalrelease\": \"Digitale Veröffentlichung\",\n  \"components.MovieDetails.managemovie\": \"Film verwalten\",\n  \"components.MovieDetails.mark4kavailable\": \"4K als verfügbar markieren\",\n  \"components.MovieDetails.markavailable\": \"Als verfügbar markieren\",\n  \"components.MovieDetails.originallanguage\": \"Originalsprache\",\n  \"components.MovieDetails.originaltitle\": \"Originaltitel\",\n  \"components.MovieDetails.overview\": \"Übersicht\",\n  \"components.MovieDetails.overviewunavailable\": \"Übersicht nicht verfügbar.\",\n  \"components.MovieDetails.physicalrelease\": \"Physische Veröffentlichung\",\n  \"components.MovieDetails.productioncountries\": \"Produktions{countryCount, plural, one {land} other {länder}}\",\n  \"components.MovieDetails.recommendations\": \"Empfehlungen\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Erscheinungsdatum} other {Erscheinungsdaten}}\",\n  \"components.MovieDetails.reportissue\": \"Problem melden\",\n  \"components.MovieDetails.revenue\": \"Einnahmen\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes - Nutzerwertung\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes - Tomatometer\",\n  \"components.MovieDetails.runtime\": \"{minutes} Minuten\",\n  \"components.MovieDetails.showless\": \"Weniger anzeigen\",\n  \"components.MovieDetails.showmore\": \"Mehr anzeigen\",\n  \"components.MovieDetails.similar\": \"Ähnliche Titel\",\n  \"components.MovieDetails.streamingproviders\": \"Derzeit verfügbar auf\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studios}}\",\n  \"components.MovieDetails.theatricalrelease\": \"Kinostart\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB - Nutzerwertung\",\n  \"components.MovieDetails.viewfullcrew\": \"Komplette Crew anzeigen\",\n  \"components.MovieDetails.watchtrailer\": \"Trailer ansehen\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Benachrichtigung erhalten, wenn andere Benutzer Kommentare zu Problemen verfassen.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Benachrichtigung erhalten, wenn Probleme von anderen Benutzern wieder geöffnet werden.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Benachrichtigung erhalten, wenn Probleme von anderen Benutzern gelöst werden.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Problem Kommentar\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Benachrichtigung erhalten, wenn Probleme neue Kommentare erhalten.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problem gemeldet\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Benachrichtigung erhalten, wenn Probleme gemeldet werden.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problem wiedereröffnet\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Benachrichtigung erhalten, wenn Probleme wieder geöffnet werden.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problem gelöst\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Benachrichtigung erhalten, wenn Probleme gelöst sind.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Anfrage automatisch genehmigt\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Benachrichtigung erhalten, wenn das angefragte Medium automatisch genehmigt wird.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Anfrage genehmigt\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Benachrichtigung erhalten, wenn angefragte Medien manuell genehmigt wurden.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Anfrage automatisch übermittelt\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Benachrichtigung erhalten, wenn neue Medienanfragen für Objekte auf deiner Merkliste automatisch übermittelt werden.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Anfrage verfügbar\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Benachrichtigung erhalten, wenn angefragte Medien verfügbar werden.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Anfrage abgelehnt\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Benachrichtigung erhalten, wenn Medienanfragen abgelehnt wurden.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Anfrageverarbeitung fehlgeschlagen\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Benachrichtigungen senden, wenn angefragte Medien nicht zu Radarr oder Sonarr hinzugefügt werden konnten.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Genehmigung ausstehend\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Benachrichtigungen senden, wenn neue Medien angefragt wurden und auf Genehmigung warten.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Benachrichtigungstypen\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Benachrichtigung erhalten, wenn dein Problem neue Kommentare erhält.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Benachrichtigung erhalten, wenn andere Benutzer Probleme melden.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Benachrichtigung erhalten, wenn von dir gemeldete Probleme wieder geöffnet werden.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Benachrichtigung erhalten, wenn dein Problem gelöst wurde.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Benachrichtigung erhalten, wenn andere Benutzer neue Medienanfragen stellen, die automatisch genehmigt werden.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Benachrichtigung erhalten, wenn deine Medienanfragen genehmigt werden.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Benachrichtigung erhalten, wenn deine Medienanfragen verfügbar sind.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Benachrichtigung erhalten, wenn deine Medienanfrage abgelehnt wurde.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Benachrichtigung erhalten, wenn die angefragten Medien bei der Hinzufügung zu Radarr oder Sonarr fehlschlagen.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Benachrichtigung erhalten, wenn andere Nutzer ein Medium anfragen, welches eine Genehmigung erfordert.\",\n  \"components.PermissionEdit.admin\": \"Admin\",\n  \"components.PermissionEdit.adminDescription\": \"Voller Administratorzugriff. Umgeht alle anderen Rechteabfragen.\",\n  \"components.PermissionEdit.advancedrequest\": \"Erweiterte Anfragen\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Autorisierung zur Änderung der erweiterten Optionen für Medienanfragen.\",\n  \"components.PermissionEdit.autoapprove\": \"Automatische Genehmigung\",\n  \"components.PermissionEdit.autoapprove4k\": \"Automatische Genehmigung von 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Autorisierung der automatischen Genehmigung für alle 4K-Medienanfragen.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Automatische Genehmigung von 4K Filmen\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Autorisierung der automatischen Genehmigung von Anfragen für 4K-Filme.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Automatische Genehmigung von 4K Serien\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Autorisierung der automatischen Genehmigung von Anfragen für 4K-Serien.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Autorisierung der automatischen Genehmigung von nicht-4K Anfragen.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Automatische Genehmigung von Filmen\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Autorisierung der automatischen Genehmigung von Anfragen für nicht-4K-Filme.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Automatische Genehmigung von Serien\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Autorisierung der automatischen Genehmigung von Anfragen für nicht-4K-Serien.\",\n  \"components.PermissionEdit.autorequest\": \"Automatische Anfrage aus Plex Merkliste\",\n  \"components.PermissionEdit.autorequestDescription\": \"Autorisierung zur automatischen Anfrage von Nicht-4K-Medien über die Plex Merkliste.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Filme automatisch anfragen\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Autorisierung zur automatischen Anfrage von Nicht-4K-Medien über die Plex Merkliste.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Serien automatisch anfragen\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Autorisierung der automatischen Anfrage von Nicht-4K-Serien über die Plex Merkliste.\",\n  \"components.PermissionEdit.createissues\": \"Probleme melden\",\n  \"components.PermissionEdit.createissuesDescription\": \"Autorisierung zur Meldung von Medienproblemen.\",\n  \"components.PermissionEdit.manageissues\": \"Probleme verwalten\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Autorisierung zur Verwaltung von Medienproblemen.\",\n  \"components.PermissionEdit.managerequests\": \"Anfragen verwalten\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Autorisierung zur Verwaltung von Medienanfragen. Alle Anfragen, die von einem Benutzer mit dieser Berechtigung gestellt werden, werden automatisch genehmigt.\",\n  \"components.PermissionEdit.request\": \"Anfragen senden\",\n  \"components.PermissionEdit.request4k\": \"4K anfragen\",\n  \"components.PermissionEdit.request4kDescription\": \"Autorisierung zur Anfrage von Medien in 4K.\",\n  \"components.PermissionEdit.request4kMovies\": \"4K Filme anfragen\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Autorisierung zur Übermittlung von Anfragen für 4K-Filme.\",\n  \"components.PermissionEdit.request4kTv\": \"4K Serien anfragen\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Autorisierung zur Übermittlung von Anfragen für 4K-Serien.\",\n  \"components.PermissionEdit.requestDescription\": \"Autorisierung zur Übermittlung von Anfragen für nicht-4K Medien.\",\n  \"components.PermissionEdit.requestMovies\": \"Filme anfragen\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Autorisierung zur Übermittlung von Anfragen für nicht-4K-Filme.\",\n  \"components.PermissionEdit.requestTv\": \"Serien anfragen\",\n  \"components.PermissionEdit.requestTvDescription\": \"Autorisierung zur Übermittlung von Anfragen für nicht-4K-Serien.\",\n  \"components.PermissionEdit.users\": \"Benutzer verwalten\",\n  \"components.PermissionEdit.usersDescription\": \"Autorisierung zur Benutzerverwaltung erteilen. Benutzer mit dieser Berechtigung können keine Benutzer mit Admin-Recht ändern oder das Admin-Recht gewähren.\",\n  \"components.PermissionEdit.viewissues\": \"Probleme ansehen\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Autorisierung zur Ansicht von Medienproblemen, die von anderen Benutzern gemeldet wurden.\",\n  \"components.PermissionEdit.viewrecent\": \"Kürzlich hinzugefügt anzeigen\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Autorisierung zur Anzeige der Liste der kürzlich hinzugefügten Medien.\",\n  \"components.PermissionEdit.viewrequests\": \"Anfragen anzeigen\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Autorisierung zur Anzeige der von anderen Benutzern eingereichten Medienanfragen.\",\n  \"components.PermissionEdit.viewwatchlists\": \"{mediaServerName} Merklisten anzeigen\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Autorisierung zur Anzeige von {mediaServerName} Merklisten anderer Benutzer.\",\n  \"components.PersonDetails.alsoknownas\": \"Auch bekannt unter: {names}\",\n  \"components.PersonDetails.appearsin\": \"Auftritte\",\n  \"components.PersonDetails.ascharacter\": \"als {character}\",\n  \"components.PersonDetails.birthdate\": \"Geboren am {birthdate}\",\n  \"components.PersonDetails.crewmember\": \"Crew\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {Tag} other {Tage}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} pro {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {Film} other {Filme}}\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {Staffel} other {Staffeln}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} pro {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.unlimited\": \"Unbegrenzt\",\n  \"components.RegionSelector.regionDefault\": \"Alle Regionen\",\n  \"components.RegionSelector.regionServerDefault\": \"Standard ({region})\",\n  \"components.RequestBlock.approve\": \"Anfrage genehmigen\",\n  \"components.RequestBlock.decline\": \"Anfrage ablehnen\",\n  \"components.RequestBlock.delete\": \"Anfrage löschen\",\n  \"components.RequestBlock.edit\": \"Anfrage bearbeiten\",\n  \"components.RequestBlock.languageprofile\": \"Sprachprofil\",\n  \"components.RequestBlock.lastmodifiedby\": \"Zuletzt geändert von\",\n  \"components.RequestBlock.profilechanged\": \"Qualitätsprofil\",\n  \"components.RequestBlock.requestdate\": \"Anfragedatum\",\n  \"components.RequestBlock.requestedby\": \"Angefragt von\",\n  \"components.RequestBlock.requestoverrides\": \"Anfrage Überschreibungen\",\n  \"components.RequestBlock.rootfolder\": \"Stammordner\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Staffel} other {Staffeln}}\",\n  \"components.RequestBlock.server\": \"Zielserver\",\n  \"components.RequestButton.approve4krequests\": \"Genehmige {requestCount, plural, one {4K Anfrage} other {{requestCount} 4K Anfragen}}\",\n  \"components.RequestButton.approverequest\": \"Anfrage genehmigen\",\n  \"components.RequestButton.approverequest4k\": \"4K Anfrage genehmigen\",\n  \"components.RequestButton.approverequests\": \"Genehmige {requestCount, plural, one {Anfrage} other {{requestCount} Anfragen}}\",\n  \"components.RequestButton.decline4krequests\": \"Lehne {requestCount, plural, one {4K Anfrage} other {{requestCount} 4K Anfragen}} ab\",\n  \"components.RequestButton.declinerequest\": \"Anfrage ablehnen\",\n  \"components.RequestButton.declinerequest4k\": \"4K Anfrage ablehnen\",\n  \"components.RequestButton.declinerequests\": \"Lehne {requestCount, plural, one {Anfrage} other {{requestCount} Anfragen}} ab\",\n  \"components.RequestButton.requestmore\": \"Mehr anfragen\",\n  \"components.RequestButton.requestmore4k\": \"Mehr in 4K anfragen\",\n  \"components.RequestButton.viewrequest\": \"Anfrage anzeigen\",\n  \"components.RequestButton.viewrequest4k\": \"4K Anfrage anzeigen\",\n  \"components.RequestCard.approverequest\": \"Anfrage genehmigen\",\n  \"components.RequestCard.cancelrequest\": \"Anfrage abbrechen\",\n  \"components.RequestCard.declinerequest\": \"Anfrage ablehnen\",\n  \"components.RequestCard.deleterequest\": \"Anfrage löschen\",\n  \"components.RequestCard.editrequest\": \"Anfrage bearbeiten\",\n  \"components.RequestCard.failedretry\": \"Beim erneuten Versuch die Anfrage zu senden ist ein Fehler aufgetreten.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} wurde nicht gefunden\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Staffel} other {Staffeln}}\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB-ID\",\n  \"components.RequestCard.unknowntitle\": \"Unbekannter Titel\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Anfrage abbrechen\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Anfrage löschen\",\n  \"components.RequestList.RequestItem.editrequest\": \"Anfrage bearbeiten\",\n  \"components.RequestList.RequestItem.failedretry\": \"Beim Wiederholen der Anfrage ist etwas schief gelaufen.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} wurde nicht gefunden\",\n  \"components.RequestList.RequestItem.modified\": \"Geändert\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} von {user}\",\n  \"components.RequestList.RequestItem.requested\": \"Angefragt\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Angefragt\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Staffel} other {Staffeln}}\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB-ID\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Unbekannter Titel\",\n  \"components.RequestList.requests\": \"Anfragen\",\n  \"components.RequestList.showallrequests\": \"Alle Anfragen anzeigen\",\n  \"components.RequestList.sortAdded\": \"Zuletzt angefragt\",\n  \"components.RequestList.sortModified\": \"Zuletzt geändert\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Erweiterte Einstellungen\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Diese Serie ist ein Anime.\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Standard)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Zielserver\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Sprachprofil\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Keine Tags.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Qualitätsprofil\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Anfragen als\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Stammordner\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Wähle Tags aus\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Tags\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Du darfst <strong>{limit}</strong> {type} Anfragen alle <strong>{days}</strong> Tage machen.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Dieser Benutzer darf <strong>{limit}</strong> {type} Anfragen alle <strong>{days}</strong> Tage machen.\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"Film\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {Film} other {Filme}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Es sind nicht genügend Staffelanfragen übrig\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Du kannst eine Zusammenfassung deiner Anfragenlimits auf deiner <ProfileLink>Profilseite</ProfileLink> ansehen.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Du kannst eine Zusammenfassung der Anfragenlimits dieses Benutzers auf seiner <ProfileLink>Profilseite</ProfileLink> ansehen.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Keine} other {<strong>#</strong>}} {type} {remaining, plural, one {Anfrage} other {Anfragen}} verbleibend\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Du musst mindestens <strong>{seasons}</strong> {seasons, plural, one {Staffel Anfrage} other {Staffel Anfragen}} verbleibend haben, um eine Anfrage für diese Serie einzureichen.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Dieser Benutzer muss mindestens <strong>{seasons}</strong> {seasons, plural, one {Staffel Anfrage} other {Staffel Anfragen}} verbleibend haben, um eine Anfrage für diese Serie einzureichen.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"Staffel\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {Staffel} other {Staffeln}}\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Wir konnten keine Übereinstimmung für diese Serie finden.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Wir konnten diese Serie nicht automatisch zuordnen. Bitte wähle unten eine korrekte Übereinstimmung aus.\",\n  \"components.RequestModal.alreadyrequested\": \"Bereits Angefragt\",\n  \"components.RequestModal.approve\": \"Anfrage genehmigen\",\n  \"components.RequestModal.autoapproval\": \"Automatische Genehmigung\",\n  \"components.RequestModal.cancel\": \"Anfrage abbrechen\",\n  \"components.RequestModal.edit\": \"Anfrage bearbeiten\",\n  \"components.RequestModal.errorediting\": \"Beim Bearbeiten der Anfrage ist etwas schief gelaufen.\",\n  \"components.RequestModal.numberofepisodes\": \"Anzahl der Folgen\",\n  \"components.RequestModal.pending4krequest\": \"Ausstehende 4K Anfrage\",\n  \"components.RequestModal.pendingapproval\": \"Deine Anfrage steht noch aus.\",\n  \"components.RequestModal.pendingrequest\": \"Ausstehende Anfrage\",\n  \"components.RequestModal.requestApproved\": \"Anfrage für <strong>{title}</strong> genehmigt!\",\n  \"components.RequestModal.requestCancel\": \"Anfrage für <strong>{title}</strong> abgebrochen.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> erfolgreich angefragt!\",\n  \"components.RequestModal.requestadmin\": \"Diese Anfrage wird automatisch genehmigt.\",\n  \"components.RequestModal.requestcancelled\": \"Anfrage für <strong>{title}</strong> abgebrochen.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Sammlung in 4K anfragen\",\n  \"components.RequestModal.requestcollectiontitle\": \"Sammlung anfragen\",\n  \"components.RequestModal.requestedited\": \"Anfrage für <strong>{title}</strong> erfolgreich bearbeitet!\",\n  \"components.RequestModal.requesterror\": \"Beim Senden der Anfrage ist etwas schief gelaufen.\",\n  \"components.RequestModal.requestfrom\": \"Die Anfrage von {username} muss noch genehmigt werden.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Film in 4K anfragen\",\n  \"components.RequestModal.requestmovies\": \"Anfrage {count} {count, plural, one {Film} other {Filme}}\",\n  \"components.RequestModal.requestmovies4k\": \"Anfrage {count} {count, plural, one {Film} other {Filme}} in 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Film anfragen\",\n  \"components.RequestModal.requestseasons\": \"{seasonCount} {seasonCount, plural, one {Staffel} other {Staffeln}} anfragen\",\n  \"components.RequestModal.requestseasons4k\": \"Anfrage {seasonCount} {seasonCount, plural, one {Staffel} other {Staffeln}} in 4K\",\n  \"components.RequestModal.requestseries4ktitle\": \"Serie in 4K anfragen\",\n  \"components.RequestModal.requestseriestitle\": \"Serie anfragen\",\n  \"components.RequestModal.season\": \"Staffel\",\n  \"components.RequestModal.seasonnumber\": \"Staffel {number}\",\n  \"components.RequestModal.selectmovies\": \"Wähle Film(e)\",\n  \"components.RequestModal.selectseason\": \"Staffel(n) Auswählen\",\n  \"components.ResetPassword.confirmpassword\": \"Passwort bestätigen\",\n  \"components.ResetPassword.email\": \"E-Mail-Adresse\",\n  \"components.ResetPassword.emailresetlink\": \"Wiederherstellungs-Link an E-Mail-Adresse senden\",\n  \"components.ResetPassword.gobacklogin\": \"Zurück zur Anmeldeseite\",\n  \"components.ResetPassword.password\": \"Passwort\",\n  \"components.ResetPassword.passwordreset\": \"Passwort zurücksetzen\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Ein Link zum Zurücksetzen des Passworts wird an die angegebene E-Mail Adresse gesendet, wenn sie einem gültigen Benutzer zugeordnet ist.\",\n  \"components.ResetPassword.resetpassword\": \"Passwort zurücksetzen\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Passwort wurde erfolgreich zurückgesetzt!\",\n  \"components.ResetPassword.validationemailrequired\": \"Du musst eine gültige E-Mail Adresse angeben\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Passwörter müssen übereinstimmen\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Das Passwort ist zu kurz, es sollte mindestens 8 Zeichen lang sein\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Du musst ein Passwort angeben\",\n  \"components.Search.search\": \"Suchen\",\n  \"components.Search.searchresults\": \"Suchergebnisse\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Agent aktivieren\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Die Gotify-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify-Testbenachrichtigung konnte nicht gesendet werden.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Versende Gotify-Testbenachrichtigung…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify-Testbenachrichtigung gesendet!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Anwendungs-Token\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Server-URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Es muss ein Anwendungs-Token angegeben werden\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Es muss mindestens eine Benachrichtigungsart ausgewählt werden\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Es muss eine gültige URL angegeben werden\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL darf nicht mit einem abschließenden Schrägstrich enden\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Zugangstoken\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Erstelle ein Token in deinen <PushbulletSettingsLink>Kontoeinstellungen</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Agent aktivieren\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Channel Tag\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbullet-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet Testbenachrichtigung fehlgeschlagen.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Pushbullet Testbenachrichtigung wird gesendet…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet Testbenachrichtigung gesendet!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Du musst ein Zugangstoken angeben\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Es muss mindestens ein Benachrichtigungstyp ausgewählt sein\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Anwendungs API-Token\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registriere eine Anwendung</ApplicationRegistrationLink> , um diese mit Seerr benutzen zu können\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Agent aktivieren\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushover-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover Testbenachrichtigung fehlgeschlagen.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Pushover Testbenachrichtigung wird gesendet…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover Testbenachrichtigung gesendet!\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Benutzer- oder Gruppenschlüssel\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Dein 30-stelliger <UsersGroupsLink>Nutzer oder Gruppen Identifikator</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Du musst ein gültiges Anwendungstoken angeben\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Du musst mindestens einen Benachrichtigungstypen auswählen\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Du musst einen gültigen Benutzer-/Gruppenschlüssel angeben\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Agent aktivieren\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Slack-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack Testbenachrichtigung fehlgeschlagen.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Slack Testbenachrichtigung wird gesendet…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack Testbenachrichtigung gesendet!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Du musst mindestens einen Benachrichtigungstypen auswählen\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Du musst eine gültige URL angeben\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Erstelle eine <WebhookLink>eingehende Webhook</WebhookLink> Integration\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Agent aktivieren\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Seerr muss via HTTPS bereitgestellt werden, um Web-Push Benachrichtigungen empfangen zu können.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Web push Testbenachrichtigung fehlgeschlagen.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Web push Testbenachrichtigung wird gesendet…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Web push Testbenachrichtigung gesendet!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Web push Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Web push Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Dienst aktivieren\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Autorisierungsüberschrift\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON-Inhalt\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Auf Standard zurücksetzen\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON-Inhalt erfolgreich zurückgesetzt!\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Hilfe zu Vorlagenvariablen\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Webhook Testbenachrichtigung konnte nicht gesendet werden.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Webhook Testbenachrichtigung wird gesendet…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook Testbenachrichtigung gesendet!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Du musst einen gültigen JSON-Inhalt angeben\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Du musst mindestens einen Benachrichtigungstypen auswählen\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Du musst eine gültige URL angeben\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Webhook-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Webhook-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.agentenabled\": \"Agent aktivieren\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Selbstsignierte Zertifikate erlauben\",\n  \"components.Settings.Notifications.authPass\": \"SMTP-Passwort\",\n  \"components.Settings.Notifications.authUser\": \"SMTP-Benutzername\",\n  \"components.Settings.Notifications.botAPI\": \"Bot-Autorisierungstoken\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Bot erstellen</CreateBotLink> für die Verwendung mit Seerr\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Bot Avatar URL\",\n  \"components.Settings.Notifications.botUsername\": \"Bot Benutzername\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Benutzern erlauben, einen Chat mit dem Bot zu starten und ihre eigenen Benachrichtigungen zu konfigurieren\",\n  \"components.Settings.Notifications.chatId\": \"Chat-ID\",\n  \"components.Settings.Notifications.chatIdTip\": \"Starte einen Chat mit dem Bot, füge <GetIdBotLink>@get_id_bot</GetIdBotLink> hinzu, und erteile den <code>/my_id</code> Befehl\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discord-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.emailsender\": \"Absenderadresse\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"E-Mail-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"E-Mail-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.enableMentions\": \"Erwähnungen aktivieren\",\n  \"components.Settings.Notifications.encryption\": \"Verschlüsselungsmethode\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Verwende STARTTLS wenn verfügbar\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Benutze implizites TLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"Keine\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"STARTTLS immer verwenden\",\n  \"components.Settings.Notifications.encryptionTip\": \"Im Regelfall verwendet Implicit TLS Port 465 und STARTTLS Port 587\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP Passwort\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Signiere verschlüsselte E-Mail-Nachrichten mit <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP Privater Schlüssel\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Signiere verschlüsselte E-Mail-Nachrichten mit <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.sendSilently\": \"Lautlos senden\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Sende Benachrichtigungen ohne Ton\",\n  \"components.Settings.Notifications.senderName\": \"Absendername\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP-Host\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP-Port\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegram-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord Testbenachrichtigung fehlgeschlagen.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Discord Testbenachrichtigung wird gesendet…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord Testbenachrichtigung gesendet!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"E-Mail Testbenachrichtigung fehlgeschlagen.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"E-Mail Testbenachrichtigung wird gesendet…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"E-Mail Testbenachrichtigung gesendet!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram Testbenachrichtigung fehlgeschlagen.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Telegram Testbenachrichtigung wird gesendet…\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram Testbenachrichtigung gesendet!\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Du musst ein Bot-Autorisierungstoken angeben\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Du musst eine gültige Chat-ID angeben\",\n  \"components.Settings.Notifications.validationEmail\": \"Du musst eine gültige E-Mail-Adresse angeben\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Ein PGP-Passwort muss angegeben werden\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Ein gültiger privater PGP-Schlüssel muss angegeben werden\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Du musst einen gültigen Hostnamen oder IP-Adresse angeben\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Du musst einen gültigen Port angeben\",\n  \"components.Settings.Notifications.validationTypes\": \"Es muss mindestens ein Benachrichtigungstyp ausgewählt werden\",\n  \"components.Settings.Notifications.validationUrl\": \"Du musst eine gültige URL angeben\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Erstelle eine <DiscordWebhookLink>webhook Integration</DiscordWebhookLink> auf dem Server\",\n  \"components.Settings.RadarrModal.add\": \"Server hinzufügen\",\n  \"components.Settings.RadarrModal.announced\": \"Angekündigt\",\n  \"components.Settings.RadarrModal.apiKey\": \"API-Schlüssel\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Basis-URL\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Neuen 4K Radarr Server hinzufügen\",\n  \"components.Settings.RadarrModal.createradarr\": \"Neuen Radarr Server hinzufügen\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Standard 4K Server\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Standardserver\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"4K Radarr Server bearbeiten\",\n  \"components.Settings.RadarrModal.editradarr\": \"Radarr Server bearbeiten\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Automatische Suche aktivieren\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Externe URL\",\n  \"components.Settings.RadarrModal.hostname\": \"Hostname oder IP-Adresse\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Im Kino\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Lade Tags…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Qualitätsprofile werden geladen…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Stammordner werden geladen…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Mindestverfügbarkeit\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Keine Tags.\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Qualitätsprofil\",\n  \"components.Settings.RadarrModal.released\": \"Veröffentlicht\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Stammordner\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Wähle die Mindestverfügbarkeit\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Wähle Qualitätsprofil\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Wähle Stammordner\",\n  \"components.Settings.RadarrModal.selecttags\": \"Tags auswählen\",\n  \"components.Settings.RadarrModal.server4k\": \"4K-Server\",\n  \"components.Settings.RadarrModal.servername\": \"Servername\",\n  \"components.Settings.RadarrModal.ssl\": \"SSL verwenden\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Scannen aktivieren\",\n  \"components.Settings.RadarrModal.tags\": \"Tags\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Teste die Verbindung, um Qualitätsprofile zu laden\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Teste die Verbindung, um Stammordner zu laden\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Teste die Verbindung, um Tags zu laden\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Die Verbindung zu Radarr ist fehlgeschlagen.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr-Verbindung erfolgreich hergestellt!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Du musst einen API-Schlüssel angeben\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Du musst eine gültige URL angeben\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"Die URL darf nicht mit einem abschließenden Schrägstrich enden\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Die URL-Basis muss einen vorangestellten Schrägstrich enthalten\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Die Basis-URL darf nicht mit einem Schrägstrich enden\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Es muss ein gültiger Hostname oder IP-Adresse angegeben werden\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Du musst eine Mindestverfügbarkeit auswählen\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Du musst einen Servernamen angeben\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Du musst einen Port angeben\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Du musst ein Qualitätsprofil auswählen\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Du musst einen Stammordner auswählen\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Aktuell\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Neueste\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Informationen der Version nicht verfügbar.\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Veröffentlichungen\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Änderungsprotokoll {version}\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Änderungsprotokoll anzeigen\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Auf GitHub anzeigen\",\n  \"components.Settings.SettingsAbout.about\": \"Über\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Datenverzeichnis\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentation\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Hilfe erhalten\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub-Diskussionen\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Veraltet\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Es wird der <code>develop</code>-Branch von Seerr verwendet, der nur für Mitwirkende an der Entwicklung oder für Tests der neuesten Funktionen empfohlen wird.\",\n  \"components.Settings.SettingsAbout.timezone\": \"Zeitzone\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Medien insgesamt\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Anfragen insgesamt\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Auf dem neuesten Stand\",\n  \"components.Settings.SettingsAbout.version\": \"Version\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Zur Leistungsoptimierung und um unnötige Anfragen zu minimieren, speichert Seerr Anfragen zwischen.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} Cache geleert.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Cache-Treffer\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Schlüssel insgesamt\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Schlüsselgröße\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Cache-Fehlzugriff\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Cache Name\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Wertgröße\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Aufgabe abbrechen\",\n  \"components.Settings.SettingsJobsCache.command\": \"Befehl\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Download Synchronisierung\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Download Synchronisierung Zurücksetzen\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Job ändern\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Aktuelle Häufigkeit\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Häufigkeit\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Alle {jobScheduleHours, plural, one {Stunde} other {{jobScheduleHours} Stunden}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Alle {jobScheduleMinutes, plural, one {Minute} other {{jobScheduleMinutes} Minuten}}\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Cache leeren\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Bild-Cache-Bereinigung\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Bild-Cache\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Wenn diese Einstellung aktiviert ist, wird Seerr Bilder aus vorkonfigurierten externen Quellen im Proxy-Cache zwischenspeichern. Bilder im Zwischenspeicher werden in deinem Konfigurationsordner gespeichert: <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Bilder im Cache\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Gesamtgröße des Caches\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Scan der zuletzt hinzugefügten Jellyfin Medien\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Vollständiger Jellyfin Bibliotheken Scan\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Beim Speichern des Auftrags ging etwas schief.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Auftrag erfolgreich bearbeitet!\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} abgebrochen.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Aufgabenname\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Aufgaben\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr führt bestimmte Wartungsaufgaben als regulär geplante Aufgaben durch. Diese können allerdings auch manuell ausgeführt werden, ohne dabei den regulären Zeitplan abzuändern.\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Aufgaben und Cache\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} gestartet.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Art\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Nächste Ausführung\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Vollständiger Plex Bibliotheken Scan\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Scan der zuletzt hinzugefügten Plex Medien\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex Merklisten Sync\",\n  \"components.Settings.SettingsJobsCache.process\": \"Prozess\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr Scan\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Jetzt ausführen\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr Scan\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Unbekannte Aufgabe\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Protokollnachricht in die Zwischenablage kopiert.\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"In Zwischenablage kopieren\",\n  \"components.Settings.SettingsLogs.extraData\": \"Zusätzliche Daten\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Debug\",\n  \"components.Settings.SettingsLogs.filterError\": \"Fehler\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Infos\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Warnung\",\n  \"components.Settings.SettingsLogs.label\": \"Bezeichnung\",\n  \"components.Settings.SettingsLogs.level\": \"Schweregrad\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Protokolldetails\",\n  \"components.Settings.SettingsLogs.logs\": \"Protokolle\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Du kannst diese Protokolle auch direkt über <code>stdout</code> oder in <code>{appDataPath}/logs/seerr.log</code> anzeigen.\",\n  \"components.Settings.SettingsLogs.message\": \"Nachricht\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pause\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Fortsetzen\",\n  \"components.Settings.SettingsLogs.showall\": \"Alle Protokolle anzeigen\",\n  \"components.Settings.SettingsLogs.time\": \"Zeitstempel\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Details anzeigen\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Standardberechtigungen\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Initiale Berechtigungen, die neuen Nutzern zugewiesen werden\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Lokale Anmeldung aktivieren\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Nutzer dürfen sich mit ihrer E-Mail-Adresse und Passwort anmelden\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Globales Filmanfragen-Limit\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Neue {mediaServerName}-Anmeldung aktivieren\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Ermöglicht {mediaServerName}-Nutzern die Anmeldung, ohne diese zuerst importieren zu müssen\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Beim Speichern der Einstellungen ist ein Fehler aufgetreten.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Benutzereinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Globales Serienanfragenlimit\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Benutzereinstellungen\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Globale und Standardbenutzereinstellungen konfigurieren.\",\n  \"components.Settings.SettingsUsers.users\": \"Benutzer\",\n  \"components.Settings.SonarrModal.add\": \"Server hinzufügen\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime Tags\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime-Sprachprofil\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Animequalitätsprofil\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Animestammverzeichnis\",\n  \"components.Settings.SonarrModal.apiKey\": \"API-Schlüssel\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Basis-URL\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Neuen 4K Sonarr Server hinzufügen\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Neuen Sonarr-Server hinzufügen\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Standard 4K Server\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Standardserver\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"4K Sonarr Server bearbeiten\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Sonarr Server bearbeiten\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Automatische Suche aktivieren\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Externe URL\",\n  \"components.Settings.SonarrModal.hostname\": \"Hostname oder IP-Adresse\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Sprachprofil\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Lade Tags…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Sprachprofile werden geladen…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Qualitätsprofile werden geladen…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Stammordner werden geladen…\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Keine Tags.\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Qualitätsprofil\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Stammordner\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Staffel Ordner\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Wähle ein Sprachprofil aus\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Wähle Qualitätsprofil\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Wähle Stammordner\",\n  \"components.Settings.SonarrModal.selecttags\": \"Wähle Tags\",\n  \"components.Settings.SonarrModal.server4k\": \"4K-Server\",\n  \"components.Settings.SonarrModal.servername\": \"Servername\",\n  \"components.Settings.SonarrModal.ssl\": \"SSL verwenden\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Scannen aktivieren\",\n  \"components.Settings.SonarrModal.tags\": \"Tags\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Teste die Verbindung zum Laden von Sprachprofilen\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Teste die Verbindung, um Qualitätsprofile zu laden\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Teste die Verbindung, um Stammordner zu laden\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Teste die Verbindung, um Tags zu laden\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Die Verbindung zu Sonarr ist fehlgeschlagen.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr-Verbindung erfolgreich hergestellt!\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Du musst einen API-Schlüssel angeben\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Du musst eine gültige URL angeben\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"Die URL darf nicht mit einem abschließenden Schrägstrich enden\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Die Basis-URL muss einen führenden Schrägstrich haben\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Die Basis-URL darf nicht mit einem abschließenden Schrägstrich enden\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Du musst einen Hostnamen oder IP-Adresse angeben\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Du musst ein Sprachprofil auswählen\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Du musst einen Servernamen angeben\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Du musst einen Port angeben\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Du musst ein Qualitätsprofil auswählen\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Du musst einen Stammordner auswählen\",\n  \"components.Settings.activeProfile\": \"Aktives Profil\",\n  \"components.Settings.addradarr\": \"Radarr Server hinzufügen\",\n  \"components.Settings.address\": \"Adresse\",\n  \"components.Settings.addsonarr\": \"Sonarr Server hinzufügen\",\n  \"components.Settings.advancedTooltip\": \"Bei falscher Konfiguration dieser Einstellung, kann dies zu einer Funktionsstörung führen\",\n  \"components.Settings.cancelscan\": \"Durchsuchung abbrechen\",\n  \"components.Settings.currentlibrary\": \"Aktuelle Bibliothek: {name}\",\n  \"components.Settings.default\": \"Standardmäßig\",\n  \"components.Settings.default4k\": \"Standard-4K\",\n  \"components.Settings.deleteServer\": \"{serverType} Server löschen\",\n  \"components.Settings.deleteserverconfirm\": \"Bist du sicher, dass du diesen Server löschen möchtest?\",\n  \"components.Settings.email\": \"E-Mail\",\n  \"components.Settings.enablessl\": \"SSL verwenden\",\n  \"components.Settings.experimentalTooltip\": \"Die Aktivierung dieser Einstellung kann zu einem unerwarteten Verhalten der Anwendung führen\",\n  \"components.Settings.externalUrl\": \"Externe URL\",\n  \"components.Settings.hostname\": \"Hostname oder IP-Adresse\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.librariesRemaining\": \"Verbleibende Bibliotheken: {count}\",\n  \"components.Settings.manualscan\": \"Manuelle Bibliotheksdurchsuchung\",\n  \"components.Settings.manualscanDescription\": \"Normalerweise wird dies nur einmal alle 24 Stunden ausgeführt. Seerr überprüft die kürzlich hinzugefügten Inhalte deines Plex-Servers aggressiver. Falls du Plex zum ersten Mal konfigurierst, wird empfohlen, einmalig eine manuelle, komplette Bibliotheksdurchsuchung anzustoßen!\",\n  \"components.Settings.mediaTypeMovie\": \"Film\",\n  \"components.Settings.mediaTypeSeries\": \"Serie\",\n  \"components.Settings.menuAbout\": \"Über\",\n  \"components.Settings.menuGeneralSettings\": \"Allgemein\",\n  \"components.Settings.menuJobs\": \"Aufgaben und Cache\",\n  \"components.Settings.menuLogs\": \"Protokolle\",\n  \"components.Settings.menuNotifications\": \"Benachrichtigungen\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Dienste\",\n  \"components.Settings.menuUsers\": \"Benutzer\",\n  \"components.Settings.noDefault4kServer\": \"Ein 4K {serverType} Server muss als Standard markiert werden um Nutzern zu ermöglichen 4K {mediaType} anfragen zu senden.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Wenn du nur einen einzigen {serverType}-Server für Nicht-4K- und 4K-Inhalte hast (oder wenn du nur 4K-Inhalte herunterlädst), solltest du den {serverType}-Server <strong>NICHT</strong> als 4K-Server festlegen.\",\n  \"components.Settings.noDefaultServer\": \"Mindestens ein {serverType}-Server muss als Standard markiert sein, damit {mediaType}-Anfragen verarbeitet werden können.\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Konfiguriere und aktiviere Benachrichtigungsagenten.\",\n  \"components.Settings.notifications\": \"Benachrichtigungen\",\n  \"components.Settings.notificationsettings\": \"Benachrichtigungseinstellungen\",\n  \"components.Settings.notrunning\": \"Nicht aktiv\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.plexlibraries\": \"Plex Bibliotheken\",\n  \"components.Settings.plexlibrariesDescription\": \"Die Bibliotheken, welche Seerr nach Titeln durchsucht. Richte deine Plex Verbindungseinstellungen ein und speichere sie. Sollten keine aufgelistet sein, klicke auf die Schaltfläche weiter unten.\",\n  \"components.Settings.plexsettings\": \"Plex Einstellungen\",\n  \"components.Settings.plexsettingsDescription\": \"Konfiguriere die Einstellungen deines Plex Servers. Seerr durchsucht deine Plex Bibliotheken zur Feststellung der verfügbaren Inhalte.\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.radarrsettings\": \"Radarr Einstellungen\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr muss neu gestartet werden, damit Änderungen angewendet werden können\",\n  \"components.Settings.scan\": \"Bibliotheken synchronisieren\",\n  \"components.Settings.scanning\": \"Synchronisieren…\",\n  \"components.Settings.serverLocal\": \"lokal\",\n  \"components.Settings.serverRemote\": \"entfernt\",\n  \"components.Settings.serverSecure\": \"Sicher\",\n  \"components.Settings.serverpreset\": \"Server\",\n  \"components.Settings.serverpresetLoad\": \"Klicke auf die Schaltfläche, um verfügbare Server zu laden\",\n  \"components.Settings.serverpresetManualMessage\": \"Manuelle Konfiguration\",\n  \"components.Settings.serverpresetRefreshing\": \"Rufe Server ab…\",\n  \"components.Settings.serviceSettingsDescription\": \"Konfiguriere unten deine {serverType}-Server. Du kannst mehrere {serverType}-Server verbinden, aber nur zwei davon können als Standard markiert werden (ein Nicht-4K- und ein 4K-Server). Administratoren können den Server überschreiben, auf dem neue Anfragen vor der Genehmigung verarbeitet werden.\",\n  \"components.Settings.services\": \"Dienste\",\n  \"components.Settings.settingUpPlexDescription\": \"Um Plex einzurichten, kannst du die Daten manuell eintragen oder einen Server auswählen, der von <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink> abgerufen wurde. Drücke den Knopf rechts neben dem Dropdown-Menü, um die Liste der verfügbaren Server abzurufen.\",\n  \"components.Settings.sonarrsettings\": \"Sonarr Einstellungen\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Durchsuchung starten\",\n  \"components.Settings.tautulliApiKey\": \"API-Schlüssel\",\n  \"components.Settings.tautulliSettings\": \"Tautulli Einstellungen\",\n  \"components.Settings.tautulliSettingsDescription\": \"Optionale Einstellungen für den Tautulli-Server konfigurieren. Seerr holt den Wiedergabeverlauf für deine Plex-Medien von Tautulli.\",\n  \"components.Settings.toastPlexConnecting\": \"Versuche mit Plex zu verbinden…\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Verbindung zu Plex fehlgeschlagen.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex Verbindung erfolgreich hergestellt!\",\n  \"components.Settings.toastPlexRefresh\": \"Abrufen der Serverliste von Plex…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Fehler beim Abrufen der Plex Serverliste.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Plex Serverliste erfolgreich abgerufen!\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Beim Speichern der Tautulli Einstellungen ist etwas schief gegangen.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli Einstellungen erfolgreich gespeichert!\",\n  \"components.Settings.urlBase\": \"URL-Basis\",\n  \"components.Settings.validationApiKey\": \"Die Angabe eines API-Schlüssels ist erforderlich\",\n  \"components.Settings.validationHostnameRequired\": \"Ein gültiger Hostname oder eine IP-Adresse muss angegeben werden\",\n  \"components.Settings.validationPortRequired\": \"Du musst einen gültigen Port angeben\",\n  \"components.Settings.validationUrl\": \"Die Angabe einer gültigen URL ist erforderlich\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Die URL-Basis muss mit einem Schrägstrich beginnen\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"Die URL-Basis darf nicht mit einem Schrägstrich enden\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL darf nicht mit einem Schrägstrich enden\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Web App</WebAppLink> URL\",\n  \"components.Settings.webAppUrlTip\": \"Leite Benutzer optional zur Web-App auf deinem Server statt zur „gehosteten“ Web-App weiter\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Setup.configureservices\": \"Dienste konfigurieren\",\n  \"components.Setup.continue\": \"Fortfahren\",\n  \"components.Setup.finish\": \"Konfiguration beenden\",\n  \"components.Setup.finishing\": \"Fertigstellung…\",\n  \"components.Setup.setup\": \"Einrichtung\",\n  \"components.Setup.signinMessage\": \"Melde dich zunächst an\",\n  \"components.Setup.welcome\": \"Willkommen bei Seerr\",\n  \"components.StatusBadge.managemedia\": \"{mediaType} verwalten\",\n  \"components.StatusBadge.openinarr\": \"In {arr} öffnen\",\n  \"components.StatusBadge.playonplex\": \"Auf {mediaServerName} abspielen\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} aktualisiert\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Klicke bitte auf die Schaltfläche unten, um die Anwendung neu zu laden.\",\n  \"components.StatusChecker.reloadApp\": \"{applicationTitle} neu laden\",\n  \"components.StatusChecker.restartRequired\": \"Server Neustart erforderlich\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Starte bitte den Server neu, um die aktualisierten Einstellungen zu übernehmen.\",\n  \"components.TitleCard.cleardata\": \"Daten löschen\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} wurde nicht gefunden\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB-ID\",\n  \"components.TvDetails.Season.noepisodes\": \"Liste der Folgen nicht verfügbar.\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Beim Datenabruf der Staffel ist etwas schief gelaufen.\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Komplette Serien Besetzung\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Komplette Serien-Crew\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.cast\": \"Besetzung\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Folge} other {# Folgen}}\",\n  \"components.TvDetails.episodeRuntime\": \"Laufzeit der Folge\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} Minuten\",\n  \"components.TvDetails.firstAirDate\": \"Erstausstrahlung\",\n  \"components.TvDetails.manageseries\": \"Serie verwalten\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Netzwerk} other {Netzwerke}}\",\n  \"components.TvDetails.nextAirDate\": \"Nächstes Sendedatum\",\n  \"components.TvDetails.originallanguage\": \"Originalsprache\",\n  \"components.TvDetails.originaltitle\": \"Originaltitel\",\n  \"components.TvDetails.overview\": \"Übersicht\",\n  \"components.TvDetails.overviewunavailable\": \"Übersicht nicht verfügbar.\",\n  \"components.TvDetails.productioncountries\": \"Produktions{countryCount, plural, one {land} other {länder}}\",\n  \"components.TvDetails.recommendations\": \"Empfehlungen\",\n  \"components.TvDetails.reportissue\": \"Problem melden\",\n  \"components.TvDetails.rtaudiencescore\": \"Rotten Tomatoes - Nutzerwertung\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes - Tomatometer\",\n  \"components.TvDetails.seasonnumber\": \"Staffel {seasonNumber}\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Staffel} other {# Staffeln}}\",\n  \"components.TvDetails.seasonstitle\": \"Staffeln\",\n  \"components.TvDetails.showtype\": \"Serientyp\",\n  \"components.TvDetails.similar\": \"Ähnliche Serien\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.streamingproviders\": \"Streamt derzeit auf\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB - Nutzerwertung\",\n  \"components.TvDetails.viewfullcrew\": \"Komplette Crew anzeigen\",\n  \"components.TvDetails.watchtrailer\": \"Trailer ansehen\",\n  \"components.UserList.accounttype\": \"Art\",\n  \"components.UserList.admin\": \"Admin\",\n  \"components.UserList.autogeneratepassword\": \"Passwort automatisch generieren\",\n  \"components.UserList.autogeneratepasswordTip\": \"Sende ein vom Server generiertes Passwort per E-Mail an den Benutzer\",\n  \"components.UserList.bulkedit\": \"Ausgewählte bearbeiten\",\n  \"components.UserList.create\": \"Erstellen\",\n  \"components.UserList.created\": \"Beigetreten\",\n  \"components.UserList.createlocaluser\": \"Lokalen Benutzer erstellen\",\n  \"components.UserList.creating\": \"Erstelle…\",\n  \"components.UserList.deleteconfirm\": \"Möchtest du diesen Benutzer wirklich löschen? Alle seine Anfragendaten werden dauerhaft entfernt.\",\n  \"components.UserList.deleteuser\": \"Benutzer löschen\",\n  \"components.UserList.edituser\": \"Benutzerberechtigungen bearbeiten\",\n  \"components.UserList.email\": \"E-Mail-Adresse\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {Benutzer} other {Benutzer}} erfolgreich importiert!\",\n  \"components.UserList.importfrommediaserver\": \"{mediaServerName}-Benutzer importieren\",\n  \"components.UserList.importfromplex\": \"Plex Benutzer importieren\",\n  \"components.UserList.importfromplexerror\": \"Beim Importieren von Plex Benutzern ist etwas schief gelaufen.\",\n  \"components.UserList.localLoginDisabled\": \"Die Einstellung <strong>Lokale Anmeldung aktivieren</strong> ist derzeit deaktiviert.\",\n  \"components.UserList.localuser\": \"Lokaler Benutzer\",\n  \"components.UserList.newplexsigninenabled\": \"Die Einstellung <strong>Neue Plex-Anmeldung aktivieren</strong> ist derzeit aktiviert. Plex-Benutzer mit Bibliothekszugang müssen nicht importiert werden, um sich anmelden zu können.\",\n  \"components.UserList.nouserstoimport\": \"Es gibt keine zu importierenden Plex Benutzer.\",\n  \"components.UserList.owner\": \"Besitzer\",\n  \"components.UserList.password\": \"Passwort\",\n  \"components.UserList.passwordinfodescription\": \"Konfiguriere eine Anwendungs-URL und aktiviere E-Mail-Benachrichtigungen, um die automatische Passwortgenerierung zu ermöglichen.\",\n  \"components.UserList.plexuser\": \"Plex-Benutzer\",\n  \"components.UserList.role\": \"Rolle\",\n  \"components.UserList.sortCreated\": \"Beitrittsdatum\",\n  \"components.UserList.sortDisplayName\": \"Anzeigename\",\n  \"components.UserList.sortRequests\": \"Anzahl der Anfragen\",\n  \"components.UserList.totalrequests\": \"Anfragen\",\n  \"components.UserList.user\": \"Benutzer\",\n  \"components.UserList.usercreatedfailed\": \"Beim Erstellen des Benutzers ist etwas schief gelaufen.\",\n  \"i18n.edit\": \"Bearbeiten\",\n  \"i18n.experimental\": \"Experimentell\",\n  \"components.UserList.userssaved\": \"Benutzerberechtigungen erfolgreich gespeichert!\",\n  \"i18n.advanced\": \"Erweitert\",\n  \"components.UserList.validationEmail\": \"E-Mail Adresse benötigt\",\n  \"components.UserList.users\": \"Benutzer\",\n  \"components.UserProfile.recentrequests\": \"Letzte Anfragen\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Berechtigungen\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Benachrichtigungen\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Allgemein\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Passwort\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Berechtigungen erfolgreich gespeichert!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Beim Speichern der Einstellungen ist etwas schief gelaufen.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Berechtigungen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Das Passwort ist zu kurz, es sollte mindestens 8 Zeichen lang sein\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Du musst ein neues Passwort angeben\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Du musst dein aktuelles Passwort angeben\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Die Passwörter müssen übereinstimmen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Du musst das neue Passwort bestätigen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Passwort erfolgreich geändert!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Beim Speichern des Passworts ist ein Fehler aufgetreten.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Passwort ändern\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Neues Passwort\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Aktuelles Passwort\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Passwort bestätigen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Benachrichtigungseinstellungen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Benutzer-ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Einstellungen erfolgreich gespeichert!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Beim Speichern der Einstellungen ist etwas schief gelaufen.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex Benutzer\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Lokaler Benutzer\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Allgemeine Einstellungen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Anzeigename\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Einstellungen bearbeiten\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Profil anzeigen\",\n  \"components.UserList.userfail\": \"Beim Speichern der Benutzerberechtigungen ist ein Fehler aufgetreten.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Du musst eine gültige Benutzer-ID angeben\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"Die <FindDiscordIdLink>ID Nummer</FindDiscordIdLink> für dein Benutzerkonto\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtere Inhalte nach regionaler Verfügbarkeit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Region Entdecken\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtere Inhalte nach Originalsprache\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Sprache des Bereichs \\\"Entdecken\\\"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Es besteht keine Berechtigung, das Passwort dieses Benutzers zu ändern.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Benutzer\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rolle\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Besitzer\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Admin\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Kontotyp\",\n  \"i18n.loading\": \"Lade…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Du musst eine gültige Chat-ID angeben\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Starte einen Chat</TelegramBotLink>, füge <GetIdBotLink>@get_id_bot</GetIdBotLink> hinzu, und führe den Befehl <code>/my_id</code> aus\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chat-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Sende Benachrichtigungen ohne Ton\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Lautlos senden\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Benutzer-ID: {userid}\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Mitglied seit dem {joindate}\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Du hast keine Berechtigung, die Einstellungen dieses Benutzers zu ändern.\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Du kannst deine eigenen Berechtigungen nicht ändern.\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.somethingwentwrong\": \"Etwas ist schief gelaufen\",\n  \"pages.serviceunavailable\": \"Dienst nicht verfügbar\",\n  \"pages.pagenotfound\": \"Seite nicht gefunden\",\n  \"pages.internalservererror\": \"Interner Serverfehler\",\n  \"i18n.usersettings\": \"Benutzereinstellungen\",\n  \"i18n.settings\": \"Einstellungen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Beim Speichern des Passworts ist ein Fehler aufgetreten. Wurde dein aktuelles Passwort korrekt eingegeben?\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Benachrichtigungen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Allgemein\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.view\": \"Anzeigen\",\n  \"i18n.tvshow\": \"Serie\",\n  \"i18n.testing\": \"Testen…\",\n  \"i18n.test\": \"Test\",\n  \"i18n.status\": \"Status\",\n  \"i18n.showingresults\": \"Zeige <strong>{from}</strong> bis <strong>{to}</strong> von <strong>{total}</strong> Ergebnissen\",\n  \"i18n.saving\": \"Speichern…\",\n  \"i18n.save\": \"Änderungen speichern\",\n  \"i18n.retrying\": \"Wiederholen…\",\n  \"i18n.resultsperpage\": \"Zeige {pageSize} Ergebnisse pro Seite\",\n  \"i18n.requesting\": \"Anfragen…\",\n  \"i18n.request4k\": \"In 4K anfragen\",\n  \"i18n.previous\": \"Zurück\",\n  \"i18n.notrequested\": \"Nicht angefragt\",\n  \"i18n.noresults\": \"Keine Ergebnisse.\",\n  \"i18n.next\": \"Weiter\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.canceling\": \"Abbrechen…\",\n  \"i18n.back\": \"Zurück\",\n  \"i18n.areyousure\": \"Bist du sicher?\",\n  \"i18n.all\": \"Alle\",\n  \"components.UserProfile.totalrequests\": \"Anfragen insgesamt\",\n  \"components.UserProfile.seriesrequest\": \"Serienanfragen\",\n  \"components.UserProfile.pastdays\": \"{type} (vergangene {days} Tage)\",\n  \"components.UserProfile.movierequests\": \"Filmanfragen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Für dein Konto ist derzeit kein Passwort festgelegt. Konfiguriere unten ein Passwort, um die Anmeldung als \\\"lokaler Benutzer\\\" mit deiner E-Mail-Adresse zu aktivieren.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Für dieses Benutzerkonto ist derzeit kein Passwort festgelegt. Konfiguriere unten ein Passwort, damit sich dieses Konto als \\\"lokaler Benutzer\\\" anmelden kann\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Du musst einen gültigen öffentlichen PGP-Schlüssel angeben\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Die Einstellungen für die Telegram-Benachrichtigung konnten nicht gespeichert werden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Verschlüssele E-Mail-Nachrichten mit <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Öffentlicher PGP-Schlüssel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"E-Mail-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"E-Mail-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-Mail\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Die Einstellungen für die Discord-Benachrichtigung konnten nicht gespeichert werden.\",\n  \"components.UserProfile.unlimited\": \"Unbegrenzt\",\n  \"components.UserProfile.requestsperdays\": \"{limit} verbleibend\",\n  \"components.UserProfile.limit\": \"{remaining} von {limit}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Serienanfragenlimit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Filmanfragenlimit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Überschreibe globales Limit\",\n  \"components.UserList.usercreatedfailedexisting\": \"Die angegebene E-Mail Adresse wird bereits von einem anderen Benutzer verwendet.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Standard ({language})\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Anzeigesprache\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord Benutzer ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Die <FindDiscordIdLink>mehrstellige ID-Nummer</FindDiscordIdLink> deines Discord-Accounts\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Filme automatisch aus Plex-Merkliste anfragen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Automatisch Filme aus deiner <PlexWatchlistSupportLink>Plex Merkliste</PlexWatchlistSupportLink> anfragen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Serien automatisch aus Plex-Merkliste anfragen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Automatisch Serien aus deiner <PlexWatchlistSupportLink>Plex Merkliste</PlexWatchlistSupportLink> anfragen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Du musst eine gültige Discord Benutzer ID angeben\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Zugangs-Token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Erstelle ein Token aus deinen <PushbulletSettingsLink>Kontoeinstellungen</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Die Einstellungen für Pushbullet-Benachrichtigungen konnten nicht gespeichert werden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Anwendungs API-Token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registriere eine Anwendung</ApplicationRegistrationLink> zur Verwendung mit {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Benutzer- oder Gruppenschlüssel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Die 30-stellige <UsersGroupsLink>Benutzer- oder Gruppenkennung</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Die Einstellungen für die Pushover-Benachrichtigung konnten nicht gespeichert werden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Ein Zugriffstoken muss angegeben werden\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Du musst einen gültigen Anwendungs-Token angeben\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Du musst einen gültigen Benutzer- oder Gruppenschlüssel angeben\",\n  \"i18n.resolved\": \"Gelöst\",\n  \"i18n.importing\": \"Importieren…\",\n  \"i18n.import\": \"Importieren\",\n  \"components.UserProfile.recentlywatched\": \"Kürzlich angesehen\",\n  \"i18n.restartRequired\": \"Neustart erforderlich\",\n  \"components.UserProfile.emptywatchlist\": \"Hier erscheinen deine zur <PlexWatchlistSupportLink>Plex Merkliste</PlexWatchlistSupportLink> hinzugefügte Medien.\",\n  \"components.UserProfile.plexwatchlist\": \"Plex Merkliste\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Serien\",\n  \"components.Discover.moviegenres\": \"Film-Genres\",\n  \"components.Discover.studios\": \"Studios\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB Film-Genre\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB Serien-Genre\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB Serien Stichwort\",\n  \"components.Discover.tvgenres\": \"Serien-Genres\",\n  \"components.Settings.SettingsMain.apikey\": \"API-Schlüssel\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Anwendungstitel\",\n  \"components.Settings.SettingsMain.general\": \"Allgemein\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Allgemeine Einstellungen\",\n  \"components.Settings.SettingsMain.locale\": \"Anzeigesprache\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Verfügbare Medien ausblenden\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Neuer API Schlüssel erfolgreich generiert!\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Du musst eine gültige URL angeben\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"Die URL darf nicht mit einem Schrägstrich \\\"/\\\" enden\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Filme\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Deine Merkliste\",\n  \"components.Discover.tmdbsearch\": \"TMDB Suche\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Etwas ist schiefgelaufen während der Generierung eines neuen API Schlüssels.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Einstellungen erfolgreich gespeichert!\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB Film-Stichwort\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Du musst einen Anwendungstitel angeben\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Medien in deiner <PlexWatchlistSupportLink>Plex Merkliste</PlexWatchlistSupportLink> erscheinen hier.\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Cache extern gehostete Bilder (erfordert eine beträchtliche Menge an Speicherplatz)\",\n  \"components.Discover.networks\": \"Dienste\",\n  \"components.Discover.tmdbstudio\": \"TMDB Studio\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Anwendung URL\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Bild-Caching aktivieren\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Globale und Standardeinstellungen für Seerr konfigurieren.\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Sprache des Bereichs \\\"Entdecken\\\"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Teilweise Serienanfragen zulassen\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Beim Speichern der Einstellungen ist ein Fehler aufgetreten.\",\n  \"components.Discover.tmdbnetwork\": \"TMDB Netzwerk\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Inhalt nach Originalsprache filtern\",\n  \"components.Discover.CreateSlider.addSlider\": \"Schieberegler hinzufügen\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Benutzerdefinierten Schieberegler erstellen\",\n  \"components.Discover.CreateSlider.addfail\": \"Neuer Schieberegler konnte nicht erstellt werden.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Ein neuer Schieberegler wurde erstellt und die Einstellungen wurden gespeichert.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Schieberegler bearbeiten\",\n  \"components.Discover.CreateSlider.editfail\": \"Schieberegler konnte nicht bearbeitet werden.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Schieberegler bearbeitet und Einstellung gespeichert.\",\n  \"components.Discover.CreateSlider.needresults\": \"Es muss mindestens 1 Ergebnis vorhanden sein.\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filme\",\n  \"components.Layout.Sidebar.browsetv\": \"Serien\",\n  \"components.Discover.CreateSlider.nooptions\": \"Keine Ergebnisse.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Hinterlege eine TMDB Genre ID\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Hinterlege eine TMDB Schlüsselwort ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Hinterlege eine TMDB Netzwerk ID\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Gib eine Suchanfrage ein\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Du musst einen Titel eingeben.\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Entfernen\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Schieberegler konnte nicht gelöscht werden.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Schieberegler erfolgreich entfernt.\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filme\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Erscheinungsdatum (aufsteigend)\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Erscheinungsdatum (absteigend)\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Titel (A-Z) (aufsteigend)\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Titel (Z-A) (absteigend)\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Serien\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Erstausstrahlung (absteigend)\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Erstausstrahlung (aufsteigend)\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Beliebtheit (aufsteigend)\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Beliebtheit (absteigend)\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Name des Schiebereglers\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Medienverfügbarkeit Sync\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# aktiver Filter} other {# aktive Filter}}\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Originalsprache\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Alle {jobScheduleSeconds, plural, one {Sekunde} other {{jobScheduleSeconds} Sekunden}}\",\n  \"components.Discover.updatefailed\": \"Bei der Aktualisierung der Entdecken-Einstellungen ist ein Fehler aufgetreten.\",\n  \"components.Selector.searchGenres\": \"Genres auswählen…\",\n  \"components.Discover.updatesuccess\": \"Die Einstellungen für die Entdecken-Anpassung wurden aktualisiert.\",\n  \"components.Selector.showmore\": \"Mehr anzeigen\",\n  \"components.Selector.starttyping\": \"Start der Suche durch Tippen.\",\n  \"components.Selector.showless\": \"Weniger anzeigen\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"TMDB Studio ID angeben\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Genres suchen…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Stichwörter suchen…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Studios suchen…\",\n  \"components.Discover.CreateSlider.starttyping\": \"Start der Suche durch Tippen.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Du musst einen Datenwert angeben.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Sichtbarkeit umschalten\",\n  \"components.Discover.customizediscover\": \"Entdecken anpassen\",\n  \"components.Discover.resetfailed\": \"Beim Zurücksetzen der Entdecken-Einstellungen ist etwas schief gelaufen.\",\n  \"components.Discover.resetsuccess\": \"Die Entdecken-Einstellungen wurden erfolgreich zurückgesetzt.\",\n  \"components.Discover.stopediting\": \"Bearbeitung stoppen\",\n  \"components.Discover.resettodefault\": \"Zurücksetzen auf Standard\",\n  \"components.Discover.resetwarning\": \"Setzt alle Schieberegler auf die Standardwerte zurück. Dadurch werden auch alle benutzerdefinierten Schieberegler gelöscht!\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# aktiver Filter} other {# aktive Filter}}\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Beliebtheit (aufsteigend)\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Beliebtheit (absteigend)\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB Bewertung (aufsteigend)\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB Bewertung (absteigend)\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# aktiver Filter} other {# aktive Filter}}\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Titel (A-Z) (aufsteigend)\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Titel (Z-A) (absteigend)\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB Bewertung (aufsteigend)\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB Bewertung (absteigend)\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Aktive Filter löschen\",\n  \"components.Discover.FilterSlideover.filters\": \"Filter\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Datum der Erstausstrahlung\",\n  \"components.Discover.FilterSlideover.from\": \"Von\",\n  \"components.Discover.FilterSlideover.genres\": \"Genres\",\n  \"components.Discover.FilterSlideover.keywords\": \"Stichwörter\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Bewertungen zwischen {minValue} und {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Erscheinungsdatum\",\n  \"components.Discover.FilterSlideover.runtime\": \"Laufzeit\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} Minuten Laufzeit\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB - Nutzerwertung\",\n  \"components.Discover.FilterSlideover.to\": \"Bis\",\n  \"components.Discover.createnewslider\": \"Neuen Schieberegler erstellen\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streamingdienste\",\n  \"components.Selector.nooptions\": \"Keine Ergebnisse.\",\n  \"components.Selector.searchKeywords\": \"Stichwörter suchen…\",\n  \"components.Selector.searchStudios\": \"Studios suchen…\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB Film-Streamingdienste\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TV-Streamingdienste\",\n  \"i18n.collection\": \"Sammlung\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Anzahl der TMDB-Nutzerwertungen\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Füge automatisch einen zusätzlichen Tag mit der ID und dem Namen des anfragenden Nutzers hinzu\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB Nutzerbewertung - Stimmen: {formattedCount}\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Tag Anforderungen\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Anzahl der Abstimmungen zwischen {minValue} und {maxValue}\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Füge automatisch einen zusätzlichen Tag mit der ID und dem Namen des anfragenden Nutzers hinzu\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Ein Passwort ist erforderlich.\",\n  \"components.Login.description\": \"Da du dich zum ersten Mal bei {applicationName} anmeldest, musst du eine gültige E-Mail-Adresse angeben.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Eine E-Mail-Adresse ist erforderlich.\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Die E-Mail-Adresse ist ungültig.\",\n  \"components.Login.credentialerror\": \"Der Benutzername oder das Passwort ist falsch.\",\n  \"components.Login.emailtooltip\": \"Die Adresse muss nicht mit deiner {mediaServerName}-Instanz verbunden sein.\",\n  \"components.Login.initialsignin\": \"Verbinde\",\n  \"components.Login.initialsigningin\": \"Verbinden…\",\n  \"components.Login.save\": \"Hinzufügen\",\n  \"components.Login.saving\": \"Hinzufügen…\",\n  \"components.Login.signinwithjellyfin\": \"Verwende dein {mediaServerName} Konto\",\n  \"components.Login.title\": \"E-Mail hinzufügen\",\n  \"components.Login.username\": \"Benutzername\",\n  \"components.Login.validationEmailFormat\": \"Ungültige E-Mail-Adresse\",\n  \"components.Login.validationEmailRequired\": \"Du musst eine E-Mail-Adresse angeben\",\n  \"components.Login.validationemailformat\": \"Gültige E-Mail-Adresse erforderlich\",\n  \"components.Login.validationhostformat\": \"Gültige URL erforderlich\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL erforderlich\",\n  \"components.Login.validationusernamerequired\": \"Benutzername erforderlich\",\n  \"components.ManageSlideOver.removearr\": \"Aus {arr} entfernen\",\n  \"components.ManageSlideOver.removearr4k\": \"Aus 4K {arr} entfernen\",\n  \"components.MovieDetails.downloadstatus\": \"Download-Status\",\n  \"components.MovieDetails.openradarr4k\": \"Film in 4K Radarr öffnen\",\n  \"components.MovieDetails.play\": \"Auf {mediaServerName} wiedergeben\",\n  \"components.MovieDetails.play4k\": \"4K abspielen auf {mediaServerName}\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Anime-Serien Typ\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName} Einstellungen\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName} Einstellungen erfolgreich gespeichert!\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName} Bibliotheken\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName} Einstellungen\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Konfiguriere die Einstellungen für deinen {mediaServerName} Server. {mediaServerName} scannt deine {mediaServerName} Bibliotheken, um zu sehen, welche Inhalte verfügbar sind.\",\n  \"components.Settings.manualscanJellyfin\": \"Manuelles Scannen der Bibliothek\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.saving\": \"Speichern…\",\n  \"components.Settings.syncing\": \"Synchronisierung\",\n  \"components.Settings.timeout\": \"Zeitüberschreitung\",\n  \"components.Setup.signin\": \"Anmelden\",\n  \"components.Setup.signinWithJellyfin\": \"Gib deine Jellyfin Daten ein\",\n  \"components.Setup.signinWithPlex\": \"Gib deine Plex Daten ein\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> Erfolgreich aus der Merkliste entfernt!\",\n  \"components.TitleCard.watchlistError\": \"Ein Fehler ist aufgetreten. Bitte versuche es erneut.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> erfolgreich zur Merkliste hinzugefügt!\",\n  \"components.TvDetails.play\": \"Auf {mediaServerName} wiedergeben\",\n  \"components.TvDetails.play4k\": \"4K abspielen auf {mediaServerName}\",\n  \"components.UserList.importfromJellyfin\": \"Importieren von {mediaServerName} Benutzern\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName} Benutzer\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Es gibt keine {mediaServerName} Benutzer zu importieren.\",\n  \"components.UserList.userdeleted\": \"Benutzer erfolgreich gelöscht!\",\n  \"components.UserList.userdeleteerror\": \"Beim Löschen des Benutzers ist etwas schief gelaufen.\",\n  \"components.UserList.userlist\": \"Benutzerliste\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-Mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName} Benutzer\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Speichern…\",\n  \"i18n.close\": \"Schließen\",\n  \"i18n.decline\": \"Ablehnen\",\n  \"i18n.declined\": \"Abgelehnt\",\n  \"i18n.delete\": \"Löschen\",\n  \"i18n.deleting\": \"Löschen…\",\n  \"i18n.failed\": \"Fehlgeschlagen\",\n  \"i18n.movies\": \"Filme\",\n  \"i18n.open\": \"Offen\",\n  \"i18n.pending\": \"Ausstehend\",\n  \"i18n.processing\": \"Verarbeiten\",\n  \"i18n.request\": \"Anfrage senden\",\n  \"i18n.requested\": \"Angefragt\",\n  \"i18n.retry\": \"Wiederholen\",\n  \"i18n.tvshows\": \"Serien\",\n  \"i18n.unavailable\": \"Nicht verfügbar\",\n  \"pages.oops\": \"Hoppla\",\n  \"components.MovieDetails.openradarr\": \"Film in Radarr öffnen\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Gerätestandard\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Tag-Anfragen\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Konfiguriere optional die internen und externen Endpunkte für deinen {mediaServerName} Server. In den meisten Fällen ist die externe URL eine andere als die interne URL. Für die Anmeldung bei {mediaServerName} kann auch eine benutzerdefinierte URL zum Zurücksetzen des Passworts festgelegt werden, falls du auf eine andere Seite zum Zurücksetzen des Passworts umleiten möchtest. Du kannst auch selber einen API Key für Jellyfin anlegen, was bisher automatisch geschah.\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Beim Speichern der Einstellungen von {mediaServerName} ist ein Fehler aufgetreten.\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalerweise wird dieser Vorgang nur einmal alle 24 Stunden durchgeführt. Seerr wird die kürzlich hinzugefügten Bibliotheken deines {mediaServerName} Servers aggressiver überprüfen. Wenn dies das erste Mal ist, dass du Seerr konfigurierst, wird ein einmaliger vollständiger manueller Bibliotheks-Scan empfohlen!\",\n  \"components.Settings.save\": \"Änderungen speichern\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Benutzer E-Mail erforderlich\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Benachrichtigungston\",\n  \"components.Settings.SonarrModal.seriesType\": \"TV-Serie Typ\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"Die Bibliotheken {mediaServerName} werden nach Titeln durchsucht. Klicke auf die Schaltfläche unten, wenn keine Bibliotheken aufgelistet sind.\",\n  \"components.UserList.importfromJellyfinerror\": \"Beim Importieren von {mediaServerName} Benutzern ist etwas schief gelaufen.\",\n  \"components.Settings.syncJellyfin\": \"Bibliotheken synchronisieren\",\n  \"components.Setup.configuremediaserver\": \"Medienserver konfigurieren\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Änderungen speichern\",\n  \"i18n.available\": \"Verfügbar\",\n  \"i18n.cancel\": \"Abbrechen\",\n  \"components.TitleCard.addToWatchList\": \"Zur Merkliste hinzufügen\",\n  \"components.TitleCard.watchlistCancel\": \"Merkliste für <strong>{title}</strong> entfernt.\",\n  \"components.UserList.usercreatedsuccess\": \"Benutzer erfolgreich angelegt!\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Dadurch wird dieser {mediaType} unwiderruflich aus {arr} entfernt, einschließlich aller Dateien.\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {Benutzer} other {Benutzer}} erfolgreich importiert!\",\n  \"components.UserList.validationpasswordminchars\": \"Das Passwort ist zu kurz, es sollte mindestens 8 Zeichen lang sein\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Gerätestandard\",\n  \"i18n.approve\": \"Genehmigen\",\n  \"i18n.partiallyavailable\": \"Teilweise verfügbar\",\n  \"components.UserList.newJellyfinsigninenabled\": \"Die Einstellung <strong>Neue {mediaServerName}-Anmeldung aktivieren</strong> ist derzeit aktiviert. {mediaServerName}-Benutzer mit Bibliothekszugang müssen nicht importiert werden, um sich anmelden zu können.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Benachrichtigungston\",\n  \"components.UserProfile.localWatchlist\": \"Merkliste von {username}\",\n  \"i18n.approved\": \"Genehmigt\",\n  \"pages.returnHome\": \"Zurück zur Startseite\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.UserList.username\": \"Benutzername\",\n  \"components.Login.adminerror\": \"Für die Anmeldung ist ein Administratorkonto erforderlich.\",\n  \"components.MovieDetails.watchlistError\": \"Es ist ein Fehler aufgetreten. Bitte erneut versuchen.\",\n  \"components.RequestList.RequestItem.profileName\": \"Profil\",\n  \"components.Selector.searchStatus\": \"Status auswählen...\",\n  \"components.Settings.invalidurlerror\": \"Es kann keine Verbindung zu {mediaServerName} hergestellt werden.\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Es trat ein unbekannter Fehler während der Bibliothekssynchronisation auf\",\n  \"components.UserList.validationUsername\": \"Du musst einen Benutzernamen angeben\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"E-Mail-Adresse benötigt\",\n  \"components.Login.invalidurlerror\": \"Es kann keine Verbindung zu {mediaServerName} hergestellt werden.\",\n  \"components.MovieDetails.removefromwatchlist\": \"Von der Merkliste entfernen\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> erfolgreich aus der Merkliste entfernt!\",\n  \"components.Login.back\": \"Zurück\",\n  \"components.Login.servertype\": \"Servertyp\",\n  \"components.Login.validationPortRequired\": \"Du musst einen gültigen Port angeben\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"Die URL-Basis muss mit einem Schrägstrich beginnen\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"Die URL-Basis darf nicht auf einem Slash enden\",\n  \"components.Login.validationUrlTrailingSlash\": \"Die URL darf nicht auf einem Slash enden\",\n  \"components.Login.validationservertyperequired\": \"Bitte wähle einen Servertyp\",\n  \"components.MovieDetails.addtowatchlist\": \"Zur Merkliste hinzufügen\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> erfolgreich aus der Merkliste entfernt!\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> erfolgreich zur Merkliste hinzugefügt!\",\n  \"components.Selector.canceled\": \"Abgebrochen\",\n  \"components.Selector.ended\": \"Beendet\",\n  \"components.Selector.inProduction\": \"In Produktion\",\n  \"components.Selector.pilot\": \"Pilotfolge\",\n  \"components.Selector.planned\": \"Geplant\",\n  \"components.Selector.returningSeries\": \"Wiederkehrende Serie\",\n  \"components.Setup.back\": \"Zurückgehen\",\n  \"components.Setup.configemby\": \"Emby konfigurieren\",\n  \"components.Setup.configjellyfin\": \"Jellyfin konfigurieren\",\n  \"components.Setup.configplex\": \"Plex konfigurieren\",\n  \"components.Setup.servertype\": \"Servertyp auswählen\",\n  \"components.Setup.signinWithEmby\": \"Emby Daten eintragen\",\n  \"components.Setup.subtitle\": \"Leg los, indem du einen Medienserver auswählst\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.TvDetails.addtowatchlist\": \"Zur Merkliste hinzufügen\",\n  \"components.TvDetails.removefromwatchlist\": \"Von der Merkliste entfernen\",\n  \"components.TvDetails.watchlistError\": \"Ein Fehler ist aufgetreten. Bitte versuche es erneut.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> erfolgreich zur Merkliste hinzugefügt!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Gültige E-Mail-Adresse benötigt\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.urlBase\": \"URL-Basis\",\n  \"components.Login.enablessl\": \"Benutze SSL\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Passwort vergessen URL\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Eine benutzerdefinierte Authentifizierung mit automatischer Bibliotheksbündelung wird nicht unterstützt\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Es wurden keine Bibliotheken gefunden\",\n  \"components.Settings.scanbackground\": \"Der Scan läuft im Hintergrund. Die Einrichtung kann in der Zwischenzeit fortgesetzt werden.\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Region für \\\"Entdecken\\\"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex Refresh Token\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Region für \\\"Entdecken\\\"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Du musst eine gültige Discord Rollen-ID angeben\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"Die Rollen ID, die in der Webhook Nachricht erwähnt werden soll. Leer lassen, um Erwähnungen zu deaktivieren\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Region des Streamings\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Streaming Region\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Streaming Seiten nach regionaler Verfügbarkeit anzeigen\",\n  \"components.RequestList.RequestItem.removearr\": \"Von {arr} entfernen\",\n  \"components.RequestList.sortDirection\": \"Sortierrichtung umschalten\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Benachrichtigung Rollen ID\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Avatare der Nutzer\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Inhalte nach regionaler Verfügbarkeit filtern\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Streaming Seiten nach regionaler Verfügbarkeit anzeigen\",\n  \"components.Settings.apiKey\": \"API-Schlüssel\",\n  \"components.Settings.tip\": \"Tipp\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Inhalte nach regionaler Verfügbarkeit filtern\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Diese E-Mail-Adresse ist bereits vergeben!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Dieser Benutzername ist bereits vergeben. Eine E-Mail-Adresse muss angegeben werden\",\n  \"i18n.specials\": \"Sonderfolgen\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Erlaube Seerr die Client-IP-Adressen hinter einem Proxy zu registrieren\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Demnächst erscheinende Serien\",\n  \"components.Login.loginwithapp\": \"Mit {appName} anmelden\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Stammverzeichnis\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Verknüpfte Konten\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Verknüpftes Konto kann nicht gelöscht werden.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Es muss ein Benutzername eingegeben werden\",\n  \"components.Setup.librarieserror\": \"Validierung fehlgeschlagen. Bitte schalte die Bibliotheken erneut um, um fortzufahren.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Verwende ',' als Trennzeichen und '*.' als Platzhalter für Subdomains\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Gibt an, welche Einstellungen geändert werden, wenn die oben genannten Bedingungen erfüllt sind.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Aktiviere {mediaServerName} Anmeldung\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Dieses Konto ist bereits mit einem Plex Benutzer verknüpft\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Anmeldedaten von {mediaServerName} eingeben, um das Konto mit {applicationName} zu verbinden.\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Netzwerkparameter des Containers bzw. Systems sollten statt dieser Einstellungen verwendet werden. Weitere Informationen in den {docs}.\",\n  \"components.Selector.searchUsers\": \"Benutzer auswählen…\",\n  \"components.Settings.overrideRules\": \"Überschreibungsregeln\",\n  \"components.Settings.Notifications.messageThreadId\": \"Thread-/Themen-ID\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Bedingungen\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Einstellungen\",\n  \"components.Login.noadminerror\": \"Auf dem Server wurde kein Administrator gefunden.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Mit deinen Anmeldeinformationen kann keine Verbindung zu Plex hergestellt werden\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Ein unbekannter Fehler ist aufgetreten\",\n  \"components.Settings.addrule\": \"Neue Override-Regel\",\n  \"components.Login.orsigninwith\": \"Oder anmelden mit\",\n  \"components.Settings.OverrideRuleModal.create\": \"Regel erstellen\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Neue Überschreibungsregel\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Überschreibungsregel bearbeiten\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Genre\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Schlüsselwörter\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Sprachen\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Keine Tags.\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Überschreibungsregel erfolgreich erstellt!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Überschreibungsregel erfolgreich aktualisiert!\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Stammverzeichnis wählen\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Dienst auswählen\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Tags auswählen\",\n  \"components.Settings.OverrideRuleTile.users\": \"Benutzer\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Stammverzeichnis\",\n  \"components.Settings.OverrideRuleTile.language\": \"Sprache\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Schlüsselwörter\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Genre\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Bedingungen\",\n  \"components.Settings.OverrideRuleModal.users\": \"Benutzer\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Einstellungen\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Wende diese Regel auf den ausgewählten Dienst an.\",\n  \"components.Settings.OverrideRuleModal.service\": \"Dienst\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Anfragen zu Spezial-Folgen zulassen\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"Diese Einstellung nur aktivieren, wenn die Auswirkungen bekannt sind!\",\n  \"components.Settings.SettingsNetwork.docs\": \"Dokumentation/Hilfe\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Netzwerkeinstellungen\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Konfiguriere die Netzwerkeinstellungen deiner Seerr-Instanz.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Einstellungen erfolgreich gespeichert!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Aktiviere Proxy-Unterstützung\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Es muss ein gültiger Port eingetragen werden\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Es muss mindestens eine Authentifizierungsmethode ausgewählt werden.\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Anmeldemethoden\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Anmeldemethoden für Benutzer konfigurieren.\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Benutzern erlauben, sich mit ihrem {mediaServerName}-Konto anzumelden\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Aktiviere CSRF-Schutz\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Externen API-Zugriff auf schreibgeschützt setzen (erfordert HTTPS)\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Erzwinge IPv4-Auflösung zuerst\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Erzwinge, dass Seerr zuerst IPv4-Adressen anstelle von IPv6 auflöst\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Beim Speichern der Einstellungen ist ein Fehler aufgetreten.\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Proxy Benutzername\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Benutze SSL für Proxy\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Proxy Port\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Proxy Passwort\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Proxy Hostname\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) Proxy\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Proxy für lokale Adressen umgehen\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Vom Proxy ignorierte Adressen\",\n  \"components.Settings.SettingsNetwork.network\": \"Netzwerk\",\n  \"components.Settings.menuNetwork\": \"Netzwerk\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Benutzername\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"{mediaServerName}-Konto verknüpfen\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Hinzufügen…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Es muss ein Passwort eingegeben werden\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Passwort\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Mit deinen Anmeldeinformationen kann keine Verbindung zu {mediaServerName} hergestellt werden\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Dieses Konto ist bereits mit einem {applicationName}-Benutzer verknüpft\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Es besteht keine Berechtigung, die verknüpften Konten dieses Benutzers zu bearbeiten.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Es sind keine externen Konten mit deinem Account verknüpft.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Diese externen Konten sind mit deinem {applicationName}-Konto verknüpft.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Verknüpfte Konten\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Ein unbekannter Fehler ist aufgetreten\",\n  \"components.Settings.overrideRulesDescription\": \"Überschreibungsregeln ermöglichen es dir, Eigenschaften festzulegen, die ersetzt werden, wenn eine Anforderung der Regel entspricht.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"Die Thread/Themen ID muss eine positive volle Zahl sein\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Thread/Themen ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Wenn in deinem Gruppenchat Themen aktiviert sind, kannst du hier die ID des Threads/Themas angeben\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"Die Thread-/Themen-ID muss eine positive volle Zahl sein\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Wenn in deinem Gruppenchat Themen aktiviert sind, kannst du hier die ID des Threads/Themas angeben\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Qualitätsprofil\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Qualitätsprofil auswählen\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Qualitätsprofil\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Gib Bedingungen an, bevor die Parameteränderungen angewendet werden. Jedes Feld muss validiert werden, damit die Regeln angewendet werden (UND-Betrieb). Ein Feld gilt als verifiziert, wenn eine dieser Eigenschaften übereinstimmt (ODER Betrieb).\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Verknüpfen\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"API-Schlüssel in die Zwischenablage kopiert.\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Problem Beschreibung\",\n  \"components.Settings.Notifications.embedPoster\": \"Poster einbetten\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Unterstützung von URL-Variablen\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URL darf nicht mit einem abschließenden Schrägstrich enden\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Zwischenspeicherung von DNS-Abfragen aktivieren, um die Leistung zu optimieren und unnötige API-Aufrufe zu vermeiden\",\n  \"components.Settings.noSpecialCharacters\": \"Die Konfiguration muss eine durch Komma getrennte Liste von TMDB-Schlüsselwort-IDs sein und darf nicht mit einem Komma beginnen oder enden.\",\n  \"components.Settings.seriesMetadataProvider\": \"Serien-Metadatenanbieter\",\n  \"components.Discover.FilterSlideover.certification\": \"Altersfreigabe\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Alle ausgewählten Metadatenanbieter sind einsatzbereit\",\n  \"components.Settings.clickTest\": \"Klicke auf die Schaltfläche \\\"Testen\\\", um die Konnektivität mit den Metadatenanbietern zu überprüfen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Die Einstellungen für Web-Push-Benachrichtigungen konnten nicht gespeichert werden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Web-Push deaktivieren\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Altersfreigaben konnten nicht geladen werden\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Wähle eine Altersfreigabe\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Es muss eine gültige URL angegeben werden\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Es muss eine Prioritätsnummer festgelegt werden\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Die Ntfy-Benachrichtigungseinstellungen konnten nicht gespeichert werden.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr speichert DNS-Abfragen zwischen, um die Leistung zu optimieren und unnötige API-Aufrufe zu vermeiden.\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Einstellungen des Metadatenanbieters konnten nicht gespeichert werden\",\n  \"components.Settings.valueRequired\": \"Es muss ein Wert angegeben werden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Web-Push aktivieren\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Bei der Aktivierung von Web-Push ist ein Fehler aufgetreten.\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Benutzername + Passwort-Authentifizierung\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"Die URL der Testbenachrichtigung ist auf {testUrl} anstelle der eigentlichen Webhook-URL festgelegt.\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNS Cache\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"Aktiviere diese Option NICHT, wenn Probleme mit DNS-Lookups bestehen\",\n  \"components.Settings.menuMetadataProviders\": \"Metadatenanbieter\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"TVDB-Anbieter funktioniert nicht, bitte wähle einen anderen Metadatenanbieter aus\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Browser\",\n  \"i18n.completed\": \"Abgeschlossen\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Schlüsselwörter ausschließen\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.Selector.CertificationSelector.minRating\": \"Minimale Altersfreigabe\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Keine Optionen verfügbar\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Wähle ein Land\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Beginne mit der Eingabe, um zu suchen.\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Priorität\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Poster einbetten\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Ntfy-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Passwort\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Ntfy-Testbenachrichtigung konnte nicht gesendet werden.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Senden einer ntfy-Testmeldung…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Ntfy-Test-Benachrichtigung gesendet!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Token-Authentifizierung\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Thema\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Server Root-URL\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Benutzername\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Es muss ein Thema angegeben sein\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Es muss eine gültige URL angegeben werden\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Es muss mindestens eine Meldungsart ausgewählt werden\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Poster einbetten\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Poster einbetten\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Poster einbetten\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Diese Statistiken werden für alle DNS-Cache-Einträge aggregiert.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Aktive Adressen\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Alter\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"{hostname} DNS-Cache geleert.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Zugriffe\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Verfehlt\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Hostname\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"DNS-Cache leeren\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Trefferquote\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Treffer\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4-Fallback\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Fehlende\",\n  \"components.Settings.SettingsJobsCache.size\": \"Größe\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Verfügbare Medien auf den Entdeckungsseiten ausblenden, aber nicht in den Suchergebnissen\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"DNS Cache Maximale TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"DNS Cache Minimale TTL\",\n  \"components.Settings.chooseProvider\": \"Auswahl von Metadatenanbietern für verschiedene Inhaltstypen\",\n  \"components.Settings.connectionTestFailed\": \"Verbindungstest fehlgeschlagen\",\n  \"components.Settings.failed\": \"Es funktioniert nicht\",\n  \"components.Settings.general\": \"Allgemein\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} ist kein TMDB-Schlüsselwort.\",\n  \"components.Settings.metadataProviderSettings\": \"Metadatenanbieter\",\n  \"components.Settings.metadataSettings\": \"Einstellungen für Metadatenanbieter\",\n  \"components.Settings.metadataSettingsSaved\": \"Einstellungen des Metadatenanbieters gespeichert\",\n  \"components.Settings.no\": \"Nein\",\n  \"components.Settings.nooptions\": \"Keine Ergebnisse.\",\n  \"components.Settings.notTested\": \"Nicht getestet\",\n  \"components.Settings.operational\": \"Im Betrieb\",\n  \"components.Settings.providerStatus\": \"Status des Metadatenanbieters\",\n  \"components.Settings.starttyping\": \"Tippe, um zu suchen.\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"TMDB-Anbieter funktioniert nicht, bitte wähle einen anderen Metadaten-Anbieter aus\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Abonnement löschen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Gerät\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Bei der Deaktivierung von Web-Push ist etwas schief gelaufen.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Gerät verwalten\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Es sind keine Web-Push-Abonnements vorzuweisen.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"OS\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Abonnement gelöscht.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Beim Löschen des Benutzerabonnements ist ein Fehler aufgetreten.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Unbekannt\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Web-Push wurde deaktiviert.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Web-Push wurde aktiviert.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Web-Push-Benachrichtigungseinstellungen erfolgreich gespeichert!\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Wähle einen Metadatenanbieter aus\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Maximale Altersfreigabe\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Agent aktivieren\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Die verfügbaren Variablen sind im Abschnitt Webhook-Vorlagenvariablen dokumentiert\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Globale DNS-Cache-Statistiken\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Fehlschläge\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube URL-Adresse\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"Basis-URL für YouTube-Videos, wenn eine selbst gehostete YouTube-Instanz verwendet wird.\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNS Cache\",\n  \"components.Settings.animeMetadataProvider\": \"Anbieter von Anime-Metadaten\",\n  \"components.Settings.metadataProviderSelection\": \"Auswahl des Metadatenanbieters\",\n  \"components.Settings.searchKeywords\": \"Suchbegriffe…\",\n  \"components.Settings.settings\": \"Einstellungen\",\n  \"components.Settings.yes\": \"Ja\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Erstellt\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Engine\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"Typ\",\n  \"i18n.deleted\": \"Gelöscht\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Alle {jobScheduleDays, plural, one {Tag} other {{jobScheduleDays} Tage}}\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Über Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Einen Beitrag leisten\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Seerr unterstützen\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Es muss eine gültige maximale TTL angegeben werden\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Es muss eine gültige minimale TTL angegeben werden\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Aktives Abonnement\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Verbindung zu {services} nicht möglich. Einige Informationen sind möglicherweise nicht verfügbar.\",\n  \"components.RequestList.unableToConnect\": \"Verbindung zu {services} nicht möglich. Einige Informationen sind möglicherweise nicht verfügbar.\",\n  \"component.BlocklistBlock.blocklistdate\": \"Sperrdatum\",\n  \"component.BlocklistBlock.blocklistedby\": \"Gesperrt durch\",\n  \"component.BlocklistModal.blocklisting\": \"Sperrliste\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> ist nicht auf der Sperrliste.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Medien auf der Sperrliste verwalten.\",\n  \"components.Blocklist.blocklistdate\": \"Datum\",\n  \"components.Blocklist.blocklistedby\": \"{date} durch {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Sperrlisteneinstellungen\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Gesperrte Tags\",\n  \"components.Blocklist.filterManual\": \"Manuell\",\n  \"components.Blocklist.mediaName\": \"Name\",\n  \"components.Blocklist.mediaType\": \"Typ\",\n  \"components.Blocklist.showAllBlocklisted\": \"Alle Medien auf der Sperrliste anzeigen\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb Id\",\n  \"components.Layout.Sidebar.blocklist\": \"Sperrliste\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Autorisierung zum Sperren von Medien.\",\n  \"components.PermissionEdit.manageblocklist\": \"Sperrliste verwalten\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Erlaubnis zur Verwaltung von Medien auf der Sperrliste erteilen.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Medien auf der Sperrliste anzeigen.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Erlaubnis zum Anzeigen von Medien auf der Sperrliste erteilen.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Es wurden noch keine DNS-Abfragen gecacht.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Verarbeiten von Tags auf der Sperrliste\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Inhalte mit Tags auf die Sperrliste setzen\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Begrenzung der auf die Sperrliste gesetzten Inhalte pro Tag\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"Der Auftrag \\\"Tag auf der Sperrliste verarbeiten\\\" wird diese Anzahl von Seiten in jede Sortierung aufnehmen. Größere Zahlen führen zu einer genaueren Sperrliste, benötigen aber auch mehr Platz.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Automatisches Hinzufügen von Inhalten mit Tags zur Sperrliste mit dem Job \\\"Tag auf der Sperrliste verarbeiten\\\"\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Auf der Sperrliste stehende Objekte ausblenden\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Ausblenden von Objekten auf der Sperrliste auf den Entdeckungsseiten für alle Benutzer mit dem Recht \\\"Sperrliste verwalten\\\"\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Leitet den GESAMTEN ausgehenden HTTP/HTTPS-Datenverkehr über einen Proxy-Server (Host/Port). Aktiviert KEIN HTTPS, SSL oder Zertifikatkonfiguration.\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Füge die Konfiguration des Sperrlisten-Tags unten ein.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Konfiguration von Tags auf der Sperrliste importieren\",\n  \"components.Settings.blocklistedTagsText\": \"Tags auf der Sperrliste\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Möchtest du die Tags auf der Sperrliste wirklich löschen?\",\n  \"components.Settings.copyBlocklistedTags\": \"Kopieren von Tags der Sperrliste in die Zwischenablage.\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Nichts zu kopieren\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Kopieren der Konfiguration von Tags auf der Sperrliste\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Konfiguration von Tags auf der Sperrliste importieren\",\n  \"i18n.addToBlocklist\": \"Zur Sperrliste hinzufügen\",\n  \"i18n.blocklist\": \"Sperrliste\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> wurde bereits auf die Sperrliste gesetzt.\",\n  \"i18n.blocklistError\": \"Etwas ist schief gelaufen, versuche es noch einmal.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> wurde erfolgreich auf die Sperrliste gesetzt.\",\n  \"i18n.blocklisted\": \"Gesperrt\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> wurde erfolgreich von der Sperrliste entfernt.\",\n  \"i18n.removefromBlocklist\": \"Von der Sperrliste entfernen\",\n  \"components.PermissionEdit.blocklistedItems\": \"Medien sperren.\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"API-Anfrage-Timeout\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Maximale Wartezeit (in Sekunden) auf Antworten von externen Diensten wie Radarr/Sonarr. Auf 0 setzen für kein Zeitlimit.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Du musst einen gültigen Timeout-Wert angeben\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Neue Staffeln überwachen\",\n  \"components.Discover.timeWindowDay\": \"Täglich\",\n  \"components.Discover.timeWindowWeek\": \"Wöchentlich\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Priorität\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"Es muss eine Priorität zwischen 1 und 5 angegeben werden\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Benutzerdefinierte Kopfzeilen\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Kopfzeile hinzufügen\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Es kann sowohl den Autorisierungsheader als auch den benutzerdefinierten Autorisierungsheader nicht verwendet werden. Bitte entferne einen davon.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Alle Header müssen sowohl einen Namen als auch einen Wert haben\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Kopfzeilenname\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Entfernen\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Benutzerdefinierte HTTP-Header hinzufügen, die in Webhook-Anfragen enthalten sein sollen\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Header-Wert\"\n}\n"
  },
  {
    "path": "src/i18n/locale/el.json",
    "content": "{\n  \"components.PermissionEdit.users\": \"Διαχείριση Χρηστών\",\n  \"components.PermissionEdit.requestTvDescription\": \"Χορήγηση άδειας για υποβολής αιτημάτων σειρών που δεν είναι 4K.\",\n  \"components.PermissionEdit.requestTv\": \"Αιτήματα για Σειρές\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Χορήγηση άδειας για υποβολή αιτημάτων ταινιών που δεν είναι 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Αιτήματα για Ταινίες\",\n  \"components.PermissionEdit.requestDescription\": \"Χορήγηση άδειας για υποβολή αιτημάτων περιεχομένου που δεν είναι 4Κ.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Χορήγηση άδειας για υποβολή αιτημάτων 4K σειρών.\",\n  \"components.PermissionEdit.request4kTv\": \"Αιτήματα για 4K Σειρές\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Χορήγηση άδειας για υποβολή αιτημάτων 4K ταινιών.\",\n  \"components.PermissionEdit.request4kMovies\": \"Αιτήματα για 4K Ταινίες\",\n  \"components.PermissionEdit.request4k\": \"Αίτημα για 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Χορήγηση άδειας για υποβολή αιτημάτων 4Κ περιεχομένου.\",\n  \"components.PermissionEdit.request\": \"Αίτημα\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Χορήγηση άδειας για τη διαχείριση αιτημάτων. Όλα τα αιτήματα που υποβάλλει ένας χρήστης με αυτήν την άδεια θα εγκρίνονται αυτόματα.\",\n  \"components.PermissionEdit.managerequests\": \"Διαχείριση Αιτημάτων\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Εκχώρηση αυτόματης έγκρισης για αιτήματα σειρών που δεν είναι 4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Αυτόματη έγκριση Σειρών\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Εκχώρηση αυτόματης έγκρισης για αιτήματα ταινιών που δεν είναι 4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Αυτόματη έγκριση Ταινιών\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Εκχώρηση αυτόματης έγκρισης για όλα τα αιτήματα που δεν είναι 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Εκχώρηση αυτόματης έγκρισης για αιτήματα σειρών 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Αυτόματη έγκριση Σειρών 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Εκχώρηση αυτόματης έγκρισης για αιτήματα ταινιών 4K.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Αυτόματη Έγκριση Ταινιών 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Εκχώρηση αυτόματης έγκρισης για όλα τα αιτήματα 4K.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Αυτόματη Έγκριση 4K\",\n  \"components.PermissionEdit.autoapprove\": \"Αυτό-Έγκριση\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Εκχώρηση δικαιωμάτων για χρήση των επιλογών αιτημάτων για προχωρημένους.\",\n  \"components.PermissionEdit.advancedrequest\": \"Αιτήματα για Προχωρημένους\",\n  \"components.PermissionEdit.adminDescription\": \"Πλήρης πρόσβαση διαχειριστή. Παρακάμπτει όλους τους άλλους ελέγχους δικαιωμάτων.\",\n  \"components.PermissionEdit.admin\": \"Διαχειριστής\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Τύποι Ειδοποιήσεων\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Αποστολή ειδοποιήσεων όταν έχουν ζητηθεί μέσα και χρειάζονται έγκριση.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Αίτημα σε αναμονή έγκρισης\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Αποστολή ειδοποιήσεων όταν τα αιτούμενα μέσα δεν μπόρεσαν να προστεθούν στο Radarr ή στο Sonarr.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Η επεξεργασία του αιτήματος απέτυχε\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Αποστολή ειδοποιήσεων όταν τα αιτούμενα μέσα γίνονται διαθέσιμα.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Το αίτημα απορρίφθηκε\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Αποστολή ειδοποιήσεων όταν ένα αίτημα μέσου απορρίπτεται.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Αίτημα διαθέσιμο\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Αποστολή ειδοποιήσεων όταν αιτήματα εγκρίνονται χειροκίνητα.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Αποστολή ειδοποιήσεων όταν τα μέσα εγκρίνονται αυτόματα.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Το αίτημα εγκρίθηκε\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Το αίτημα εγκρίθηκε αυτόματα\",\n  \"components.MovieDetails.watchtrailer\": \"Δες το Τρέιλερ\",\n  \"components.MovieDetails.viewfullcrew\": \"Προβολή Πλήρους Συνεργείου\",\n  \"components.MovieDetails.similar\": \"Παρόμοιοι Τίτλοι Ταινιών\",\n  \"components.MovieDetails.runtime\": \"{minutes} λεπτά\",\n  \"components.MovieDetails.revenue\": \"Έσοδα\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Release Date} other {Release Dates}}\",\n  \"components.MovieDetails.recommendations\": \"Προτάσεις\",\n  \"components.MovieDetails.overviewunavailable\": \"Επισκόπηση μη διαθέσιμη.\",\n  \"components.MovieDetails.overview\": \"Επισκόπηση\",\n  \"components.MovieDetails.originaltitle\": \"Αρχικός Τίτλος\",\n  \"components.MovieDetails.originallanguage\": \"Αρχική Γλώσσα\",\n  \"components.MovieDetails.markavailable\": \"Σήμανση ως Διαθέσιμο\",\n  \"components.MovieDetails.mark4kavailable\": \"Σήμανση ως Διαθέσιμο σε 4K\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Όλοι οι Ηθοποιοί\",\n  \"components.MovieDetails.cast\": \"Ηθοποιοί\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Πλήρες Συνεργείο\",\n  \"components.MovieDetails.budget\": \"Προϋπολογισμός\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Δες Περισσότερα\",\n  \"components.Login.validationpasswordrequired\": \"Πρέπει να βάλεις έναν κωδικό πρόσβασης\",\n  \"components.Login.validationemailrequired\": \"Πρέπει να δώσεις μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου\",\n  \"components.Login.signinwithplex\": \"Χρησιμοποίησε τον Plex λογαριασμό σου\",\n  \"components.Login.signinwithoverseerr\": \"Χρησιμοποίησε τον {applicationTitle} λογαριασμό σου\",\n  \"components.Login.signinheader\": \"Συνδέσου για να συνεχίσεις\",\n  \"components.Login.signingin\": \"Συνδέεται …\",\n  \"components.Login.signin\": \"Σύνδεση\",\n  \"components.Login.password\": \"Κωδικός πρόσβασης\",\n  \"components.Login.loginerror\": \"Κάτι πήγε στραβά κατά την προσπάθεια σύνδεσης.\",\n  \"components.Login.forgotpassword\": \"Ξέχασες τον κωδικό πρόσβασης;\",\n  \"components.Login.email\": \"Διεύθυνση ηλεκτρονικού ταχυδρομείου\",\n  \"components.Layout.VersionStatus.streamstable\": \"Overseer Σταθερή Έκδοση\",\n  \"components.Discover.popularmovies\": \"Δημοφιλείς Ταινίες\",\n  \"components.Discover.discover\": \"Ανακάλυψε\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Είδη Σειρών\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Είδη Σειρών\",\n  \"components.Discover.StudioSlider.studios\": \"Στούντιο\",\n  \"components.Discover.NetworkSlider.networks\": \"Δίκτυα\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Είδη Tαινιών\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Είδη Tαινιών\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Σειρά\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Σειρά\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} Ταινίες\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} Σειρά\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Ταινίες\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} Ταινίες\",\n  \"components.CollectionDetails.requestcollection4k\": \"Αίτημα Συλλογής σε 4K\",\n  \"components.CollectionDetails.requestcollection\": \"Αίτημα Συλλογής\",\n  \"components.CollectionDetails.overview\": \"Επισκόπηση\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Ταινίες\",\n  \"pages.somethingwentwrong\": \"Κάτι πήγε στραβά\",\n  \"components.Layout.UserDropdown.signout\": \"Αποσύνδεση\",\n  \"components.Layout.UserDropdown.settings\": \"Ρυθμίσεις\",\n  \"components.Layout.UserDropdown.myprofile\": \"Προφίλ\",\n  \"components.Layout.Sidebar.users\": \"Χρήστες\",\n  \"components.Layout.Sidebar.settings\": \"Ρυθμίσεις\",\n  \"components.Layout.Sidebar.requests\": \"Αιτήματα\",\n  \"components.Layout.Sidebar.dashboard\": \"Ανακαλύψτε\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Αναζήτηση Ταινιών και Τηλεοπτικών Σειρών\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Όλες οι Γλώσσες\",\n  \"components.LanguageSelector.languageServerDefault\": \"Προεπιλεγμένη ({language})\",\n  \"components.DownloadBlock.estimatedtime\": \"Εκτιμώμενος {time}\",\n  \"components.Discover.upcomingtv\": \"Επερχόμενες Σειρές\",\n  \"components.Discover.upcomingmovies\": \"Επερχόμενες Ταινίες\",\n  \"components.Discover.upcoming\": \"Επερχόμενες Ταινίες\",\n  \"components.Discover.trending\": \"Τάσεις\",\n  \"components.Discover.recentrequests\": \"Πρόσφατα Αιτήματα\",\n  \"components.Discover.recentlyAdded\": \"Προστέθηκαν πρόσφατα\",\n  \"components.Discover.populartv\": \"Δημοφιλείς Σειρές\",\n  \"components.Search.searchresults\": \"Αποτελέσματα αναζήτησης\",\n  \"components.Search.search\": \"Αναζήτηση\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Πρέπει να βάλεις έναν κωδικό πρόσβασης\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Ο κωδικός πρόσβασης είναι πολύ σύντομος- θα πρέπει να αποτελείται από τουλάχιστον 8 χαρακτήρες\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Οι κωδικοί πρόσβασης πρέπει να ταιριάζουν\",\n  \"components.ResetPassword.validationemailrequired\": \"Πρέπει να δώσεις μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Η επαναφορά κωδικού πρόσβασης ολοκληρώθηκε με επιτυχία!\",\n  \"components.ResetPassword.resetpassword\": \"Επαναφορά του κωδικού πρόσβασής σου\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Ένας σύνδεσμος επαναφοράς κωδικού πρόσβασης θα αποσταλεί στην παρεχόμενη διεύθυνση ηλεκτρονικού ταχυδρομείου, εάν αυτή σχετίζεται με έγκυρο χρήστη.\",\n  \"components.ResetPassword.passwordreset\": \"Επαναφορά κωδικού\",\n  \"components.ResetPassword.password\": \"Κωδικός πρόσβασης\",\n  \"components.ResetPassword.gobacklogin\": \"Επιστροφή στη σελίδα Εισόδου\",\n  \"components.ResetPassword.emailresetlink\": \"Αποστολή συνδέσμου ανάκτησης με email\",\n  \"components.ResetPassword.email\": \"Διεύθυνση ηλεκτρονικού ταχυδρομείου\",\n  \"components.ResetPassword.confirmpassword\": \"Επιβεβαίωση κωδικού πρόσβασης\",\n  \"components.RequestModal.selectseason\": \"Επιλογή Σεζόν\",\n  \"components.RequestModal.seasonnumber\": \"Σεζόν {number}\",\n  \"components.RequestModal.season\": \"Σεζόν\",\n  \"components.RequestModal.requestseasons\": \"Ζήτα {seasonCount} {seasonCount, plural, one {Σεζόν} other {Σεζόν}}\",\n  \"components.RequestModal.requestfrom\": \"Το αίτημα του/της {username} εκκρεμεί προς έγκριση.\",\n  \"components.RequestModal.requesterror\": \"Κάτι πήγε στραβά κατά την υποβολή του αιτήματος.\",\n  \"components.RequestModal.requestedited\": \"Το αίτημα για <strong>{title}</strong> επεξεργάστηκε με επιτυχία!\",\n  \"components.RequestModal.requestcancelled\": \"Το αίτημα για <strong>{title}</strong> ακυρώθηκε.\",\n  \"components.RequestModal.requestadmin\": \"Αυτό το αίτημα θα εγκριθεί αυτόματα.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> ζητήθηκε επιτυχώς!\",\n  \"components.RequestModal.requestCancel\": \"Το αίτημα για <strong>{title}</strong> ακυρώθηκε.\",\n  \"components.RequestModal.pendingrequest\": \"Εκκρεμές αίτημα\",\n  \"components.RequestModal.pendingapproval\": \"Το αίτημα σου εκκρεμεί προς έγκριση.\",\n  \"components.RequestModal.pending4krequest\": \"Εκκρεμές αίτημα 4K\",\n  \"components.RequestModal.errorediting\": \"Κάτι πήγε στραβά κατά την επεξεργασία του αιτήματος.\",\n  \"components.RequestModal.edit\": \"Επεξεργασία Αιτήματος\",\n  \"components.RequestModal.cancel\": \"Ακύρωση Αιτήματος\",\n  \"components.RequestModal.autoapproval\": \"Αυτόματη Έγκριση\",\n  \"components.RequestModal.alreadyrequested\": \"Έχει ήδη ζητηθεί\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Δεν μπορέσαμε να αντιστοιχίσουμε αυτόματα αυτή τη σειρά. Παρακαλώ επίλεξε τη σωστή αντιστοιχία παρακάτω.\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {σεζόν} other {σεζόν}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"σεζόν\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Αυτός ο χρήστης χρειάζεται τουλάχιστον <strong>{seasons}</strong> {seasons, plural, one {αίτημα σεζόν} other {αιτήματα σεζόν}} απομένουν έτσι ώστε να γίνει αίτημα για αυτή τη σειρά.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Πρέπει να έχεις τουλάχιστον <strong>(seasons)</strong> {seasons, plural, one {αίτημα σεζόν} other {αιτήματα σεζόν}} απομένουν έτσι ώστε να γίνει υποβολή αιτήματος για αυτή τη σειρά.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Κανένα} other {<strong>#</strong>}} {type} {remaining, plural, one {αίτημα} other {αιτήματα}} απομένουν\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Μπορείς να δείς την σύνοψη των ορίων των αιτημάτων του χρήστη στη <ProfileLink> σελίδα προφίλ του</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Μπορείς να δεις μια σύνοψη των ορίων των αιτημάτων σου στη <ProfileLink> σελίδα προφίλ σου </ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Δεν απομένουν άλλα αιτήματα για σεζόν\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {ταινία} other {ταινίες}}\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Προεπιλογή)\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Σεζόν} other {Σεζόν(πλυθ.)}}\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} από {user}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Σεζόν} other {Σεζόν(πλυθ.)}}\",\n  \"components.RequestButton.declinerequests\": \"Απόρριψη {requestCount, plural, one {Αίτημα} other {{requestCount} Αιτήματα}}\",\n  \"components.RequestButton.decline4krequests\": \"Απόρριψη {requestCount, plural, one {4K Αίτημα} other {{requestCount} 4K Αιτήματα}}\",\n  \"components.RequestButton.approverequests\": \"Έγκριση {requestCount, plural, one {Αίτημα} other {{requestCount} Αιτήματα}}\",\n  \"components.RequestButton.approve4krequests\": \"Έγκριση {requestCount, plural, one {4K Αίτημα} other {{requestCount} 4K Αιτήματα}}\",\n  \"components.RequestBlock.server\": \"Προοριζόμενος Διακομιστής\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Σεζόν} other {Σεζόν(πλυθ.)}}\",\n  \"components.RequestBlock.rootfolder\": \"Ριζικός φάκελος\",\n  \"components.RegionSelector.regionServerDefault\": \"Προεπιλογή ({region})\",\n  \"components.QuotaSelector.unlimited\": \"Απεριόριστο\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Γεννήθηκε {birthdate}\",\n  \"components.PersonDetails.ascharacter\": \"ως {character}\",\n  \"components.PermissionEdit.usersDescription\": \"Χορήγηση άδειας για διαχείρηση των χρηστών. Οι χρήστες με αυτή την άδεια δεν μπορούν να τροποποιήσουν τους χρήστες με το προνόμιο του διαχειριστή ή να κάνουν κάποιον διαχειριστή.\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Develop\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Η <code>{appDataPath}</code> προσάρτηση τόμου δεν έχει ρυθμιστεί σωστά. Όλα τα δεδομένα θα διαγραφούν όταν ο περιέχοντας σταματήσει ή επανεκκινήσει.\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Ριζικός φάκελος\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"ταινία\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Αυτός ο χρήστης επιτρέπεται να ζητάει <strong>{limit}</strong> {type} κάθε <strong>{days}</strong> ημέρες.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Επιτρέπεται να ζητήσεις <strong>{limit}</strong> {type} κάθε <strong>{days}</strong> ημέρες.\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Ετικέτες\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Επιλογή ετικετών\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Αίτημα ως\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Προφίλ Ποιότητας\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Δεν υπάρχουν ετικέτες.\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Προφίλ Γλώσσας\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Προορισμός Διακομιστή\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Αυτή η σειρά είναι anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Για προχωρημένους\",\n  \"components.RequestList.sortModified\": \"Τελευταία Τροποποίηση\",\n  \"components.RequestList.sortAdded\": \"Πιο πρόσφατα\",\n  \"components.RequestList.showallrequests\": \"Εμφάνιση Όλων των Αιτημάτων\",\n  \"components.RequestList.requests\": \"Αιτήματα\",\n  \"components.RequestList.RequestItem.requested\": \"Ζητήθηκε\",\n  \"components.RequestList.RequestItem.modified\": \"Τροποποιήθηκε\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} Δε βρέθηκε\",\n  \"components.RequestList.RequestItem.failedretry\": \"Κάτι πήγε στραβά κατά την επανάληψη του αιτήματος.\",\n  \"components.RequestList.RequestItem.editrequest\": \"Επεξεργασία Αιτήματος\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Διαγραφή Αιτήματος\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Ακύρωση Αιτήματος\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} Δε βρέθηκε\",\n  \"components.RequestCard.deleterequest\": \"Διαγραφή Αιτήματος\",\n  \"components.RequestButton.viewrequest4k\": \"Προβολή 4K Αιτήματος\",\n  \"components.RequestButton.viewrequest\": \"Προβολή Αιτήματος\",\n  \"components.RequestButton.requestmore4k\": \"Ζήτα περισσότερα σε 4K\",\n  \"components.RequestButton.requestmore\": \"Ζήτα Περισσότερα\",\n  \"components.RequestButton.declinerequest4k\": \"Απόρριψη 4K Αιτήματος\",\n  \"components.RequestButton.declinerequest\": \"Απόρριψη Αιτήματος\",\n  \"components.RequestButton.approverequest4k\": \"Έγκριση 4K Αιτήματος\",\n  \"components.RequestButton.approverequest\": \"Έγκριση Αιτήματος\",\n  \"components.RequestBlock.requestoverrides\": \"Παρακάμψεις των Αιτημάτων\",\n  \"components.RequestBlock.profilechanged\": \"Προφίλ Ποιότητας\",\n  \"components.RegionSelector.regionDefault\": \"Όλες οι Περιοχές\",\n  \"components.PersonDetails.crewmember\": \"Συνεργείο\",\n  \"components.PersonDetails.appearsin\": \"Εμφανίσεις\",\n  \"components.PersonDetails.alsoknownas\": \"Επίσης Γνωστός/ή ως: {names}\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Χορήγηση άδειας προβολής αιτημάτων που υποβλήθηκαν από άλλους χρήστες.\",\n  \"components.PermissionEdit.viewrequests\": \"Προβολή Αιτημάτων\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Πρέπει να δώσεις ένα έγκυρο αναγνωριστικό συνομιλίας\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Πρέπει να δώσεις μια άδεια εξουσιοδότησης bot\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Η δοκιμαστική ειδοποίηση Telegram εστάλη!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Γίνεται αποστολή δοκιμαστικής ειδοποίησης Telegram…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Η δοκιμαστική ειδοποίηση Telegram δεν κατάφερε να σταλεί.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Η δοκιμαστική ειδοποίηση email εστάλη!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Γίνεται αποστολή δοκιμαστικής ειδοποίησης email…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Η δοκιμαστική ειδοποίηση email δεν κατάφερε να σταλεί.\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Η δοκιμαστική ειδοποίηση Discord εστάλη!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Η δοκιμαστική ειδοποίηση Slack εστάλη!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Γίνεται αποστολή δοκιμαστικής ειδοποίησης Slack…\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Γίνεται αποστολή δοκιμαστικής ειδοποίησης Discord…\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Η δοκιμαστική ειδοποίηση Discord δεν κατάφερε να σταλεί.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Οι ρυθμίσεις των ειδοποιήσεων Telegram αποθηκεύτηκαν επιτυχώς!\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων Telegram δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.Settings.Notifications.smtpPort\": \"Θύρα SMTP\",\n  \"components.Settings.Notifications.smtpHost\": \"Κεντρικός υπολογιστής SMTP\",\n  \"components.Settings.Notifications.senderName\": \"Όνομα αποστολέα\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Στείλε ειδοποιήσεις χωρίς ήχο\",\n  \"components.Settings.Notifications.sendSilently\": \"Αθόρυβη Αποστολή\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Υπογραφή κρυπτογραφημένων μηνυμάτων email χρησιμοποιώντας <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Ιδιωτικό κλειδί PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Υπογραφή κρυπτογραφημένων μηνυμάτων email χρησιμοποιώντας <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPassword\": \"Κωδικός πρόσβασης PGP\",\n  \"components.Settings.Notifications.encryptionTip\": \"Στις περισσότερες περιπτώσεις, το Implicit TLS χρησιμοποιεί τη θύρα 465 και το STARTTLS τη θύρα 587\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Να χρησιμοποιείς πάντα το STARTTLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"Καμιά\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Χρήση Implicit TLS\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Χρήση STARTTLS αν υπάρχει\",\n  \"components.Settings.Notifications.encryption\": \"Μέθοδος κρυπτογράφησης\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Οι ρυθμίσεις των ειδοποιήσεων για το email αποθηκεύτηκαν επιτυχώς!\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων για το email δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.Settings.Notifications.emailsender\": \"Διεύθυνση αποστολέα\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Οι ρυθμίσεις των ειδοποιήσεων Discord αποθηκεύτηκαν επιτυχώς!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων Discord δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.Settings.Notifications.chatIdTip\": \"Ξεκίνα μια συνομιλία με το bot σου, πρόσθεσε <GetIdBotLink>@get_id_bot</GetIdBotLink>, και έκδωσε την εντολή <code>/my_id</code>\",\n  \"components.Settings.Notifications.chatId\": \"Αναγνωριστικό συνομιλίας\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Επίτρεψε στους χρήστες να ξεκινήσουν επίσης μια συνομιλία με το bot σου και να ρυθμίσουν τις δικές τους ειδοποιήσεις\",\n  \"components.Settings.Notifications.botUsername\": \"Όνομα χρήστη Bot\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Σύνδεσμος για το Avatar του Bot\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Δημιουργία bot</CreateBotLink> για χρήση με Seerr\",\n  \"components.Settings.Notifications.botAPI\": \"Διακριτικό εξουσιοδότησης Bot\",\n  \"components.Settings.Notifications.authUser\": \"Όνομα χρήστη SMTP\",\n  \"components.Settings.Notifications.authPass\": \"Κωδικός πρόσβασης SMTP\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Επίτρεψε Αυτο-Υπογεγραμμένα Πιστοποιητικά\",\n  \"components.Settings.Notifications.agentenabled\": \"Ενεργοποίηση του Μεταφορέα\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Οι ρυθμίσεις των ειδοποιήσεων Webhook αποθηκεύτηκαν με επιτυχία!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων Slack δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Οι ρυθμίσεις των ειδοποιήσεων Pushover αποθηκεύτηκαν επιτυχώς!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων Pushover δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Οι ρυθμίσεις των ειδοποιήσεων Pushbullet δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων Webhook δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Πρέπει να βάλεις μια έγκυρη διεύθυνση URL\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Πρέπει να βάλεις μια έγκυρη διεύθυνση URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Πρέπει να βάλεις ένα έγκυρο φορτίο πληροφοριών JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Η δοκιμαστική ειδοποίηση webhook εστάλη!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Αποστολή δοκιμαστικής ειδοποίησης webhook…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Η δοκιμαστική ειδοποίηση webhook δεν κατάφερε να σταλεί.\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"Η επαναφορά του φορτίου πληροφοριών Jason ολοκληρώθηκε με επιτυχία!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Επαναφορά προεπιλογών\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON Φορτίο Πληροφοριών\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Κεφαλίδα Εξουσιοδότησης\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Ενεργοποίηση του Μεταφορέα\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Οι ρυθμίσεις των ειδοποιήσεων push αποθηκεύτηκαν επιτυχώς!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων push δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Η δοκιμαστική ειδοποίηση push εστάλη!\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Για να λάβεις ειδοποιήσεις push, το Seerr πρέπει να προβάλλεται μέσω HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Η δοκιμαστική ειδοποιήση push δεν κατάφερε να σταλεί.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Αποστολή δοκιμαστικής ειδοποίησης push…\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Ενεργοποίηση του Μεταφορέα\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Δημιούργησε ένα <WebhookLink> Εισερχόμενο Webhook</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Αποτυχία αποστολής δοκιμαστικής ειδοποίησης Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Οι ρυθμίσεις ειδοποιήσεων Slack αποθηκεύτηκαν με επιτυχία!\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Ενεργοποίηση του Μεταφορέα\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Πρέπει να δώσετε ένα έγκυρο κλειδί χρήστη ή ομάδας\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Πρέπει να δώσεις ένα έγκυρο διακριτικό εφαρμογής\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"<UsersGroupsLink>Το αναγνωριστικό χρήστη ή ομάδας 30 χαρακτήρων</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Κλειδί Χρήστη ή Ομάδας\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Η δοκιμαστική ειδοποίηση Pushover εστάλη!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Η δοκιμαστική ειδοποίηση Pushbullet εστάλη!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Αποστολή δοκιμαστικής ειδοποίησης Pushbullet …\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Αποστολή δοκιμαστικής ειδοποίησης Pushover …\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Αποτυχία αποστολής δοκιμαστικής ειδοποιήσης Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Αποτυχία αποστολής δοκιμαστικής ειδοποίησης Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Ενεργοποίηση του Μεταφορέα\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Καταχώρηση εφαρμογής</ApplicationRegistrationLink> για χρήση με Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Διακριτικό API Εφαρμογής\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Πρέπει να δώσεις ένα διακριτικό πρόσβασης\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Οι ρυθμίσεις για τις ειδοποιήσεις Pushbullet αποθηκεύτηκαν με επιτυχία!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Ενεργοποίηση του Μεταφορέα\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Δημιουργία διακριτικού πρόσβασης από <PushbulletSettingsLink>τις Ρυθμίσεις Λογαρισμού</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Διακριτικό πρόσβασης\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Προσθήκη νέου διακομιστή 4K Radarr\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Βασική Διεύθυνση URL\",\n  \"components.Settings.RadarrModal.apiKey\": \"Κλειδί API\",\n  \"components.Settings.RadarrModal.add\": \"Προσθήκη διακομιστή\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Δημιουργία ενός <DiscordWebhookLink>webhook integration</DiscordWebhookLink> στον σέρβερ σου\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.validationUrl\": \"Πρέπει να βάλεις μια έγκυρη διεύθυνση URL\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Πρέπει να δώσεις έναν έγκυρο αριθμό θύρας\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Πρέπει να δώσεις ένα έγκυρο όνομα κεντρικού υπολογιστή ή διεύθυνση IP\",\n  \"components.Settings.validationHostnameRequired\": \"Πρέπει να δώσεις ένα έγκυρο όνομα κεντρικού υπολογιστή ή διεύθυνση IP\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Πρέπει να δώσετε ένα έγκυρο ιδιωτικό κλειδί PGP\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Πρέπει να δώσετε έναν κωδικό πρόσβασης PGP\",\n  \"components.Settings.Notifications.validationEmail\": \"Πρέπει να δώσεις μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Καθολικό όριο αιτημάτων στις Ταινίες\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Ενεργοποίηση τοπικής σύνδεσης\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Προεπιλεγμένα δικαιώματα\",\n  \"components.Settings.SettingsLogs.time\": \"Χρονική σήμανση\",\n  \"components.Settings.SettingsLogs.showall\": \"Εμφάνιση όλων των αρχείων καταγραφής\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Συνέχιση\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Παύση\",\n  \"components.Settings.SettingsLogs.message\": \"Μήνυμα\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Μπορείτε επίσης να δείτε αυτά τα αρχεία καταγραφής απευθείας μέσω του <code>stdout</code> ή στο <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.logs\": \"Αρχεία καταγραφής\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Λεπτομέρειες αρχείου καταγραφής\",\n  \"components.Settings.SettingsLogs.level\": \"Σοβαρότητα\",\n  \"components.Settings.SettingsLogs.label\": \"Ετικέτα\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Προσοχή\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Πληροφορίες\",\n  \"components.Settings.SettingsLogs.filterError\": \"Σφάλμα\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Εντοπισμός σφαλμάτων\",\n  \"components.Settings.SettingsLogs.extraData\": \"Επιπρόσθετα Δεδομένα\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Αντιγραφή στο Πρόχειρο\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Αντιγράφηκε το μήνυμα καταγραφής στο πρόχειρο.\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Άγνωστη εργασία\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Σάρωση Sonarr\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Τρέξε τώρα\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Σάρωση Radarr\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Εργασίες & Κρυφή μνήμη\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Εργασίες\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Όνομα εργασίας\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Ακύρωση Εργασίας\",\n  \"components.Settings.SettingsJobsCache.process\": \"Διεργασία\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Σάρωση Plex για μέσα που προστέθηκαν πρόσφατα\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Σάρωση πλήρους βιβλιοθήκης Plex\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Σάρωση πλήρους βιβλιοθήκης Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Σάρωση Jellyfin για μέσα που προστέθηκαν πρόσφατα\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Επόμενη εκτέλεση\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Είδος\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} ξεκίνησε.\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} ακυρώθηκε.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Εκκαθάριση κρυφής μνήμης\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Επαναρύθμιση Λήψης Συγχρονισμού\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Λήψη συγχρονισμού\",\n  \"components.Settings.SettingsJobsCache.command\": \"Εντολή\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Μέγεθος\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Όνομα κρυφής μνήμης\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Χαμένες\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Μέγεθος κλειδιού\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Σύνολο κλειδιών\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Κλήσεις\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} εκκαθαρίστηκε η κρυφή μνήμη.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Το Seerr αποθηκεύει προσωρινά αιτήματα σε εξωτερικά τελικά σημεία API για τη βελτιστοποίηση της απόδοσης και την αποφυγή περιττών κλήσεων API.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Κρυφή μνήμη\",\n  \"components.Settings.SettingsAbout.version\": \"Έκδοση\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Εκδόσεις\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Τα δεδομένα έκδοσης δεν είναι διαθέσιμα αυτή τη στιγμή.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Πιο πρόσφατη\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Τρέχουσα\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Πρέπει να επιλέξεις ένα ριζικό φάκελο\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Πρέπει να επιλέξεις ένα προφίλ ποιότητας\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Πρέπει να δώσεις έναν έγκυρο αριθμό θύρας\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Πρέπει να δώσεις ένα όνομα διακομιστή\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Πρέπει να επιλέξεις μια ελάχιστη διαθεσιμότητα\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Πρέπει να δώσετε ένα έγκυρο όνομα κεντρικού υπολογιστή ή διεύθυνση IP\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Η βάση URL δεν πρέπει να τελειώνει με κάθετο\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Η βάση URL πρέπει να έχει μια κάθετο μπροστά\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"Η διεύθυνση URL δεν πρέπει να τελειώνει με κάθετο\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Πρέπει να βάλεις μια έγκυρη διεύθυνση URL\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Πρέπει να βάλεις ένα κλειδί API\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Η σύνδεση με το Radarr ολοκληρώθηκε με επιτυχία!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Αποτυχία σύνδεσης με το Radarr.\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Δοκιμή σύνδεσης για την φόρτωση των ετικετών\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Δοκιμή σύνδεσης για την φόρτωση των προφίλ ποιότητας\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Δοκιμή σύνδεσης για την φόρτωση των ριζικών φακέλων\",\n  \"components.Settings.RadarrModal.tags\": \"Ετικέτες\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Ενεργοποίηση σάρωσης\",\n  \"components.Settings.RadarrModal.ssl\": \"Χρήση SSL\",\n  \"components.Settings.RadarrModal.servername\": \"Όνομα διακομιστή\",\n  \"components.Settings.RadarrModal.server4k\": \"Διακομιστής 4K\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Ριζικός φάκελος\",\n  \"components.Settings.RadarrModal.selecttags\": \"Επιλογή ετικετών\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Επίλεξε ριζικό φάκελο\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Επίλεξε προφίλ ποιότητας\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Επιλογή ελάχιστης διαθεσιμότητας\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Προφίλ Ποιότητας\",\n  \"components.Settings.RadarrModal.port\": \"Θύρα\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Δεν υπάρχουν ετικέτες.\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Ελάχιστη διαθεσιμότητα\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Φόρτωση ριζικών φακέλων…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Φόρτωση των προφίλ ποιότητας…\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Φόρτωση ετικετών…\",\n  \"components.Settings.RadarrModal.hostname\": \"Όνομα κεντρικού υπολογιστή ή διεύθυνση IP\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Εξωτερική διεύθυνση URL\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Ενεργοποίηση αυτόματης αναζήτησης\",\n  \"components.Settings.RadarrModal.editradarr\": \"Επεξεργασία διακομιστή Radarr\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Επεξεργασία διακομιστή 4K Radarr\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Προεπιλεγμένος διακομιστής\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Προεπιλεγμένος διακομιστής 4K\",\n  \"components.Settings.RadarrModal.createradarr\": \"Προσθήκη νέου διακομιστή Radarr\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Ενημερωμένο\",\n  \"components.Layout.VersionStatus.outofdate\": \"Ξεπερασμένο\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Ξεπερασμένο\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Σύνολο αιτημάτων\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Σύνολο μέσων\",\n  \"components.Settings.SettingsAbout.timezone\": \"Ζώνη ώρας\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Συζητήσεις στο GitHub\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Λήψη Υποστήριξης\",\n  \"components.Settings.SettingsAbout.documentation\": \"Εγχειρίδιο\",\n  \"components.Settings.SettingsAbout.about\": \"Σχετικά\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Προβολή στο GitHub\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Αλλαγές\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Προβολή καταλόγου με τις αλλαγές\",\n  \"i18n.settings\": \"Ρυθμίσεις\",\n  \"i18n.saving\": \"Αποθηκεύεται…\",\n  \"i18n.save\": \"Αποθήκευση αλλαγών\",\n  \"i18n.retrying\": \"Γίνεται επαναπροσπάθεια…\",\n  \"i18n.retry\": \"Δοκίμασε ξανά\",\n  \"i18n.resultsperpage\": \"Εμφάνιση {pageSize} αποτελεσμάτων ανά σελίδα\",\n  \"i18n.requesting\": \"Γίνεται το αίτημα…\",\n  \"i18n.requested\": \"Ζητήθηκε\",\n  \"i18n.request4k\": \"Ζήτα το σε 4K\",\n  \"i18n.request\": \"Ζήτα το\",\n  \"i18n.processing\": \"Επεξεργάζεται\",\n  \"i18n.previous\": \"Προηγούμενο\",\n  \"i18n.pending\": \"Εκκρεμεί\",\n  \"i18n.partiallyavailable\": \"Μερικώς Διαθέσιμο\",\n  \"i18n.notrequested\": \"Δεν έχει ζητηθεί\",\n  \"i18n.noresults\": \"Δεν υπάρχουν αποτελέσματα.\",\n  \"i18n.next\": \"Επόμενο\",\n  \"i18n.movies\": \"Ταινίες\",\n  \"i18n.movie\": \"Ταινία\",\n  \"i18n.loading\": \"Φόρτωση…\",\n  \"i18n.failed\": \"Απέτυχε\",\n  \"i18n.experimental\": \"Πειραματικό\",\n  \"i18n.edit\": \"Επεξεργασία\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.deleting\": \"Διαγράφεται…\",\n  \"i18n.delete\": \"Διαγραφή\",\n  \"i18n.declined\": \"Απορρίφθηκε\",\n  \"i18n.decline\": \"Απόρριψη\",\n  \"i18n.close\": \"Κλείσιμο\",\n  \"i18n.canceling\": \"Ακυρώνεται…\",\n  \"i18n.cancel\": \"Ακύρωση\",\n  \"i18n.back\": \"Πίσω\",\n  \"i18n.available\": \"Διαθέσιμο\",\n  \"i18n.areyousure\": \"Είσαι σίγουρος;\",\n  \"i18n.approved\": \"Εγκρίθηκε\",\n  \"i18n.approve\": \"Έγκριση\",\n  \"i18n.all\": \"Όλα\",\n  \"i18n.advanced\": \"Για προχωρημένους\",\n  \"components.UserProfile.unlimited\": \"Απεριόριστο\",\n  \"components.UserProfile.totalrequests\": \"Σύνολο αιτημάτων\",\n  \"components.UserProfile.seriesrequest\": \"Αιτήματα Σειρών\",\n  \"components.UserProfile.requestsperdays\": \"Απομένει {limit}\",\n  \"components.UserProfile.recentrequests\": \"Πρόσφατα Αιτήματα\",\n  \"components.UserProfile.pastdays\": \"{type} (περασμένες {days} ημέρες)\",\n  \"components.UserProfile.movierequests\": \"Αιτήματα Ταινιών\",\n  \"components.UserProfile.limit\": \"{remaining} από {limit}\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Δεν έχεις άδεια να τροποποιήσεις τον κωδικό πρόσβασης αυτού του χρήστη.\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Δεν έχεις άδεια να τροποποιήσεις τις ρυθμίσεις αυτού του χρήστη.\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Άδειες\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Ειδοποιήσεις\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Γενικές\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Κωδικός πρόσβασης\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Δεν μπορείς να τροποποιήσεις τις δικές σου άδειες.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Οι άδειες αποθηκεύτηκαν με επιτυχία!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Κάτι πήγε στραβά κατά την αποθήκευση των ρυθμίσεων.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Άδειες\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Ο κωδικός πρόσβασης είναι πολύ σύντομος- θα πρέπει να αποτελείται από τουλάχιστον 8 χαρακτήρες\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Πρέπει να βάλεις έναν νέο κωδικό πρόσβασης\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Πρέπει να δώσεις τον τρέχοντα κωδικό πρόσβασής σου\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Οι κωδικοί πρόσβασης πρέπει να ταιριάζουν\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Πρέπει να επιβεβαιώσεις τον νέο κωδικό πρόσβασης\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Ο κωδικός πρόσβασης αποθηκεύτηκε με επιτυχία!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Κάτι πήγε στραβά κατά την αποθήκευση του κωδικού πρόσβασης. Εισήχθη σωστά ο τρέχων κωδικός πρόσβασης;\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Κάτι πήγε στραβά κατά την αποθήκευση του κωδικού πρόσβασης.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Κωδικός πρόσβασης\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Ο λογαριασμός σου προς το παρόν δεν έχει ορίσει κωδικός πρόσβασης. Διαμόρφωσε έναν κωδικό πρόσβασης παρακάτω για να μπορέσεις να συνδεθείς ως \\\"τοπικός χρήστης\\\" χρησιμοποιώντας τη διεύθυνση ηλεκτρονικού ταχυδρομείου σου.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Αυτός ο λογαριασμός χρήστη δεν έχει ορίσει έναν κωδικό πρόσβασης. Διαμόρφωσε έναν κωδικό πρόσβασης παρακάτω για να μπορέσει αυτός ο λογαριασμός να συνδεθεί ως \\\"τοπικός χρήστης\\\".\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Νέος κωδικός πρόσβασης\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Τρέχων κωδικός πρόσβασης\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Επιβεβαίωση κωδικού πρόσβασης\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Πρέπει να δώσεις ένα έγκυρο αναγνωριστικό συνομιλίας\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Πρέπει να βάλεις ένα έγκυρο δημόσιο κλειδί PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Πρέπει να δώσεις ένα έγκυρο αναγνωριστικό χρήστη\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Οι ρυθμίσεις των ειδοποιήσεων Telegram αποθηκεύτηκαν επιτυχώς!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων Telegram δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Ξεκίνα μια συνομιλία</TelegramBotLink>, πρόσθεσε το <GetIdBotLink>@get_id_bot</GetIdBotLink> και δώσε την εντολή <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Αναγνωριστικό συνομιλίας\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Στείλε ειδοποιήσεις χωρίς ήχο\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Αθόρυβη Αποστολή\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Κρυπτογράφηση μηνυμάτων ηλεκτρονικού ταχυδρομείου χρησιμοποιώντας <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Δημόσιο κλειδί PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Ρυθμίσεις ειδοποιήσεων\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Ειδοποιήσεις\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Οι ρυθμίσεις των ειδοποιήσεων για το email αποθηκεύτηκαν επιτυχώς!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων για το email δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Οι ρυθμίσεις των ειδοποιήσεων Discord αποθηκεύτηκαν επιτυχώς!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Οι ρυθμίσεις των ειδοποιήσεων Discord δεν κατάφεραν να αποθηκευτούν.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"Ο <FindDiscordIdLink>multi-digit ID αριθμός</FindDiscordIdLink> που σχετίζεται με τον λογαριασμό σας\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Αναγνωριστικό χρήστη\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Χρήστης\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Οι ρυθμίσεις αποθηκεύτηκαν με επιτυχία!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Κάτι πήγε στραβά κατά την αποθήκευση των ρυθμίσεων.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Όριο Αιτημάτων Σειρών\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Ρόλος\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Φιλτράρει το περιεχόμενο βάσει της διαθεσιμότητας του περιεχομένου\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Ανακάλυψη βάσει περιοχής\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Χρήστης Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Ιδιοκτήτης\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Φίλτραρε το περιεχόμενο με βάση την αρχική γλώσσα\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Ανακάλυψη με βάση την γλώσσα\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Όριο Αιτημάτων Ταινιών\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Τοπικός χρήστης\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Προεπιλεγμένη ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Γενικές Ρυθμίσεις\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Γενικές\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Παράκαμψη καθολικού ορίου\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Εμφανιζόμενο όνομα\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Προβολή Γλώσσας\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Διαχειριστής\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Τύπος Λογαριασμού\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Αναγνωριστικό χρήστη: {userid}\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Επεξεργασία ρυθμίσεων\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Προβολή προφίλ\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Έγινε μέλος {joindate}\",\n  \"components.UserList.validationpasswordminchars\": \"Ο κωδικός πρόσβασης είναι πολύ σύντομος- θα πρέπει να αποτελείται από τουλάχιστον 8 χαρακτήρες\",\n  \"components.UserList.validationEmail\": \"Πρέπει να δώσεις μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου\",\n  \"components.UserList.userssaved\": \"Τα δικαιώματα χρήστη αποθηκεύτηκαν με επιτυχία!\",\n  \"components.UserList.users\": \"Χρήστες\",\n  \"components.UserList.userlist\": \"Λίστα χρηστών\",\n  \"components.UserList.userfail\": \"Κάτι πήγε στραβά κατά την αποθήκευση των δικαιωμάτων του χρήστη.\",\n  \"components.UserList.userdeleteerror\": \"Κάτι πήγε στραβά κατά τη διαγραφή του χρήστη.\",\n  \"components.UserList.userdeleted\": \"Ο χρήστης διαγράφηκε επιτυχώς!\",\n  \"components.UserList.usercreatedsuccess\": \"Ο χρήστης δημιουργήθηκε με επιτυχία!\",\n  \"components.UserList.usercreatedfailedexisting\": \"Η παρεχόμενη διεύθυνση email χρησιμοποιείται ήδη από άλλο χρήστη.\",\n  \"components.UserList.usercreatedfailed\": \"Κάτι πήγε στραβά κατά τη δημιουργία του χρήστη.\",\n  \"components.UserList.user\": \"Χρήστης\",\n  \"components.UserList.totalrequests\": \"Αιτήματα\",\n  \"components.UserList.sortRequests\": \"Αριθμός αιτημάτων\",\n  \"components.UserList.sortDisplayName\": \"Εμφανιζόμενο όνομα\",\n  \"components.UserList.sortCreated\": \"Ημερομηνία που έγινε μέλος\",\n  \"components.UserList.role\": \"Ρόλος\",\n  \"components.UserList.plexuser\": \"Χρήστης Plex\",\n  \"components.UserList.passwordinfodescription\": \"Ορίστε ένα URL εφαρμογής και ενεργοποιήστε τις ειδοποιήσεις με email για να επιτρέψετε την αυτόματη δημιουργία κωδικού.\",\n  \"components.UserList.password\": \"Κωδικός πρόσβασης\",\n  \"components.UserList.owner\": \"Ιδιοκτήτης\",\n  \"components.UserList.nouserstoimport\": \"Δεν υπάρχουν χρήστες για εισαγωγή από το Plex.\",\n  \"components.UserList.localuser\": \"Τοπικός χρήστης\",\n  \"components.UserList.localLoginDisabled\": \"Η ρύθμιση <strong>Ενεργοποίηση τοπικής σύνδεσης</strong> είναι προς το παρόν απενεργοποιημένη.\",\n  \"components.UserList.importfromplexerror\": \"Κάτι πήγε στραβά κατά την εισαγωγή χρηστών από το Plex.\",\n  \"components.UserList.importfrommediaserver\": \"Εισαγωγή χρηστών {mediaServerName}\",\n  \"components.UserList.importfromplex\": \"Εισαγωγή χρηστών από το Plex\",\n  \"components.UserList.importedfromplex\": \"{userCount, plural, one {# νέου χρήστη} other {#νέοι χρήστες}} εισήχθησαν απο το Plex επιτυχώς!\",\n  \"components.UserList.email\": \"Διεύθυνση ηλεκτρονικού ταχυδρομείου\",\n  \"components.UserList.edituser\": \"Επεξεργασία δικαιωμάτων χρήστη\",\n  \"components.UserList.deleteuser\": \"Διαγραφή χρήστη\",\n  \"components.UserList.deleteconfirm\": \"Είσαι σίγουρος ότι θες να διαγράψεις αυτόν τον χρήστη; Όλα τα αποθηκευμένα αιτήματα του θα διαγραφούν οριστικά.\",\n  \"components.UserList.creating\": \"Δημιουργείται…\",\n  \"components.UserList.createlocaluser\": \"Δημιουργία τοπικού χρήστη\",\n  \"components.UserList.created\": \"Έγινε μέλος\",\n  \"components.UserList.create\": \"Δημιουργία\",\n  \"components.UserList.bulkedit\": \"Μαζική επεξεργασία\",\n  \"components.UserList.autogeneratepasswordTip\": \"Στείλε με μήνυμα ηλεκτρονικού ταχυδρομείου έναν κωδικό πρόσβασης που δημιουργείται από τον διακομιστή στον χρήστη\",\n  \"components.UserList.autogeneratepassword\": \"Αυτόματη δημιουργία κωδικού πρόσβασης\",\n  \"components.UserList.admin\": \"Διαχειριστής\",\n  \"components.UserList.accounttype\": \"Τύπος\",\n  \"components.TvDetails.watchtrailer\": \"Δες το Τρέιλερ\",\n  \"components.TvDetails.viewfullcrew\": \"Προβολή Πλήρους Συνεργείου\",\n  \"components.TvDetails.similar\": \"Παρόμοιες σειρές\",\n  \"components.TvDetails.showtype\": \"Τύπος σειράς\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Σεζόν} other {# Σεζόν}}\",\n  \"components.TvDetails.recommendations\": \"Προτάσεις\",\n  \"components.TvDetails.overviewunavailable\": \"Επισκόπηση μη διαθέσιμη.\",\n  \"components.TvDetails.overview\": \"Επισκόπηση\",\n  \"components.TvDetails.originaltitle\": \"Αρχικός τίτλος\",\n  \"components.TvDetails.originallanguage\": \"Αρχική Γλώσσα\",\n  \"components.TvDetails.nextAirDate\": \"Επόμενη ημερομηνία προβολής\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Δίκτυο} other {Δίκτυα}}\",\n  \"components.TvDetails.firstAirDate\": \"Ημερομηνία πρώτης προβολής\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} λεπτά\",\n  \"components.TvDetails.episodeRuntime\": \"Διάρκεια επεισοδίου\",\n  \"components.TvDetails.cast\": \"Πρωταγωνιστές\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Όλο το Πλήρωμα της Σειράς\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Όλοι οι Ηθοποιοί της Σειράς\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Setup.welcome\": \"Καλώς ήρθες στο Seerr\",\n  \"components.Setup.signinMessage\": \"Ξεκίνα με την σύνδεση στον λογαριασμό του Plex σου\",\n  \"components.Setup.setup\": \"Εγκατάσταση\",\n  \"components.Setup.finishing\": \"Ολοκληρώνει…\",\n  \"components.Setup.finish\": \"Ολοκλήρωση εγκατάστασης\",\n  \"components.Setup.continue\": \"Συνέχεια\",\n  \"components.Setup.configureservices\": \"Διαμόρφωση υπηρεσιών\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.webAppUrlTip\": \"Προαιρετικά κατεύθυνε τους χρήστες στην εφαρμογή ιστού στον διακομιστή σας αντί για την εφαρμογή ιστού που \\\"φιλοξενείται\\\"\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Web App</WebAppLink> διεύθυνση URL\",\n  \"components.Settings.validationPortRequired\": \"Πρέπει να δώσεις έναν έγκυρο αριθμό θύρας\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Η λίστα διακομιστών Plex ανακτήθηκε με επιτυχία!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Απέτυχε η ανάκτηση της λίστας με τους διακομιστές Plex.\",\n  \"components.Settings.toastPlexRefresh\": \"Ανάκτηση λίστας διακομιστών από το Plex…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Η σύνδεση Plex δημιουργήθηκε με επιτυχία!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Απέτυχε να συνδεθεί στο Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"Προσπάθεια σύνδεσης στο Plex…\",\n  \"components.Settings.startscan\": \"Έναρξη σάρωσης\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.sonarrsettings\": \"Ρυθμίσεις Sonarr\",\n  \"components.Settings.settingUpPlexDescription\": \"Για να ρυθμίσεις το Plex, μπορείς είτε να εισαγάγεις τα στοιχεία χειροκίνητα είτε να επιλέξεις έναν διακομιστή που ανακτήθηκε από το <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Πάτα το κουμπί στα δεξιά του αναπτυσσόμενου μενού για να ανακτήσεις τη λίστα με τους διαθέσιμους διακομιστές.\",\n  \"components.Settings.services\": \"Υπηρεσίες\",\n  \"components.Settings.serviceSettingsDescription\": \"Διαμόρφωσε τον {serverType} διακομιστή(-ές) παρακάτω . Μπορείτε να συνδέσεις πολλούς {serverType} διακομιστές, αλλά μόνο δύο από αυτούς μπορούν να χαρακτηριστούν ως προεπιλεγμένοι (ένας μη-4K και ένας 4K). Οι διαχειριστές έχουν τη δυνατότητα να παρακάμψουν τον διακομιστή που χρησιμοποιείται για την επεξεργασία νέων αιτημάτων πριν από την έγκριση.\",\n  \"components.Settings.serverpresetRefreshing\": \"Ανάκτηση διακομιστών…\",\n  \"components.Settings.serverpresetManualMessage\": \"Χειροκίνητη διαμόρφωση\",\n  \"components.Settings.serverpresetLoad\": \"Πάτα το κουμπί για να φορτώσει τους διαθέσιμους διακομιστές\",\n  \"components.Settings.serverpreset\": \"Διακομιστής\",\n  \"components.Settings.serverSecure\": \"ασφαλές\",\n  \"components.Settings.serverRemote\": \"απομακρυσμένα\",\n  \"components.Settings.serverLocal\": \"τοπικά\",\n  \"components.Settings.scanning\": \"Συγχρονίζει…\",\n  \"components.Settings.scan\": \"Συγχρονισμός των βιβλιοθήκων\",\n  \"components.Settings.radarrsettings\": \"Ρυθμίσεις Radarr\",\n  \"components.Settings.port\": \"Θύρα\",\n  \"components.Settings.plexsettingsDescription\": \"Διαμόρφωσε τις ρυθμίσεις του Plex διακομιστή σου. Το Seerr σαρώνει τις βιβλιοθήκες του Plex για να προσδιορίσει τη διαθεσιμότητα περιεχομένου.\",\n  \"components.Settings.plexsettings\": \"Ρυθμίσεις Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"Οι βιβλιοθήκες που το Seerr θα σαρώνει για τίτλους. Ρύθμισε και αποθήκευσε τις ρυθμίσεις της σύνδεσης του Plex και, στη συνέχεια, κάνε κλικ στο παρακάτω κουμπί, εάν δεν εμφανιστύν οι βιβλιοθήκες.\",\n  \"components.Settings.plexlibraries\": \"Βιβλιοθήκες Plex\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notrunning\": \"Δεν τρέχει\",\n  \"components.Settings.notificationsettings\": \"Ρυθμίσεις Ειδοποιήσεων\",\n  \"components.Settings.notifications\": \"Ειδοποιήσεις\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Διαμόρφωσε και ενεργοποίησε τους πράκτορες ειδοποιήσεων.\",\n  \"components.Settings.noDefaultServer\": \"Τουλάχιστον ένας διακομιστής {serverType} πρέπει να έχει επισημανθεί ως προεπιλεγμένος προκειμένου να διεκπεραιωθούν τα αιτήματα {mediaType}.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Εάν έχεις μόνο έναν διακομιστή {serverType} τόσο για περιεχόμενο που δεν είναι 4K όσο και για περιεχόμενο 4K (ή εάν κάνεις λήψη μόνο περιεχομένου 4K), ο διακομιστής {serverType} θα πρέπει <strong>να ΜΗΝ</strong> οριστεί ως διακομιστής 4K.\",\n  \"components.Settings.noDefault4kServer\": \"Ένας διακομιστής 4K {serverType} πρέπει να επισημανθεί ως προεπιλεγμένος για να μπορούν οι χρήστες να υποβάλλουν αιτήσεις 4K {mediaType}.\",\n  \"components.Settings.menuUsers\": \"Χρήστες\",\n  \"components.Settings.menuServices\": \"Υπηρεσίες\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Ειδοποιήσεις\",\n  \"components.Settings.menuLogs\": \"Αρχεία καταγραφής\",\n  \"components.Settings.menuJobs\": \"Εργασίες & Κρυφή μνήμη\",\n  \"components.Settings.menuGeneralSettings\": \"Γενικές\",\n  \"components.Settings.menuAbout\": \"Σχετικά\",\n  \"components.Settings.mediaTypeSeries\": \"σειρά\",\n  \"components.Settings.mediaTypeMovie\": \"ταινία\",\n  \"components.Settings.manualscanDescription\": \"Κανονικά, αυτό εκτελείται μόνο μία φορά κάθε 24 ώρες. Το Seerr θα ελέγχει πιο επιθετικά τις προσθήκες που έγιναν πρόσφατα στον διακομιστή Plex. Εάν αυτή είναι η πρώτη φορά που ρυθμίζεις το Plex, συνιστάται μια εφάπαξ πλήρης χειροκίνητη σάρωση βιβλιοθήκης!\",\n  \"components.Settings.manualscan\": \"Χειροκίνητη σάρωση βιβλιοθήκης\",\n  \"components.Settings.librariesRemaining\": \"Βιβλιοθήκες που απομένουν: {count}\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.hostname\": \"Όνομα κεντρικού υπολογιστή ή διεύθυνση IP\",\n  \"components.Settings.enablessl\": \"Χρήση SSL\",\n  \"components.Settings.email\": \"Email\",\n  \"components.Settings.deleteserverconfirm\": \"Είσαι σίγουρος ότι θες να διαγράψεις αυτόν τον διακομιστή;\",\n  \"components.Settings.default4k\": \"Προεπιλεγμένο 4K\",\n  \"components.Settings.default\": \"Προκαθορισμένο\",\n  \"components.Settings.currentlibrary\": \"Τρέχουσα βιβλιοθήκη: {name}\",\n  \"components.Settings.cancelscan\": \"Ακύρωση σάρωσης\",\n  \"components.Settings.addsonarr\": \"Προσθήκη διακομιστή Sonarr\",\n  \"components.Settings.address\": \"Διεύθυνση\",\n  \"components.Settings.addradarr\": \"Προσθήκη διακομιστή Radarr\",\n  \"components.Settings.activeProfile\": \"Ενεργό προφίλ\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Πρέπει να επιλέξεις ένα ριζικό φάκελο\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Πρέπει να επιλέξεις ένα προφίλ ποιότητας\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Πρέπει να δώσεις έναν έγκυρο αριθμό θύρας\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Πρέπει να δώσεις ένα όνομα διακομιστή\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Πρέπει να επιλέξεις ένα προφίλ γλώσσας\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Πρέπει να δώσετε ένα έγκυρο όνομα κεντρικού υπολογιστή ή διεύθυνση IP\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Η βασική διεύθυνση URL δεν πρέπει να τελειώνει με κάθετο\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Η βασική διεύθυνση URL πρέπει να έχει μια κάθετο μπροστά\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"Η διεύθυνση URL δεν πρέπει να τελειώνει με κάθετο\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Πρέπει να βάλεις μια έγκυρη διεύθυνση URL\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Πρέπει να βάλεις ένα κλειδί API\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Η σύνδεση με το Sonarr δημιουργήθηκε επιτυχώς!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Η σύνδεση με το Sonarr δεν ήταν επιτυχής.\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Δοκιμή σύνδεσης για την φόρτωση των ετικετών\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Δοκιμή σύνδεσης για την φόρτωση των ριζικών φακέλων\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Δοκιμή σύνδεσης για την φόρτωση των προφίλ ποιότητας\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Δοκιμή σύνδεσης για την φόρτωση των προφίλ γλώσσας\",\n  \"components.Settings.SonarrModal.tags\": \"Ετικέτες\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Ενεργοποίηση σάρωσης\",\n  \"components.Settings.SonarrModal.ssl\": \"Χρήση SSL\",\n  \"components.Settings.SonarrModal.servername\": \"Όνομα διακομιστή\",\n  \"components.Settings.SonarrModal.server4k\": \"Διακομιστής 4K\",\n  \"components.Settings.SonarrModal.selecttags\": \"Επιλογή ετικετών\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Επίλεξε ριζικό φάκελο\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Επίλεξε προφίλ ποιότητας\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Επιλέξτε προφίλ γλώσσας\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Φάκελοι των Σεζόν\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Ριζικός φάκελος\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Προφίλ Ποιότητας\",\n  \"components.Settings.SonarrModal.port\": \"Θύρα\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Δεν υπάρχουν ετικέτες.\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Φόρτωση ριζικών φακέλων…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Φόρτωση των προφίλ ποιότητας…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Φόρτωση προφίλ γλώσσας…\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Φόρτωση ετικετών…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Προφίλ Γλώσσας\",\n  \"components.Settings.SonarrModal.hostname\": \"Όνομα κεντρικού υπολογιστή ή διεύθυνση IP\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Εξωτερική διεύθυνση URL\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Ενεργοποίηση αυτόματης αναζήτησης\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Επεξεργασία διακομιστή Sonarr\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Επεξεργασία διακομιστή 4K Sonarr\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Προεπιλεγμένος διακομιστής\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Προεπιλεγμένος διακομιστής 4K\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Προσθήκη νέου διακομιστή Sonarr\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Προσθήκη νέου διακομιστή 4K Sonarr\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Βασική Διεύθυνση URL\",\n  \"components.Settings.SonarrModal.apiKey\": \"Κλειδί API\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Ριζικός φάκελος Anime\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Προφίλ ποιότητας Anime\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Προφίλ γλώσσας Anime\",\n  \"components.Settings.SonarrModal.animeTags\": \"Ετικέτες Anime\",\n  \"components.Settings.SonarrModal.add\": \"Προσθήκη διακομιστή\",\n  \"components.Settings.SettingsUsers.users\": \"Χρήστες\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Ρυθμίσεις χρήστη\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Διαμόρφωση των γενικών και προεπιλεγμένων ρυθμίσεων του χρήστη.\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Καθολικό όριο των αιτημάτων στις Σειρές\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Οι ρυθμίσεις του χρήστη αποθηκεύτηκαν επιτυχώς!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Κάτι πήγε στραβά κατά την αποθήκευση των ρυθμίσεων.\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Επίτρεψε στους χρήστες του {mediaServerName} να συνδεθούν χωρίς να εισαχθούν πρώτα\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Ενεργοποίηση νέας σύνδεσης {mediaServerName}\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Το Seerr εκτελεί ορισμένες εργασίες συντήρησης ως τακτικά προγραμματισμένες εργασίες, αλλά μπορούν επίσης να ενεργοποιηθούν χειροκίνητα παρακάτω. Η χειροκίνητη εκτέλεση μιας εργασίας δεν θα αλλάξει το χρονοδιάγραμμα του.\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Template Variable Help\",\n  \"components.RequestModal.numberofepisodes\": \"# Αριθμός Επεισοδίων\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Στούντιο} other {Στούντιο}}\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} πίσω\",\n  \"pages.serviceunavailable\": \"Η υπηρεσία δεν είναι διαθέσιμη\",\n  \"pages.returnHome\": \"Επιστροφή στην Αρχική\",\n  \"pages.pagenotfound\": \"Η σελίδα δεν βρέθηκε\",\n  \"pages.oops\": \"Ουπς\",\n  \"pages.internalservererror\": \"Εσωτερικό Σφάλμα Διακομιστή\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"i18n.view\": \"Προβολή\",\n  \"i18n.usersettings\": \"Ρυθμίσεις χρήστη\",\n  \"i18n.unavailable\": \"Μη Διαθέσιμο\",\n  \"i18n.tvshows\": \"Σειρές\",\n  \"i18n.tvshow\": \"Σειρά\",\n  \"i18n.testing\": \"Γίνεται Δοκιμή…\",\n  \"i18n.test\": \"Δοκιμή\",\n  \"i18n.status\": \"Κατάσταση\",\n  \"i18n.showingresults\": \"Εμφάνιση <strong>{from}</strong> έως <strong>{to}</strong> από <strong>{total}</strong> αποτελέσματα\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Η βάση URL πρέπει να έχει μια κάθετο μπροστά\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Αυτόματη αίτηση ταινιών\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Αναφορά προβλήματος\",\n  \"i18n.resolved\": \"Επιλύθηκε\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Πρέπει να επιλέξετε τουλάχιστον έναν τύπο ειδοποιήσεων\",\n  \"i18n.import\": \"Εισαγωγή\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Αριθμός ψήφων χρηστών TMDB\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Αριθμός ψήφων μεταξύ {minValue} και {maxValue}\",\n  \"components.IssueDetails.comments\": \"Σχόλια\",\n  \"components.IssueDetails.season\": \"Σεζόν {seasonNumber}\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Episode} other {Episodes}}\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} από {user}\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Παρακαλώ δώστε λεπτομερή εξήγηση του προβλήματος που αντιμετωπίσατε.\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Υποβολή προβλήματος\",\n  \"components.IssueModal.issueSubtitles\": \"Υπότιτλος\",\n  \"components.ManageSlideOver.movie\": \"ταινία\",\n  \"components.ManageSlideOver.openarr\": \"Άνοιγμα σε {arr}\",\n  \"components.MovieDetails.rtcriticsscore\": \"Τοματόμετρο Rotten Tomatoes\",\n  \"components.MovieDetails.showmore\": \"Εμφάνιση περισσότερων\",\n  \"components.MovieDetails.streamingproviders\": \"Γίνεται Streaming στο\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Σχόλιο προβλήματος\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Το πρόβλημα ανοίχθηκε ξανά\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Το πρόβλημα επιλύθηκε\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Ειδοποιηθείτε όταν αιτήματα αποτυγχάνουν να προστεθούν στο Radarr ή το Sonarr.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Χορήγηση άδειας για την αναφορά προβλημάτων.\",\n  \"components.PermissionEdit.manageissues\": \"Διαχείριση προβλημάτων\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Χορήγηση άδειας για την προβολή προβλημάτων που αναφέρθηκαν από άλλους χρήστες.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Προβολή λιστών παρακολούθησης Plex\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {day} other {days}}\",\n  \"components.RequestBlock.requestedby\": \"Αιτήθηκε από\",\n  \"components.RequestCard.approverequest\": \"Έγκριση αίτησης\",\n  \"components.RequestCard.declinerequest\": \"Απόρριψη αίτησης\",\n  \"components.RequestCard.editrequest\": \"Επεξεργασία αίτησης\",\n  \"components.RequestCard.failedretry\": \"Κάτι πήγε στραβά με την επανάληψη της αίτησης.\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestModal.requestseries4ktitle\": \"Αίτηση σειράς σε 4Κ\",\n  \"components.RequestModal.selectmovies\": \"Επιλέξτε ταινία(ες)\",\n  \"components.Selector.nooptions\": \"Δεν υπάρχουν αποτελέσματα.\",\n  \"components.Selector.searchKeywords\": \"Αναζήτηση λέξεων-κλειδιών…\",\n  \"components.Selector.searchStudios\": \"Αναζήτηση στούντιο…\",\n  \"components.Selector.showless\": \"Εμφάνιση λιγότερων\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Οι ρυθμίσεις ειδοποιήσεων Gotify αποθηκεύτηκαν επιτυχώς!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Η δοκιμαστική αποστολή ειδοποίησης Gotify απέτυχε.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Πρέπει να επιλέξετε τουλάχιστον έναν τύπο ειδοποιήσεων\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"Ο σύνδεσμος δε μπορεί να τελειώνει σε κάθετο\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Τίτλος εφαρμογής\",\n  \"components.StatusBadge.playonplex\": \"Αναπαραγωγή στο Plex\",\n  \"components.TvDetails.rtaudiencescore\": \"Βαθμολογία κοινού Rotten Tomatoes\",\n  \"components.TvDetails.tmdbuserscore\": \"Βαθμολογία χρηστών TMDB\",\n  \"components.TvDetails.reportissue\": \"Αναφέρετε ένα πρόβλημα\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Αιτήματα ετικετών\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Αυτόματη προσθήκη πρόσθετης ετικέτας με το αναγνωριστικό χρήστη και το όνομα χρήστη του αιτούντος\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Μεταβολή εργασίας\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Κάτι πήγε στραβά με την αποθήκευση της εργασίας.\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Ενεργοποίηση caching εικόνων\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Κάνε cache εικόνες από εξωτερικές πηγές (απαιτεί πολύ αποθηκευτικό χώρο στο δίσκο)\",\n  \"components.Settings.SettingsMain.general\": \"Γενικά\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Διαμόρφωση των γενικών και προεπιλεγμένων ρυθμίσεων για το Seerr.\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Κάτι πήγε στραβά κατά την αποθήκευση των ρυθμίσεων.\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"Το URL δε μπορεί να τελειώνει με κάθετο\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Αρχικά δικαιώματα που ορίζονται σε νέους χρήστες\",\n  \"components.Settings.deleteServer\": \"Διαγραφή {serverType} διακομιστή\",\n  \"components.Settings.tautulliSettingsDescription\": \"Προαιρετικό: Διαμορφώστε τις ρυθμίσεις του Tautulli διακομιστή σας. Το Seerr τραβάει το ιστορικό προβολών του Plex από το Tautulli.\",\n  \"components.Settings.validationApiKey\": \"Πρέπει να δώσετε ένα κλειδί API\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Παρακαλώ επανεκκινήστε τον διακομιστή ώστε να εφαρμοστούν οι ενημερωμένες ρυθμίσεις.\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Κάτι πήγε στραβά κατά την ανάκτηση των δεδομένων της σεζόν.\",\n  \"components.TvDetails.manageseries\": \"Διαχείριση σειράς\",\n  \"components.TvDetails.productioncountries\": \"Παραγωγή {countryCount, plural, one {Country} other {Countries}}\",\n  \"components.TvDetails.rtcriticsscore\": \"Τοματόμετρο Rotten Tomatoes\",\n  \"components.TvDetails.seasonnumber\": \"Σεζόν {seasonNumber}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Πρέπει να εισάγετε ένα έγκυρο αναγνωριστικό χρήστη Discord\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Πρέπει να δώσετε ένα έγκυρο κλειδί χρήστη ή ομάδας\",\n  \"components.UserProfile.emptywatchlist\": \"Περιεχόμενο που εισάγεται στη <PlexWatchlistSupportLink>λίστα παρακολούθησης του Plex</PlexWatchlistSupportLink> θα εμφανίζεται εδώ.\",\n  \"components.UserProfile.recentlywatched\": \"Είδατε πρόσφατα\",\n  \"i18n.collection\": \"Συλλογή\",\n  \"components.MovieDetails.digitalrelease\": \"Ψηφιακή κυκλοφορία\",\n  \"components.MovieDetails.physicalrelease\": \"Κυκλοφορία σε φυσική έκδοση\",\n  \"components.RequestModal.approve\": \"Έγκριση αίτησης\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Είστε σίγουροι πως θέλετε να διαγράψετε αυτό το πρόβλημα;\",\n  \"components.IssueDetails.commentplaceholder\": \"Προσθέστε ένα σχόλιο…\",\n  \"components.IssueDetails.playonplex\": \"Αναπαραγωγή στο Plex\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Άγνωστο\",\n  \"components.IssueDetails.unknownissuetype\": \"Άγνωστο\",\n  \"components.IssueList.IssueItem.viewissue\": \"Προβολή προβλήματος\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Διαχείριση {mediaType}\",\n  \"components.MovieDetails.showless\": \"Εμφάνιση λιγότερων\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {season} other {seasons}}\",\n  \"components.Discover.tmdbmoviekeyword\": \"Λέξη-κλειδί ταινίας από TMDB\",\n  \"components.IssueDetails.IssueDescription.description\": \"Περιγραφή\",\n  \"components.ManageSlideOver.openarr4k\": \"Άνοιγμα σε 4K {arr}\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Ειδοποιηθείτε όταν άλλοι χρήστες σχολιάζουν σε προβλήματα.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Ειδοποιηθείτε όταν άλλοι χρήστες ξανανοίγουν προβλήματα.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Ειδοποιηθείτε όταν προβλήματα λύνονται από άλλους χρήστες.\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Ειδοποιηθείτε όταν νέα αιτήματα καταχωρούνται αυτόματα από τη λίστα παρακολούθησης Plex.\",\n  \"components.RequestBlock.approve\": \"Έγκριση αίτησης\",\n  \"components.PermissionEdit.viewissues\": \"Προβολή προβλημάτων\",\n  \"components.RequestBlock.edit\": \"Επεξεργασία αίτησης\",\n  \"components.RequestCard.cancelrequest\": \"Ακύρωση αίτησης\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Πρέπει να δώσετε ένα token εφαρμογής\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL διακομιστή\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Πρέπει να δώσετε έναν έγκυρο σύνδεσμο\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Πρέπει να δώσετε ένα token πρόσβασης\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL εφαρμογής\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Γλώσσα σελίδας ανακάλυψης\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Το νέο κλειδί API δημιουργήθηκε με επιτυχία!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Token πρόσβασης\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"API Token εφαρμογής\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Οι ρυθμίσεις ειδοποιήσεων Pushbullet αποθηκεύτηκαν επιτυχώς!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Οι ρυθμίσεις ειδοποιήσεων του Pushover αποθηκεύτηκαν επιτυχώς!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Οι ρυθμίσεις ειδοποιήσεων του Pushover απέτυχαν να αποθηκευτούν.\",\n  \"components.PermissionEdit.viewrecent\": \"Προβολή αυτών που προστέθηκαν πρόσφατα\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Κατάλογος Δεδομένων\",\n  \"components.RequestModal.requestApproved\": \"Η αίτηση για το <strong>{title}</strong> εγκρίθηκε!\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Ενεργοποίηση Agent\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Ειδοποιηθείτε όταν άλλοι χρήστες κάνουν αιτήματα που εγκρίνονται αυτόματα.\",\n  \"components.IssueModal.issueOther\": \"Άλλο\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Ανοιχτά προβλήματα\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Αποστολή ειδοποιήσεων όταν αναφέρονται προβλήματα.\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Λίστα παρακολούθησης Plex\",\n  \"components.IssueDetails.closeissueandcomment\": \"Κλείσιμο με σχόλιο\",\n  \"components.IssueDetails.deleteissue\": \"Διαγραφή προβλήματος\",\n  \"components.IssueDetails.nocomments\": \"Δεν υπάρχουν σχόλια.\",\n  \"components.IssueDetails.problemepisode\": \"Επηρεασμένο επεισόδιο\",\n  \"components.IssueDetails.reopenissue\": \"Ανοίξτε ξανά το πρόβλημα\",\n  \"components.IssueModal.issueAudio\": \"Ήχος\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Καθαρισμός δεδομένων\",\n  \"components.ManageSlideOver.opentautulli\": \"Άνοιγμα στο Tautulli\",\n  \"components.MovieDetails.managemovie\": \"Διαχείριση ταινίας\",\n  \"components.MovieDetails.reportissue\": \"Αναφορά προβλήματος\",\n  \"components.PermissionEdit.createissues\": \"Αναφορά προβλημάτων\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Προβολή λεπτομερειών\",\n  \"components.IssueDetails.IssueComment.delete\": \"Διαγραφή σχολίου\",\n  \"components.IssueList.IssueItem.issuetype\": \"Τύπος\",\n  \"components.Settings.Notifications.validationTypes\": \"Πρέπει να επιλέξετε τουλάχιστον έναν τύπο ειδοποιήσεων\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Ζητήθηκε\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Υπηρεσίες streaming ταινίας από TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB Υπηρεσίες streaming τηλεόρασης\",\n  \"components.IssueDetails.allseasons\": \"Όλες οι σεζόν\",\n  \"components.Discover.updatesuccess\": \"Ενημέρωση των ρυθμίσεων προσαρμογής της ανακάλυψης.\",\n  \"components.IssueDetails.closeissue\": \"Κλείσιμο προβλήματος\",\n  \"components.IssueDetails.openedby\": \"#{issueId} ανοίχτηκε {relativeTime} από {username}\",\n  \"components.IssueDetails.leavecomment\": \"Σχόλιο\",\n  \"components.IssueDetails.openinarr\": \"Άνοιγμα σε {arr}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Πρόσθετα\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Κάτι πήγε στραβά κατά την επεξεργασία της περιγραφής του προβλήματος.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Η περιγραφή του προβλήματος επεξεργάστηκε με επιτυχία!\",\n  \"components.Layout.Sidebar.issues\": \"Προβλήματα\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Κάτι πήγε στραβά με την υποβολή του προβλήματος.\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Περιεχόμενο\",\n  \"components.ManageSlideOver.downloadstatus\": \"Λήψεις\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4Κ περιεχόμενο\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Επισήμανση ως διαθέσιμο σε 4K\",\n  \"components.ManageSlideOver.markavailable\": \"Επισήμανση ως διαθέσιμο\",\n  \"components.ManageSlideOver.playedby\": \"Προβλήθηκε από\",\n  \"components.ManageSlideOver.pastdays\": \"Προηγούμενες {days, number} Ημέρες\",\n  \"components.MovieDetails.theatricalrelease\": \"Κινηματογραφική κυκλοφορία\",\n  \"components.MovieDetails.tmdbuserscore\": \"Βαθμολογία χρηστών TMDB\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Αναφέρθηκε πρόβλημα\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Αποστολή ειδοποιήσεων όταν υπάρχουν νέα σχόλια σε προβλήματα.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Καταχωρήθηκε αίτημα αυτόματα\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Ειδοποιηθείτε όταν προβλήματα που αναφέρατε ξανανοίγουν.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Ειδοποιηθείτε όταν προβλήματα που αναφέρατε επιλύονται.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Ειδοποιηθείτε όταν τα αιτήματα σας εγκρίνονται.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Ειδοποιηθείτε όταν τα αιτήματα σας γίνονται διαθέσιμα.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Ειδοποιηθείτε όταν άλλοι χρήστες αναφέρουν προβλήματα.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Ειδοποιηθείτε όταν τα αιτήματα σας απορρίπτονται.\",\n  \"components.PermissionEdit.autorequest\": \"Αυτόματη αίτηση\",\n  \"components.PermissionEdit.autorequestMovies\": \"Αυτόματη αίτηση ταινιών\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Χορήγηση άδειας για την αυτόματη υποβολή αιτημάτων για μη-4Κ σειρές από τη λίστα προβολής του Plex.\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Χορήγηση άδειας για τη διαχείριση προβλημάτων.\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} ανά {quotaDays} {days}</quotaUnits>\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Δε μπορέσαμε να αντιστοιχήσουμε αυτή τη σειρά.\",\n  \"components.RequestModal.requestmovies\": \"Αίτηση {count} {count, plural, one {Movie} other {Movies}}\",\n  \"components.Selector.showmore\": \"Εμφάνιση περισσότερων\",\n  \"components.Selector.starttyping\": \"Αρχίστε να πληκτρολογείτε για αναζήτηση.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Αποστολή δοκιμαστικής ειδοποίησης Gotify…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Ετικέτα καναλιού\",\n  \"components.Settings.RadarrModal.announced\": \"Ανακοινώθηκε\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Στους Κινηματογράφους\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Συγχρονισμός διαθεσιμότητας περιεχομένου\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Οι εικόνες έγιναν cache\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Καθαρισμός cached εικόνων\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Καθαρισμός Cache\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Συγχρονισμός λίστας παρακολούθησης Plex\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Γενικές ρυθμίσεις\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Απόκρυψη διαθέσιμου περιεχομένου\",\n  \"components.Settings.restartrequiredTooltip\": \"Το Seerr πρέπει να κάνει επανεκκίνηση ώστε να εφαρμοστεί αυτή η ρύθμιση\",\n  \"components.Settings.tautulliSettings\": \"Ρυθμίσεις Tautulli\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Οι ρυθμίσεις του Tautulli αποθηκεύτηκαν επιτυχώς!\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"Η βάση URL δεν πρέπει να τελειώνει με κάθετο\",\n  \"components.Settings.validationUrlTrailingSlash\": \"Το URL δε μπορεί να τελειώνει με κάθετο\",\n  \"components.StatusChecker.reloadApp\": \"Επαναφόρτωση {applicationTitle}\",\n  \"components.StatusBadge.seasonepisodenumber\": \"Σ{seasonNumber}Ε{episodeNumber}\",\n  \"components.TitleCard.cleardata\": \"Καθαρισμός δεδομένων\",\n  \"components.TvDetails.seasonstitle\": \"Σεζόν\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Ζητήστε αυτόματα ταινίες που βρίσκονται στη <PlexWatchlistSupportLink>λίστα παρακολούθησης του Plex</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Το αναγνωριστικό 30 χαρακτήρων <UsersGroupsLink>του χρήστη ή της ομάδας σας</UsersGroupsLink>\",\n  \"components.AirDateBadge.airedrelative\": \"Προβλήθηκε {relativeTime}\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Αιτήματα\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Επισημάνετε όλες τις σεζόν ως διαθέσιμες σε 4Κ\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Δώστε ένα TMDB Genre ID\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Δώστε ένα TMDB Keyword ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Δώστε το TMDB Network ID\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Δώστε ένα ερώτημα αναζήτησης\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Δώστε το TMDB Studio ID\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Αναζήτηση ειδών…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Αναζήτηση λέξεων-κλειδιών…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Αναζήτηση στούντιο…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Όνομα Slider\",\n  \"components.Discover.CreateSlider.starttyping\": \"Αρχίστε να πληκτρολογείτε για αναζήτηση.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Πρέπει να δώσετε μια τιμή.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Πρέπει να δώσετε έναν τίτλο.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Ταινίες\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Εναλλαγή ορατότητας\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Αφαίρεση\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Σειρά\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Η λίστα παρακολούθησης σας του Plex\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Η λίστα παρακολούθησης σας του Plex\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Προστέθηκαν πρόσφατα\",\n  \"components.Discover.createnewslider\": \"Δημιουργία νέου Slider\",\n  \"components.Discover.customizediscover\": \"Προσαρμογή σελίδας ανακάλυψης\",\n  \"components.Discover.plexwatchlist\": \"Η λίστα παρακολούθησης σας του Plex\",\n  \"components.Discover.networks\": \"Δίκτυα\",\n  \"components.Discover.resetwarning\": \"Επαναφορά όλων των sliders την προεπιλογή. Αυτό θα διαγράψει και οποιοδήποτε εξατομικευμένο slider!\",\n  \"components.Discover.stopediting\": \"Διακοπή επεξεργασίας\",\n  \"components.Discover.studios\": \"Στούντιο\",\n  \"components.Discover.tmdbmoviegenre\": \"Είδος Ταινίας TMDB\",\n  \"components.Discover.updatefailed\": \"Κάτι πήγε στραβά με την ενημέρωση των ρυθμίσεων προσαρμογής της ανακάλυψης.\",\n  \"components.Discover.tvgenres\": \"Είδη σειρών\",\n  \"components.IssueDetails.episode\": \"Επεισόδιο {episodeNumber}\",\n  \"components.IssueDetails.openin4karr\": \"Άνοιγμα σε 4K {arr}\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Διαγραφή προβλήματος\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Όλες οι σεζόν\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Κατάσταση\",\n  \"components.IssueList.IssueItem.opened\": \"Ανοίχτηκε\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Επηρεασμένο επεισόδιο\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Season} other {Seasons}}\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Επηρεασμένο επεισόδιο\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Επηρεασμένη σεζόν\",\n  \"components.IssueModal.issueVideo\": \"Βίντεο\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Τι συμβαίνει;\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Αιτήματα ταινιών\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Αιτήματα σειρών\",\n  \"components.Layout.UserDropdown.requests\": \"Αιτήματα\",\n  \"components.ManageSlideOver.tvshow\": \"σειρά\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {play} other {plays}}\",\n  \"components.RequestBlock.decline\": \"Απόρριψη αίτησης\",\n  \"components.RequestBlock.delete\": \"Διαγραφή αίτησης\",\n  \"components.RequestBlock.lastmodifiedby\": \"Τελευταία τροποποίηση από\",\n  \"components.RequestBlock.requestdate\": \"Ημ/νία αίτησης\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Episode} other {# Episodes}}\",\n  \"components.TvDetails.streamingproviders\": \"Γίνεται Streaming στο\",\n  \"components.RequestBlock.languageprofile\": \"Προφίλ γλώσσας\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Πρέπει να επιλέξετε τουλάχιστον έναν τύπο ειδοποιήσεων\",\n  \"components.Settings.Notifications.enableMentions\": \"Ενεργοποίηση αναφορών\",\n  \"i18n.importing\": \"Γίνεται εισαγωγή…\",\n  \"components.IssueDetails.issuetype\": \"Τύπος\",\n  \"components.IssueDetails.toaststatusupdated\": \"Η κατάσταση του προβλήματος ενημερώθηκε επιτυχώς!\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Όλα τα επεισόδια\",\n  \"components.IssueList.showallissues\": \"Προβολή όλων των προβλημάτων\",\n  \"components.IssueList.sortAdded\": \"Πιο πρόσφατα\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Προβολή προβλήματος\",\n  \"components.AirDateBadge.airsrelative\": \"Θα προβληθεί σε {relativeTime}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Κάθε {jobScheduleSeconds, plural, one {second} other {{jobScheduleSeconds} seconds}}\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Συνολικό μέγεθος cache\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Πρέπει να δώσετε έναν τίτλο εφαρμογής\",\n  \"components.Settings.advancedTooltip\": \"Λανθασμένη παραμετροποίηση αυτή της ρύθμισης μπορεί να οδηγήσει σε διακοπή της λειτουργίας\",\n  \"components.Settings.experimentalTooltip\": \"Η ενεργοποίηση αυτής της ρύθμισης μπορεί να οδηγήσει σε απρόσμενη συμπεριφορά της εφαρμογής\",\n  \"components.Settings.urlBase\": \"Βάση URL\",\n  \"components.Settings.validationUrl\": \"Πρέπει να δώσετε ένα έγκυρο URL\",\n  \"components.StatusBadge.managemedia\": \"Διαχείριση {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Άνοιγμα σε {arr}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Αυτόματη αίτηση σειρών\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Δημιουργήστε ένα token από τις <PushbulletSettingsLink>Ρυθμίσεις Λογαριασμού</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Καταχωρήστε μια εφαρμογή</ApplicationRegistrationLink> για χρήση με το {applicationTitle}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Ταινίες\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Τίτλος (Α-Ω) Αύξουσα σειρά\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Τίτλος (Ω-Α) φθίνουσα σειρά\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Βαθμολογία TMDB αύξουσα\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Βαθμολογία TMDB φθίνουσα\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Active Filter} other {# Active Filters}}\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Εκκαθάριση ενεργών φίλτρων\",\n  \"components.Discover.FilterSlideover.filters\": \"Φίλτρα\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Ημ/νία πρώτης προβολής\",\n  \"components.Discover.FilterSlideover.from\": \"Από\",\n  \"components.Discover.FilterSlideover.genres\": \"Είδη\",\n  \"components.Discover.FilterSlideover.keywords\": \"Λέξεις κλειδιά\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Πρωτότυπη γλώσσα\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Βαθμολογίες από {minValue} έως {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Ημερομηνία κυκλοφορίας\",\n  \"components.Discover.FilterSlideover.runtime\": \"Διάρκεια\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Χορήγηση άδειας για την αυτόματη υποβολή αιτήσεων για ταινίες μη-4K μέσω της λίστας παρακολούθησης του Plex.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Αυτόματη αίτηση σειρών\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Αίτηση συλλογής σε 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Αίτηση συλλογής\",\n  \"components.Selector.searchGenres\": \"Επιλέξτε είδη…\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Νέα συχνότητα\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Κάθε {jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Κάθε {jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Όταν είναι ενεργοποιημένο στις ρυθμίσεις, το Seerr θα κάνει proxy και cache εικόνες από προκαθορισμένες εξωτερικές πηγές. Οι εικόνες που έχουν γίνει cached θα αποθηκευτούν στον φάκελο των αρχείων. Μπορείτε να βρείτε τα αρχεία στο <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsMain.locale\": \"Γλώσσα εμφάνισης\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Φιλτράρετε το περιεχόμενο με βάση τη πρωτότυπη γλώσσα\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Επιτρέψτε τις αιτήσεων σειρών μερικώς\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Χορήγηση άδειας σε χρήστες να συνδεθούν χρησιμοποιώντας το email τους και τον κωδικό τους, αντί να συνδεθούν μέσω Plex\",\n  \"components.Settings.externalUrl\": \"Εξωτερικό URL\",\n  \"components.Settings.tautulliApiKey\": \"Κλειδί API\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Κάτι πήγε στραβά κατά την αποθήκευση των ρυθμίσεων του Tautulli.\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Ενημερώθηκε\",\n  \"components.StatusChecker.restartRequired\": \"Απαιτείται επανεκκίνηση του διακομιστή\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} Δε βρέθηκε\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.TvDetails.Season.noepisodes\": \"Η λίστα επεισοδίων δεν είναι διαθέσιμη.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Ο <FindDiscordIdLink>multi-digit ID αριθμός</FindDiscordIdLink> που σχετίζεται με τον λογαριασμό σας στο Discord\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Οι ρυθμίσεις ειδοποιήσεων Pushbullet απέτυχαν να αποθηκευτούν.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Κλειδί χρήστη ή ομάδας\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Πρέπει να δώσετε ένα έγκυρο token εφαρμογής\",\n  \"i18n.open\": \"Άνοιγμα\",\n  \"i18n.restartRequired\": \"Απαιτείται επανεκκίνηση\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Σεζόν {seasonNumber} Επεισόδιο {episodeNumber}\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Αποστολή ειδοποιήσεων όταν λύνονται προβλήματα.\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Άγνωστος τίτλος\",\n  \"components.RequestModal.requestseriestitle\": \"Αίτηση σειράς\",\n  \"components.Discover.moviegenres\": \"Είδη ταινιών\",\n  \"components.Discover.resetfailed\": \"Κάτι πήγε στραβά με την επαναφορά των ρυθμίσεων εξατομίκευσης ανακάλυψης.\",\n  \"components.Discover.resetsuccess\": \"Επιτυχής επαναφορά των ρυθμίσεων προσαρμογής ανακάλυψης.\",\n  \"components.Discover.FilterSlideover.studio\": \"Στούντιο\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Βαθμολογία χρηστών TMDB\",\n  \"components.Discover.FilterSlideover.to\": \"Εως\",\n  \"components.Discover.tmdbnetwork\": \"Δίκτυο TMDB\",\n  \"components.Discover.tmdbsearch\": \"TMDB Αναζήτηση\",\n  \"components.Discover.tmdbtvgenre\": \"Είδος σειράς TMDB\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Δημοσιεύθηκε {relativeTime} από {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Δημοσιεύθηκε {relativeTime} από {username} (Επεξεργάστηκε)\",\n  \"components.IssueDetails.play4konplex\": \"Αναπαραγωγή σε 4K στο Plex\",\n  \"components.IssueDetails.toastissuedeleted\": \"Το πρόβλημα διαγράφηκε επιτυχώς!\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Γλώσσα εμφάνισης\",\n  \"components.Layout.Sidebar.browsemovies\": \"Ταινίες\",\n  \"components.Layout.Sidebar.browsetv\": \"Σειρές\",\n  \"components.RequestCard.unknowntitle\": \"Άγνωστος τίτλος\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Δημιουργία προσαρμοσμένου Slider\",\n  \"components.Discover.CreateSlider.editSlider\": \"Επεξεργασία Slider\",\n  \"components.Discover.CreateSlider.addSlider\": \"Προσθήκη Slider\",\n  \"components.Discover.CreateSlider.addfail\": \"Απέτυχε η δημιουργία νέου slider.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Δημιουργήθηνε νέο slider και αποθηκεύτηκαν οι προσαρμοσμένες ρυθμίσεις ανακάλυψης.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Δεν υπάρχουν αποτελέσματα.\",\n  \"components.Discover.CreateSlider.editfail\": \"Αποτυχία επεξεργασίας slider.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Επεξεργάστηκε το slider και αποθηκεύτηκαν οι προσαρμοσμένες ρυθμίσεις ανακάλυψης.\",\n  \"components.Discover.CreateSlider.needresults\": \"Πρέπει να έχετε τουλάχιστον 1 αποτέλεσμα.\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Active Filter} other {# Active Filters}}\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Δημοτικότητα Αύξουσα\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Δημοτικότητα φθίνουσα\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Ημ/νία κυκλοφορίας αύξουσα\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Τίτλος (Ω-Α) φθίνουσα σειρά\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Ημ/νία κυκλοφορίας φθίνουσα\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Τίτλος (Α-Ω) Αύξουσα σειρά\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Βαθμολογία TMDB αύξουσα\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Βαθμολογία TMDB φθίνουσα\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Αποτυχία διαγραφής Slider.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Το Slider διαγράφηκε επιτυχώς.\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Active Filter} other {# Active Filters}}\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Δημοτικότητα φθίνουσα\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Σειρές\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Πρώτη ημ/νία προβολής φθίνουσα\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Δημοτικότητα αύξουσα\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Πρώτη ημ/νία προβολής αύξουσα\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} λεπτά διάρκειας\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Υπηρεσίες streaming\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Περιεχόμενο που προστέθηκε στη <PlexWatchlistSupportLink>Λίστα παρακολούθησης Plex</PlexWatchlistSupportLink> θα εμφανίζεται εδώ.\",\n  \"components.Discover.resettodefault\": \"Επαναφορά στην προεπιλογή\",\n  \"components.Discover.emptywatchlist\": \"Περιεχόμενο που προστέθηκε στη <PlexWatchlistSupportLink>Λίστα παρακολούθησης Plex</PlexWatchlistSupportLink> θα εμφανίζεται εδώ.\",\n  \"components.Discover.tmdbstudio\": \"Στούντιο TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Λέξη-κλειδί σειράς TMDB\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Είστε σίγουροι πως θέλετε να διαγράψετε αυτό το σχόλιο;\",\n  \"components.IssueDetails.IssueComment.edit\": \"Επεξεργασία σχολίου\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Πρέπει να εισάγετε ένα μήνυμα\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Επεξεργασία περιγραφής\",\n  \"components.IssueDetails.allepisodes\": \"Όλα τα επεισόδια\",\n  \"components.IssueDetails.issuepagetitle\": \"Πρόβλημα\",\n  \"components.IssueDetails.lastupdated\": \"Τελευταία ενημέρωση\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Ανοίξτε ξανά με σχόλιο\",\n  \"components.IssueDetails.problemseason\": \"Επηρεασμένη σεζόν\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Κάτι πήγε στραβά κατά τη διαγραφή του προβλήματος.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Κάτι πήγε στραβά με την ενημέρωση της κατάστασης του προβλήματος.\",\n  \"components.IssueList.sortModified\": \"Τελευταία τροποποιημένα\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Σεζόν {seasonNumber}\",\n  \"components.IssueList.issues\": \"Προβλήματα\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Επεισόδιο {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Η αναφορά προβλήματος για το <strong>{title}</strong> υποβλήθηκε επιτυχώς!\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Πρέπει να δώσετε μια περιγραφή\",\n  \"components.ManageSlideOver.alltime\": \"Από πάντα\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Για προχωρημένους\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Αυτό θα αφαιρέσει αμετάκλητα όλα τα δεδομένα για αυτό το {mediaType}, συμπεριλαμβανομένων τυχόν αιτήσεων. Εάν αυτό το στοιχείο υπάρχει στη βιβλιοθήκη Plex, οι πληροφορίες του μέσου θα δημιουργηθούν εκ νέου κατά την επόμενη σάρωση.\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Δεν υπάρχουν αιτήματα.\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Επισημάνετε όλες τις σεζόν ως διαθέσιμες\",\n  \"components.MovieDetails.productioncountries\": \"Παραγωγή {countryCount, plural, one {Country} other {Countries}}\",\n  \"components.MovieDetails.rtaudiencescore\": \"Βαθμολογία κοινού Rotten Tomatoes\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Αποστολή ειδοποιήσεων όταν ξανανοίγονται προβλήματα.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Ειδοποιηθείτε όταν προβλήματα που έχετε αναφέρει λαμβάνουν νέα σχόλια.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Ειδοποιηθείτε όταν άλλοι χρήστες υποβάλλουν αιτήματα τα οποία απαιτούν έγκριση.\",\n  \"components.PermissionEdit.autorequestDescription\": \"Χορήγηση άδειας για την αυτόματη υποβολή αιτήσεων για μέσα μη-4K μέσω της λίστας παρακολούθησης του Plex.\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} ανά {quotaDays} {days}</quotaUnits>\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Χορήγηση άδειας για την προβολή της λίστας του περιεχομένου που προστέθηκε πρόσφατα.\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Χορήγηση άδειας για την προβολή λιστών παρακολούθησης Plex άλλων χρηστών.\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {movie} other {movies}}\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Αίτηση ταινίας σε 4Κ\",\n  \"components.RequestModal.requestmovies4k\": \"Αίτηση {count} {count, plural, one {Movie} other {Movies}} σε 4Κ\",\n  \"components.RequestModal.requestmovietitle\": \"Αίτηση ταινίας\",\n  \"components.RequestModal.requestseasons4k\": \"Αίτηση {seasonCount} {seasonCount, plural, one {Season} other {Seasons}} σε 4Κ\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Οι ρυθμίσεις ειδοποιήσεων Gotify απέτυχαν να αποθηκευτούν.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Η δοκιμαστική ειδοποίηση Gotify στάλθηκε!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token εφαρμογής\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Πρέπει να επιλέξετε τουλάχιστον έναν τύπο ειδοποιήσεων\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Πρέπει να επιλέξετε τουλάχιστον έναν τύπο ειδοποιήσεων\",\n  \"components.Settings.RadarrModal.released\": \"Κυκλοφόρησε\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Εκτελείτε την έκδοση <code>ανάπτυξης</code> του Seerr, το οποίο προτείνεται μόνο για αυτούς που προσφέρουν την ανάπτυξη της εφαρμογής ή σε αυτούς που βοηθούν με τον έλεγχο των τελευταίων εκδόσεων.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Τρέχουσα συχνότητα\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Η εργασία μεταβλήθηκε επιτυχώς!\",\n  \"components.Settings.SettingsMain.apikey\": \"Κλειδί API\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Κάτι πήγε στραβά κατά τη δημιουργία νέου κλειδιού API.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Οι ρυθμίσεις αποθηκεύτηκαν με επιτυχία!\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Πρέπει να δώσετε ένα έγκυρο URL\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Ετικέτες αιτημάτων\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Αυτόματη προσθήκη πρόσθετης ετικέτας με το αναγνωριστικό χρήστη και το όνομα χρήστη του αιτούντος\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Παρακαλώ πατήστε το κουμπί παρακάτω ώστε να γίνει επαναφόρτωση της εφαρμογής.\",\n  \"components.TvDetails.status4k\": \"4Κ {status}\",\n  \"components.UserList.newplexsigninenabled\": \"Η ρύθμιση <strong>Ενεργοποίηση νέας εισόδου Plex</strong> είναι ενεργοποιημένη. Οι χρήστες Plex με πρόσβαση στη βιβλιοθήκη δε χρειάζεται να γίνουν εισαγωγή ώστε να συνδεθούν.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Αναγνωριστικό χρήστη Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Ζητήστε αυτόματα σειρές που βρίσκονται στη <PlexWatchlistSupportLink>λίστα παρακολούθησης του Plex</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.plexwatchlist\": \"Λίστα παρακολούθησης Plex\",\n  \"components.MovieDetails.imdbuserscore\": \"Βαθμολογία χρηστών IMDB\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Τύπος σειράς άνιμε\",\n  \"components.Settings.SonarrModal.seriesType\": \"Τύπος σειράς\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Ήχος ειδοποίησης\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Προεπιλογή συσκευής\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Ήχος ειδοποίησης\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Προεπιλογή συσκευής\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/en.json",
    "content": "{\n  \"component.BlocklistBlock.blocklistdate\": \"Blocklisted date\",\n  \"component.BlocklistBlock.blocklistedby\": \"Blocklisted By\",\n  \"component.BlocklistModal.blocklisting\": \"Blocklisting\",\n  \"components.AirDateBadge.airedrelative\": \"Aired {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Airing {relativeTime}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"The <code>{appDataPath}</code> volume mount was not configured properly. All data will be cleared when the container is stopped or restarted.\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> is not blocklisted.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Manage blocklisted media.\",\n  \"components.Blocklist.blocklistdate\": \"date\",\n  \"components.Blocklist.blocklistedby\": \"{date} by {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Blocklist Settings\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Blocklisted Tags\",\n  \"components.Blocklist.filterManual\": \"Manual\",\n  \"components.Blocklist.mediaName\": \"Name\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb Id\",\n  \"components.Blocklist.mediaType\": \"Type\",\n  \"components.Blocklist.showAllBlocklisted\": \"Show All Blocklisted Media\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Movies\",\n  \"components.CollectionDetails.overview\": \"Overview\",\n  \"components.CollectionDetails.requestcollection\": \"Request Collection\",\n  \"components.CollectionDetails.requestcollection4k\": \"Request Collection in 4K\",\n  \"components.Discover.CreateSlider.addSlider\": \"Add Slider\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Create Custom Slider\",\n  \"components.Discover.CreateSlider.addfail\": \"Failed to create new slider.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Created new slider and saved discover customization settings.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Edit Slider\",\n  \"components.Discover.CreateSlider.editfail\": \"Failed to edit slider.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Edited slider and saved discover customization settings.\",\n  \"components.Discover.CreateSlider.needresults\": \"You need to have at least 1 result.\",\n  \"components.Discover.CreateSlider.nooptions\": \"No results.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Provide a TMDB Genre ID\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Provide a TMDB Keyword ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Provide TMDB Network ID\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Provide a search query\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Provide TMDB Studio ID\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Search genres…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Search keywords…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Search studios…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Slider Name\",\n  \"components.Discover.CreateSlider.starttyping\": \"Starting typing to search.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"You must provide a data value.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"You must provide a title.\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} Movies\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Movies\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Movies\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Active Filter} other {# Active Filters}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Movies\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularity Ascending\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularity Descending\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Release Date Ascending\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Release Date Descending\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Title (A-Z) Ascending\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Title (Z-A) Descending\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB Rating Ascending\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB Rating Descending\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} Series\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Failed to delete slider.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Sucessfully deleted slider.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Toggle Visibility\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Remove\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} Movies\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Active Filter} other {# Active Filters}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Series\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"First Air Date Ascending\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"First Air Date Descending\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularity Ascending\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularity Descending\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Title (A-Z) Ascending\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Title (Z-A) Descending\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB Rating Ascending\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB Rating Descending\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Series\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Series\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Series\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Your Watchlist\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex Watchlist\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Active Filter} other {# Active Filters}}\",\n  \"components.Discover.FilterSlideover.certification\": \"Content Rating\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Clear Active Filters\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Exclude Keywords\",\n  \"components.Discover.FilterSlideover.filters\": \"Filters\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"First Air Date\",\n  \"components.Discover.FilterSlideover.from\": \"From\",\n  \"components.Discover.FilterSlideover.genres\": \"Genres\",\n  \"components.Discover.FilterSlideover.keywords\": \"Keywords\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Original Language\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Ratings between {minValue} and {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Release Date\",\n  \"components.Discover.FilterSlideover.runtime\": \"Runtime\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minute runtime\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streaming Services\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB User Score\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB User Vote Count\",\n  \"components.Discover.FilterSlideover.to\": \"To\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Number of votes between {minValue} and {maxValue}\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Movie Genres\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Movie Genres\",\n  \"components.Discover.NetworkSlider.networks\": \"Networks\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Your Watchlist\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Recently Added\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Unable to connect to {services}. Some information may be unavailable.\",\n  \"components.Discover.StudioSlider.studios\": \"Studios\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Series Genres\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Series Genres\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Upcoming Series\",\n  \"components.Discover.createnewslider\": \"Create New Slider\",\n  \"components.Discover.customizediscover\": \"Customize Discover\",\n  \"components.Discover.discover\": \"Discover\",\n  \"components.Discover.emptywatchlist\": \"Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.\",\n  \"components.Discover.moviegenres\": \"Movie Genres\",\n  \"components.Discover.networks\": \"Networks\",\n  \"components.Discover.plexwatchlist\": \"Your Watchlist\",\n  \"components.Discover.popularmovies\": \"Popular Movies\",\n  \"components.Discover.populartv\": \"Popular Series\",\n  \"components.Discover.recentlyAdded\": \"Recently Added\",\n  \"components.Discover.recentrequests\": \"Recent Requests\",\n  \"components.Discover.resetfailed\": \"Something went wrong resetting the discover customization settings.\",\n  \"components.Discover.resetsuccess\": \"Sucessfully reset discover customization settings.\",\n  \"components.Discover.resettodefault\": \"Reset to Default\",\n  \"components.Discover.resetwarning\": \"Reset all sliders to default. This will also delete any custom sliders!\",\n  \"components.Discover.stopediting\": \"Stop Editing\",\n  \"components.Discover.studios\": \"Studios\",\n  \"components.Discover.timeWindowDay\": \"Daily\",\n  \"components.Discover.timeWindowWeek\": \"Weekly\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB Movie Genre\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB Movie Keyword\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB Movie Streaming Services\",\n  \"components.Discover.tmdbnetwork\": \"TMDB Network\",\n  \"components.Discover.tmdbsearch\": \"TMDB Search\",\n  \"components.Discover.tmdbstudio\": \"TMDB Studio\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB Series Genre\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB Series Keyword\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TV Streaming Services\",\n  \"components.Discover.trending\": \"Trending\",\n  \"components.Discover.tvgenres\": \"Series Genres\",\n  \"components.Discover.upcoming\": \"Upcoming Movies\",\n  \"components.Discover.upcomingmovies\": \"Upcoming Movies\",\n  \"components.Discover.upcomingtv\": \"Upcoming Series\",\n  \"components.Discover.updatefailed\": \"Something went wrong updating the discover customization settings.\",\n  \"components.Discover.updatesuccess\": \"Updated discover customization settings.\",\n  \"components.DownloadBlock.estimatedtime\": \"Estimated {time}\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Season {seasonNumber} Episode {episodeNumber}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Are you sure you want to delete this comment?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Delete Comment\",\n  \"components.IssueDetails.IssueComment.edit\": \"Edit Comment\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Posted {relativeTime} by {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Posted {relativeTime} by {username} (Edited)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"You must enter a message\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Delete Issue\",\n  \"components.IssueDetails.IssueDescription.description\": \"Description\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Edit Description\",\n  \"components.IssueDetails.allepisodes\": \"All Episodes\",\n  \"components.IssueDetails.allseasons\": \"All Seasons\",\n  \"components.IssueDetails.closeissue\": \"Close Issue\",\n  \"components.IssueDetails.closeissueandcomment\": \"Close with Comment\",\n  \"components.IssueDetails.commentplaceholder\": \"Add a comment…\",\n  \"components.IssueDetails.comments\": \"Comments\",\n  \"components.IssueDetails.deleteissue\": \"Delete Issue\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Are you sure you want to delete this issue?\",\n  \"components.IssueDetails.episode\": \"Episode {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Issue\",\n  \"components.IssueDetails.issuetype\": \"Type\",\n  \"components.IssueDetails.lastupdated\": \"Last Updated\",\n  \"components.IssueDetails.leavecomment\": \"Comment\",\n  \"components.IssueDetails.nocomments\": \"No comments.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} opened {relativeTime} by {username}\",\n  \"components.IssueDetails.openin4karr\": \"Open in 4K {arr}\",\n  \"components.IssueDetails.openinarr\": \"Open in {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Play in 4K on {mediaServerName}\",\n  \"components.IssueDetails.playonplex\": \"Play on {mediaServerName}\",\n  \"components.IssueDetails.problemepisode\": \"Affected Episode\",\n  \"components.IssueDetails.problemseason\": \"Affected Season\",\n  \"components.IssueDetails.reopenissue\": \"Reopen Issue\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Reopen with Comment\",\n  \"components.IssueDetails.season\": \"Season {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Something went wrong while editing the issue description.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Issue description edited successfully!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Issue deleted successfully!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Something went wrong while deleting the issue.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Issue status updated successfully!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Something went wrong while updating the issue status.\",\n  \"components.IssueDetails.unknownissuetype\": \"Unknown\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Issue Description\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Episode} other {Episodes}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Status\",\n  \"components.IssueList.IssueItem.issuetype\": \"Type\",\n  \"components.IssueList.IssueItem.opened\": \"Opened\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} by {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Affected Episode\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Season} other {Seasons}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Unknown\",\n  \"components.IssueList.IssueItem.viewissue\": \"View Issue\",\n  \"components.IssueList.issues\": \"Issues\",\n  \"components.IssueList.showallissues\": \"Show All Issues\",\n  \"components.IssueList.sortAdded\": \"Most Recent\",\n  \"components.IssueList.sortModified\": \"Last Modified\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"All Episodes\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"All Seasons\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episode {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extras\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Affected Episode\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Affected Season\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Please provide a detailed explanation of the issue you encountered.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Report an Issue\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Season {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Submit Issue\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Something went wrong while submitting the issue.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Issue report for <strong>{title}</strong> submitted successfully!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"View Issue\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"You must provide a description\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"What's wrong?\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueModal.issueOther\": \"Other\",\n  \"components.IssueModal.issueSubtitles\": \"Subtitle\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.LanguageSelector.languageServerDefault\": \"Default ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"All Languages\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Display Language\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Search Movies & TV\",\n  \"components.Layout.Sidebar.blocklist\": \"Blocklist\",\n  \"components.Layout.Sidebar.browsemovies\": \"Movies\",\n  \"components.Layout.Sidebar.browsetv\": \"Series\",\n  \"components.Layout.Sidebar.dashboard\": \"Discover\",\n  \"components.Layout.Sidebar.issues\": \"Issues\",\n  \"components.Layout.Sidebar.requests\": \"Requests\",\n  \"components.Layout.Sidebar.settings\": \"Settings\",\n  \"components.Layout.Sidebar.users\": \"Users\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Movie Requests\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Series Requests\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profile\",\n  \"components.Layout.UserDropdown.requests\": \"Requests\",\n  \"components.Layout.UserDropdown.settings\": \"Settings\",\n  \"components.Layout.UserDropdown.signout\": \"Sign Out\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Email address is invalid.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"An email address is required.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"A password is required.\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} behind\",\n  \"components.Layout.VersionStatus.outofdate\": \"Out of Date\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Develop\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stable\",\n  \"components.Login.adminerror\": \"You must use an admin account to sign in.\",\n  \"components.Login.back\": \"Go back\",\n  \"components.Login.credentialerror\": \"The username or password is incorrect.\",\n  \"components.Login.description\": \"Since this is your first time logging into {applicationName}, you are required to add a valid email address.\",\n  \"components.Login.email\": \"Email Address\",\n  \"components.Login.emailtooltip\": \"Address does not need to be associated with your {mediaServerName} instance.\",\n  \"components.Login.enablessl\": \"Use SSL\",\n  \"components.Login.forgotpassword\": \"Forgot Password?\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.initialsignin\": \"Connect\",\n  \"components.Login.initialsigningin\": \"Connecting…\",\n  \"components.Login.invalidurlerror\": \"Unable to connect to {mediaServerName} server.\",\n  \"components.Login.loginerror\": \"Something went wrong while trying to sign in.\",\n  \"components.Login.loginwithapp\": \"Login with {appName}\",\n  \"components.Login.noadminerror\": \"No admin user found on the server.\",\n  \"components.Login.orsigninwith\": \"Or sign in with\",\n  \"components.Login.password\": \"Password\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.save\": \"Add\",\n  \"components.Login.saving\": \"Adding…\",\n  \"components.Login.servertype\": \"Server Type\",\n  \"components.Login.signin\": \"Sign In\",\n  \"components.Login.signingin\": \"Signing In…\",\n  \"components.Login.signinheader\": \"Sign in to continue\",\n  \"components.Login.signinwithjellyfin\": \"Use your {mediaServerName} account\",\n  \"components.Login.signinwithoverseerr\": \"Use your {applicationTitle} account\",\n  \"components.Login.signinwithplex\": \"Use your Plex account\",\n  \"components.Login.tipEmailHasTrailingWhitespace\": \"The email ends with whitespace\",\n  \"components.Login.tipUsernameHasTrailingWhitespace\": \"The username ends with whitespace\",\n  \"components.Login.title\": \"Add Email\",\n  \"components.Login.urlBase\": \"URL Base\",\n  \"components.Login.username\": \"Username\",\n  \"components.Login.validationEmailFormat\": \"Invalid email\",\n  \"components.Login.validationEmailRequired\": \"You must provide an email\",\n  \"components.Login.validationPortRequired\": \"You must provide a valid port number\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"URL base must have a leading slash\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"URL base must not end in a trailing slash\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL must not end in a trailing slash\",\n  \"components.Login.validationemailformat\": \"Valid email required\",\n  \"components.Login.validationemailrequired\": \"You must provide a valid email address\",\n  \"components.Login.validationhostformat\": \"Valid URL required\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL required\",\n  \"components.Login.validationpasswordrequired\": \"You must provide a password\",\n  \"components.Login.validationservertyperequired\": \"Please select a server type\",\n  \"components.Login.validationusernamerequired\": \"Username required\",\n  \"components.ManageSlideOver.alltime\": \"All Time\",\n  \"components.ManageSlideOver.downloadstatus\": \"Downloads\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Advanced\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Clear Data\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* This will irreversibly remove all data for this {mediaType}, including any requests. If this item exists in your {mediaServerName} library, the media information will be recreated during the next scan.\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Open Issues\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Media\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K Media\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"No requests.\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* This will irreversibly remove this {mediaType} from {arr}, including all files.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Requests\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Manage {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Mark as Available in 4K\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Mark All Seasons as Available in 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Mark All Seasons as Available\",\n  \"components.ManageSlideOver.markavailable\": \"Mark as Available\",\n  \"components.ManageSlideOver.movie\": \"movie\",\n  \"components.ManageSlideOver.openarr\": \"Open in {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Open in 4K {arr}\",\n  \"components.ManageSlideOver.opentautulli\": \"Open in Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Past {days, number} Days\",\n  \"components.ManageSlideOver.playedby\": \"Played By\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {play} other {plays}}\",\n  \"components.ManageSlideOver.removearr\": \"Remove from {arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"Remove from 4K {arr}\",\n  \"components.ManageSlideOver.tvshow\": \"series\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"See More\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Select a metadata provider\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Full Cast\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Full Crew\",\n  \"components.MovieDetails.addtowatchlist\": \"Add To Watchlist\",\n  \"components.MovieDetails.budget\": \"Budget\",\n  \"components.MovieDetails.cast\": \"Cast\",\n  \"components.MovieDetails.digitalrelease\": \"Digital Release\",\n  \"components.MovieDetails.downloadstatus\": \"Download Status\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB User Score – votes: {formattedCount}\",\n  \"components.MovieDetails.managemovie\": \"Manage Movie\",\n  \"components.MovieDetails.mark4kavailable\": \"Mark as Available in 4K\",\n  \"components.MovieDetails.markavailable\": \"Mark as Available\",\n  \"components.MovieDetails.openradarr\": \"Open Movie in Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"Open Movie in 4K Radarr\",\n  \"components.MovieDetails.originallanguage\": \"Original Language\",\n  \"components.MovieDetails.originaltitle\": \"Original Title\",\n  \"components.MovieDetails.overview\": \"Overview\",\n  \"components.MovieDetails.overviewunavailable\": \"Overview unavailable.\",\n  \"components.MovieDetails.physicalrelease\": \"Physical Release\",\n  \"components.MovieDetails.play\": \"Play on {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Play 4K on {mediaServerName}\",\n  \"components.MovieDetails.productioncountries\": \"Production {countryCount, plural, one {Country} other {Countries}}\",\n  \"components.MovieDetails.recommendations\": \"Recommendations\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Release Date} other {Release Dates}}\",\n  \"components.MovieDetails.removefromwatchlist\": \"Remove From Watchlist\",\n  \"components.MovieDetails.reportissue\": \"Report an Issue\",\n  \"components.MovieDetails.revenue\": \"Revenue\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes Audience Score\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutes\",\n  \"components.MovieDetails.showless\": \"Show Less\",\n  \"components.MovieDetails.showmore\": \"Show More\",\n  \"components.MovieDetails.similar\": \"Similar Titles\",\n  \"components.MovieDetails.streamingproviders\": \"Currently Streaming On\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studios}}\",\n  \"components.MovieDetails.theatricalrelease\": \"Theatrical Release\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB User Score\",\n  \"components.MovieDetails.viewfullcrew\": \"View Full Crew\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> Removed from watchlist successfully!\",\n  \"components.MovieDetails.watchlistError\": \"Something went wrong. Please try again.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> added to watchlist successfully!\",\n  \"components.MovieDetails.watchtrailer\": \"Watch Trailer\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Get notified when other users comment on issues.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Get notified when issues are reopened by other users.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Get notified when issues are resolved by other users.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Issue Comment\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Send notifications when issues receive new comments.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Issue Reported\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Send notifications when issues are reported.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Issue Reopened\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Send notifications when issues are reopened.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Issue Resolved\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Send notifications when issues are resolved.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Request Automatically Approved\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Send notifications when users submit new media requests which are automatically approved.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Request Approved\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Send notifications when media requests are manually approved.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Request Automatically Submitted\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Get notified when new media requests are automatically submitted for items on Your Watchlist.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Request Available\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Send notifications when media requests become available.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Request Declined\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Send notifications when media requests are declined.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Request Processing Failed\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Send notifications when media requests fail to be added to Radarr or Sonarr.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Request Pending Approval\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Send notifications when users submit new media requests which require approval.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Notification Types\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Get notified when issues you reported receive new comments.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Get notified when other users report issues.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Get notified when issues you reported are reopened.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Get notified when issues you reported are resolved.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Get notified when other users submit new media requests which are automatically approved.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Get notified when your media requests are approved.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Get notified when your media requests become available.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Get notified when your media requests are declined.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Get notified when media requests fail to be added to Radarr or Sonarr.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Get notified when other users submit new media requests which require approval.\",\n  \"components.PermissionEdit.admin\": \"Admin\",\n  \"components.PermissionEdit.adminDescription\": \"Full administrator access. Bypasses all other permission checks.\",\n  \"components.PermissionEdit.advancedrequest\": \"Advanced Requests\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Grant permission to modify advanced media request options.\",\n  \"components.PermissionEdit.autoapprove\": \"Auto-Approve\",\n  \"components.PermissionEdit.autoapprove4k\": \"Auto-Approve 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Grant automatic approval for all 4K media requests.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Auto-Approve 4K Movies\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Grant automatic approval for 4K movie requests.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Auto-Approve 4K Series\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Grant automatic approval for 4K series requests.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Grant automatic approval for all non-4K media requests.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Auto-Approve Movies\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Grant automatic approval for non-4K movie requests.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Auto-Approve Series\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Grant automatic approval for non-4K series requests.\",\n  \"components.PermissionEdit.autorequest\": \"Auto-Request\",\n  \"components.PermissionEdit.autorequestDescription\": \"Grant permission to automatically submit requests for non-4K media via Plex Watchlist.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Auto-Request Movies\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Grant permission to automatically submit requests for non-4K movies via Plex Watchlist.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Auto-Request Series\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Grant permission to automatically submit requests for non-4K series via Plex Watchlist.\",\n  \"components.PermissionEdit.blocklistedItems\": \"Blocklist media.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Grant permission to blocklist media.\",\n  \"components.PermissionEdit.createissues\": \"Report Issues\",\n  \"components.PermissionEdit.createissuesDescription\": \"Grant permission to report media issues.\",\n  \"components.PermissionEdit.manageblocklist\": \"Manage Blocklist\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Grant permission to manage blocklisted media.\",\n  \"components.PermissionEdit.manageissues\": \"Manage Issues\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Grant permission to manage media issues.\",\n  \"components.PermissionEdit.managerequests\": \"Manage Requests\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Grant permission to manage media requests. All requests made by a user with this permission will be automatically approved.\",\n  \"components.PermissionEdit.request\": \"Request\",\n  \"components.PermissionEdit.request4k\": \"Request 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Grant permission to submit requests for 4K media.\",\n  \"components.PermissionEdit.request4kMovies\": \"Request 4K Movies\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Grant permission to submit requests for 4K movies.\",\n  \"components.PermissionEdit.request4kTv\": \"Request 4K Series\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Grant permission to submit requests for 4K series.\",\n  \"components.PermissionEdit.requestDescription\": \"Grant permission to submit requests for non-4K media.\",\n  \"components.PermissionEdit.requestMovies\": \"Request Movies\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Grant permission to submit requests for non-4K movies.\",\n  \"components.PermissionEdit.requestTv\": \"Request Series\",\n  \"components.PermissionEdit.requestTvDescription\": \"Grant permission to submit requests for non-4K series.\",\n  \"components.PermissionEdit.users\": \"Manage Users\",\n  \"components.PermissionEdit.usersDescription\": \"Grant permission to manage users. Users with this permission cannot modify users with or grant the Admin privilege.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"View blocklisted media.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Grant permission to view blocklisted media.\",\n  \"components.PermissionEdit.viewissues\": \"View Issues\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Grant permission to view media issues reported by other users.\",\n  \"components.PermissionEdit.viewrecent\": \"View Recently Added\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Grant permission to view the list of recently added media.\",\n  \"components.PermissionEdit.viewrequests\": \"View Requests\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Grant permission to view media requests submitted by other users.\",\n  \"components.PermissionEdit.viewwatchlists\": \"View {mediaServerName} Watchlists\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Grant permission to view other users' {mediaServerName} Watchlists.\",\n  \"components.PersonDetails.alsoknownas\": \"Also Known As: {names}\",\n  \"components.PersonDetails.appearsin\": \"Appearances\",\n  \"components.PersonDetails.ascharacter\": \"as {character}\",\n  \"components.PersonDetails.birthdate\": \"Born {birthdate}\",\n  \"components.PersonDetails.crewmember\": \"Crew\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {day} other {days}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {movie} other {movies}}\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {season} other {seasons}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.unlimited\": \"Unlimited\",\n  \"components.RegionSelector.regionDefault\": \"All Regions\",\n  \"components.RegionSelector.regionServerDefault\": \"Default ({region})\",\n  \"components.RequestBlock.approve\": \"Approve Request\",\n  \"components.RequestBlock.decline\": \"Decline Request\",\n  \"components.RequestBlock.delete\": \"Delete Request\",\n  \"components.RequestBlock.edit\": \"Edit Request\",\n  \"components.RequestBlock.languageprofile\": \"Language Profile\",\n  \"components.RequestBlock.lastmodifiedby\": \"Last Modified By\",\n  \"components.RequestBlock.profilechanged\": \"Quality Profile\",\n  \"components.RequestBlock.requestdate\": \"Request Date\",\n  \"components.RequestBlock.requestedby\": \"Requested By\",\n  \"components.RequestBlock.requestoverrides\": \"Request Overrides\",\n  \"components.RequestBlock.rootfolder\": \"Root Folder\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Season} other {Seasons}}\",\n  \"components.RequestBlock.server\": \"Destination Server\",\n  \"components.RequestButton.approve4krequests\": \"Approve {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.approverequest\": \"Approve Request\",\n  \"components.RequestButton.approverequest4k\": \"Approve 4K Request\",\n  \"components.RequestButton.approverequests\": \"Approve {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.decline4krequests\": \"Decline {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.declinerequest\": \"Decline Request\",\n  \"components.RequestButton.declinerequest4k\": \"Decline 4K Request\",\n  \"components.RequestButton.declinerequests\": \"Decline {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.requestmore\": \"Request More\",\n  \"components.RequestButton.requestmore4k\": \"Request More in 4K\",\n  \"components.RequestButton.viewrequest\": \"View Request\",\n  \"components.RequestButton.viewrequest4k\": \"View 4K Request\",\n  \"components.RequestCard.approverequest\": \"Approve Request\",\n  \"components.RequestCard.cancelrequest\": \"Cancel Request\",\n  \"components.RequestCard.declinerequest\": \"Decline Request\",\n  \"components.RequestCard.deleterequest\": \"Delete Request\",\n  \"components.RequestCard.editrequest\": \"Edit Request\",\n  \"components.RequestCard.failedretry\": \"Something went wrong while retrying the request.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} Not Found\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Season} other {Seasons}}\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestCard.unknowntitle\": \"Unknown Title\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Cancel Request\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Delete Request\",\n  \"components.RequestList.RequestItem.editrequest\": \"Edit Request\",\n  \"components.RequestList.RequestItem.failedretry\": \"Something went wrong while retrying the request.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} Not Found\",\n  \"components.RequestList.RequestItem.modified\": \"Modified\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} by {user}\",\n  \"components.RequestList.RequestItem.profileName\": \"Profile\",\n  \"components.RequestList.RequestItem.removearr\": \"Remove from {arr}\",\n  \"components.RequestList.RequestItem.requested\": \"Requested\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Requested\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Season} other {Seasons}}\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Unknown Title\",\n  \"components.RequestList.requests\": \"Requests\",\n  \"components.RequestList.showallrequests\": \"Show All Requests\",\n  \"components.RequestList.sortAdded\": \"Most Recent\",\n  \"components.RequestList.sortDirection\": \"Toggle Sort Direction\",\n  \"components.RequestList.sortModified\": \"Last Modified\",\n  \"components.RequestList.unableToConnect\": \"Unable to connect to {services}. Some information may be unavailable.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Advanced\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* This series is an anime.\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Default)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Destination Server\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Language Profile\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"No tags.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Quality Profile\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Request As\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Root Folder\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Select tags\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Tags\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"You are allowed to request <strong>{limit}</strong> {type} every <strong>{days}</strong> days.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"This user is allowed to request <strong>{limit}</strong> {type} every <strong>{days}</strong> days.\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"movie\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {movie} other {movies}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Not enough season requests remaining\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"You can view a summary of your request limits on your <ProfileLink>profile page</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"You can view a summary of this user's request limits on their <ProfileLink>profile page</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {request} other {requests}} remaining\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"You need to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"This user needs to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"season\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {season} other {seasons}}\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"We were unable to find a match for this series.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"We were unable to automatically match this series. Please select the correct match below.\",\n  \"components.RequestModal.alreadyrequested\": \"Already Requested\",\n  \"components.RequestModal.approve\": \"Approve Request\",\n  \"components.RequestModal.autoapproval\": \"Automatic Approval\",\n  \"components.RequestModal.cancel\": \"Cancel Request\",\n  \"components.RequestModal.edit\": \"Edit Request\",\n  \"components.RequestModal.errorediting\": \"Something went wrong while editing the request.\",\n  \"components.RequestModal.numberofepisodes\": \"# of Episodes\",\n  \"components.RequestModal.pending4krequest\": \"Pending 4K Request\",\n  \"components.RequestModal.pendingapproval\": \"Your request is pending approval.\",\n  \"components.RequestModal.pendingrequest\": \"Pending Request\",\n  \"components.RequestModal.requestApproved\": \"Request for <strong>{title}</strong> approved!\",\n  \"components.RequestModal.requestCancel\": \"Request for <strong>{title}</strong> canceled.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> requested successfully!\",\n  \"components.RequestModal.requestadmin\": \"This request will be approved automatically.\",\n  \"components.RequestModal.requestcancelled\": \"Request for <strong>{title}</strong> canceled.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Request Collection in 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Request Collection\",\n  \"components.RequestModal.requestedited\": \"Request for <strong>{title}</strong> edited successfully!\",\n  \"components.RequestModal.requesterror\": \"Something went wrong while submitting the request.\",\n  \"components.RequestModal.requestfrom\": \"{username}'s request is pending approval.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Request Movie in 4K\",\n  \"components.RequestModal.requestmovies\": \"Request {count} {count, plural, one {Movie} other {Movies}}\",\n  \"components.RequestModal.requestmovies4k\": \"Request {count} {count, plural, one {Movie} other {Movies}} in 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Request Movie\",\n  \"components.RequestModal.requestseasons\": \"Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}\",\n  \"components.RequestModal.requestseasons4k\": \"Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}} in 4K\",\n  \"components.RequestModal.requestseries4ktitle\": \"Request Series in 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Request Series\",\n  \"components.RequestModal.season\": \"Season\",\n  \"components.RequestModal.seasonnumber\": \"Season {number}\",\n  \"components.RequestModal.selectmovies\": \"Select Movie(s)\",\n  \"components.RequestModal.selectseason\": \"Select Season(s)\",\n  \"components.ResetPassword.confirmpassword\": \"Confirm Password\",\n  \"components.ResetPassword.email\": \"Email Address\",\n  \"components.ResetPassword.emailresetlink\": \"Email Recovery Link\",\n  \"components.ResetPassword.gobacklogin\": \"Return to Sign-In Page\",\n  \"components.ResetPassword.password\": \"Password\",\n  \"components.ResetPassword.passwordreset\": \"Password Reset\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"A password reset link will be sent to the provided email address if it is associated with a valid user.\",\n  \"components.ResetPassword.resetpassword\": \"Reset your password\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Password reset successfully!\",\n  \"components.ResetPassword.validationemailrequired\": \"You must provide a valid email address\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Passwords must match\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Password is too short; should be a minimum of 8 characters\",\n  \"components.ResetPassword.validationpasswordrequired\": \"You must provide a password\",\n  \"components.Search.search\": \"Search\",\n  \"components.Search.searchresults\": \"Search Results\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Failed to load certifications\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Maximum rating\",\n  \"components.Selector.CertificationSelector.minRating\": \"Minimum rating\",\n  \"components.Selector.CertificationSelector.noOptions\": \"No options available\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Select a certification\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Select a country\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Starting typing to search.\",\n  \"components.Selector.canceled\": \"Canceled\",\n  \"components.Selector.ended\": \"Ended\",\n  \"components.Selector.inProduction\": \"In Production\",\n  \"components.Selector.nooptions\": \"No results.\",\n  \"components.Selector.pilot\": \"Pilot\",\n  \"components.Selector.planned\": \"Planned\",\n  \"components.Selector.returningSeries\": \"Returning Series\",\n  \"components.Selector.searchGenres\": \"Select genres…\",\n  \"components.Selector.searchKeywords\": \"Search keywords…\",\n  \"components.Selector.searchStatus\": \"Select status...\",\n  \"components.Selector.searchStudios\": \"Search studios…\",\n  \"components.Selector.searchUsers\": \"Select users…\",\n  \"components.Selector.showless\": \"Show Less\",\n  \"components.Selector.showmore\": \"Show More\",\n  \"components.Selector.starttyping\": \"Starting typing to search.\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Enable Agent\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify notification settings failed to save.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify notification settings saved successfully!\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Priority\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify test notification failed to send.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Sending Gotify test notification…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify test notification sent!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Application Token\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Server URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"You must set a priority number\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"You must provide an application token\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"You must select at least one notification type\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"You must provide a valid URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL must not end in a trailing slash\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Enable Agent\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Embed Poster\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Ntfy notification settings failed to save.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Ntfy notification settings saved successfully!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Password\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Priority\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Ntfy test notification failed to send.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Sending ntfy test notification…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Ntfy test notification sent!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Token authentication\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Topic\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Server root URL\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Username\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Username + Password authentication\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"You must provide a topic\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"You must provide a valid URL\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"You must provide a priority between 1 and 5\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"You must select at least one notification type\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Access Token\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Create a token from your <PushbulletSettingsLink>Account Settings</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Enable Agent\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Channel Tag\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbullet notification settings failed to save.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet notification settings saved successfully!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet test notification failed to send.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Sending Pushbullet test notification…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet test notification sent!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"You must provide an access token\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"You must select at least one notification type\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Application API Token\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Register an application</ApplicationRegistrationLink> for use with Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Enable Agent\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Device Default\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Embed Poster\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushover notification settings failed to save.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover notification settings saved successfully!\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Notification Sound\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover test notification failed to send.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Sending Pushover test notification…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover test notification sent!\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"User or Group Key\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"You must provide a valid application token\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"You must select at least one notification type\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"You must provide a valid user or group key\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Enable Agent\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Embed Poster\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Slack notification settings failed to save.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack notification settings saved successfully!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack test notification failed to send.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Sending Slack test notification…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack test notification sent!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"You must select at least one notification type\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"You must provide a valid URL\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Create an <WebhookLink>Incoming Webhook</WebhookLink> integration\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Enable Agent\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Authorization Header\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Custom Headers\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Add Header\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Cannot use both Authorization Header and custom Authorization header. Please remove one.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"All headers must have both name and value\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Header Name\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Remove\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Add custom HTTP headers to include with webhook requests\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Header Value\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON Payload\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Reset to Default\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON payload reset successfully!\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Support URL Variables\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Available variables are documented in the webhook template variables section\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Template Variable Help\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Webhook test notification failed to send.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Sending webhook test notification…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook test notification sent!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"You must provide a valid JSON payload\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"You must select at least one notification type\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"You must provide a valid URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"Test Notification URL is set to {testUrl} instead of the actual webhook URL.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Webhook notification settings failed to save.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Webhook notification settings saved successfully!\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Enable Agent\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Embed Poster\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"In order to receive web push notifications, Seerr must be served over HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Web push test notification failed to send.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Sending web push test notification…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Web push test notification sent!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Web push notification settings failed to save.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Web push notification settings saved successfully!\",\n  \"components.Settings.Notifications.agentenabled\": \"Enable Agent\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Allow Self-Signed Certificates\",\n  \"components.Settings.Notifications.authPass\": \"SMTP Password\",\n  \"components.Settings.Notifications.authUser\": \"SMTP Username\",\n  \"components.Settings.Notifications.botAPI\": \"Bot Authorization Token\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Create a bot</CreateBotLink> for use with Seerr\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Bot Avatar URL\",\n  \"components.Settings.Notifications.botUsername\": \"Bot Username\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Allow users to also start a chat with your bot and configure their own notifications\",\n  \"components.Settings.Notifications.chatId\": \"Chat ID\",\n  \"components.Settings.Notifications.chatIdTip\": \"Start a chat with your bot, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discord notification settings failed to save.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord notification settings saved successfully!\",\n  \"components.Settings.Notifications.emailsender\": \"Sender Address\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Email notification settings failed to save.\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Email notification settings saved successfully!\",\n  \"components.Settings.Notifications.embedPoster\": \"Embed Poster\",\n  \"components.Settings.Notifications.enableMentions\": \"Enable Mentions\",\n  \"components.Settings.Notifications.encryption\": \"Encryption Method\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Use STARTTLS if available\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Use Implicit TLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"None\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Always use STARTTLS\",\n  \"components.Settings.Notifications.encryptionTip\": \"In most cases, Implicit TLS uses port 465 and STARTTLS uses port 587\",\n  \"components.Settings.Notifications.messageThreadId\": \"Thread/Topic ID\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"If your group-chat has topics enabled, you can specify a thread/topic's ID here\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP Password\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Sign encrypted email messages using <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP Private Key\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Sign encrypted email messages using <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.sendSilently\": \"Send Silently\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Send notifications with no sound\",\n  \"components.Settings.Notifications.senderName\": \"Sender Name\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP Host\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP Port\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegram notification settings failed to save.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram notification settings saved successfully!\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord test notification failed to send.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Sending Discord test notification…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord test notification sent!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Email test notification failed to send.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Sending email test notification…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Email test notification sent!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram test notification failed to send.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Sending Telegram test notification…\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram test notification sent!\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Require user email\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"You must provide a bot authorization token\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"You must provide a valid chat ID\",\n  \"components.Settings.Notifications.validationEmail\": \"You must provide a valid email address\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"The thread/topic ID must be a positive whole number\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"You must provide a PGP password\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"You must provide a valid PGP private key\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"You must provide a valid hostname or IP address\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"You must provide a valid port number\",\n  \"components.Settings.Notifications.validationTypes\": \"You must select at least one notification type\",\n  \"components.Settings.Notifications.validationUrl\": \"You must provide a valid URL\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"You must provide a valid Discord Role ID\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Notification Role ID\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"The role ID to mention in the webhook message. Leave empty to disable mentions\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Create a <DiscordWebhookLink>webhook integration</DiscordWebhookLink> in your server\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Conditions\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Specifies conditions before applying parameter changes. Each field must be validated for the rules to be applied (AND operation). A field is considered verified if any of its properties match (OR operation).\",\n  \"components.Settings.OverrideRuleModal.create\": \"Create rule\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"New Override Rule\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Edit Override Rule\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Genres\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Keywords\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Languages\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"No tags.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Quality Profile\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Root Folder\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Override rule created successfully!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Override rule updated successfully!\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Select quality profile\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Select root folder\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Select service\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Select tags\",\n  \"components.Settings.OverrideRuleModal.service\": \"Service\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Apply this rule to the selected service.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Settings\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Specifies which settings will be changed when the above conditions are met.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleModal.users\": \"Users\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Conditions\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Genre\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Keywords\",\n  \"components.Settings.OverrideRuleTile.language\": \"Language\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Quality Profile\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Root Folder\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Settings\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleTile.users\": \"Users\",\n  \"components.Settings.RadarrModal.add\": \"Add Server\",\n  \"components.Settings.RadarrModal.announced\": \"Announced\",\n  \"components.Settings.RadarrModal.apiKey\": \"API Key\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL Base\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Add New 4K Radarr Server\",\n  \"components.Settings.RadarrModal.createradarr\": \"Add New Radarr Server\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Default 4K Server\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Default Server\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Edit 4K Radarr Server\",\n  \"components.Settings.RadarrModal.editradarr\": \"Edit Radarr Server\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Enable Automatic Search\",\n  \"components.Settings.RadarrModal.externalUrl\": \"External URL\",\n  \"components.Settings.RadarrModal.hostname\": \"Hostname or IP Address\",\n  \"components.Settings.RadarrModal.inCinemas\": \"In Cinemas\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Loading tags…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Loading quality profiles…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Loading root folders…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimum Availability\",\n  \"components.Settings.RadarrModal.notagoptions\": \"No tags.\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Quality Profile\",\n  \"components.Settings.RadarrModal.released\": \"Released\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Root Folder\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Select minimum availability\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Select quality profile\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Select root folder\",\n  \"components.Settings.RadarrModal.selecttags\": \"Select tags\",\n  \"components.Settings.RadarrModal.server4k\": \"4K Server\",\n  \"components.Settings.RadarrModal.servername\": \"Server Name\",\n  \"components.Settings.RadarrModal.ssl\": \"Use SSL\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Enable Scan\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Tag Requests\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Automatically add an additional tag with the requester's user ID & display name\",\n  \"components.Settings.RadarrModal.tags\": \"Tags\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Test connection to load quality profiles\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Test connection to load root folders\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Test connection to load tags\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Failed to connect to Radarr.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr connection established successfully!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"You must provide an API key\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"You must provide a valid URL\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL must not end in a trailing slash\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL base must have a leading slash\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL base must not end in a trailing slash\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"You must provide a valid hostname or IP address\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"You must select a minimum availability\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"You must provide a server name\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"You must provide a valid port number\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"You must select a quality profile\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"You must select a root folder\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Current\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Latest\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Release data is currently unavailable.\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Releases\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Changelog\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"View Changelog\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"View on GitHub\",\n  \"components.Settings.SettingsAbout.about\": \"About\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"About Seerr\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Data Directory\",\n  \"components.Settings.SettingsAbout.contribute\": \"Make a Contribution\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentation\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Getting Support\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub Discussions\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Out of Date\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"You are running the <code>develop</code> branch of Seerr, which is only recommended for those contributing to development or assisting with bleeding-edge testing.\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Support Seerr\",\n  \"components.Settings.SettingsAbout.timezone\": \"Time Zone\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Total Media\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Total Requests\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Up to Date\",\n  \"components.Settings.SettingsAbout.version\": \"Version\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Media Availability Sync\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr caches requests to external API endpoints to optimize performance and avoid making unnecessary API calls.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} cache flushed.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Hits\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Total Keys\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Key Size\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Misses\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Cache Name\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Value Size\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Cancel Job\",\n  \"components.Settings.SettingsJobsCache.command\": \"Command\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNS Cache\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr caches DNS lookups to optimize performance and avoid making unnecessary API calls.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Global DNS Cache Stats\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"These stats are aggregated across all DNS cache entries.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"No DNS lookups have been cached yet.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Active Address\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Age\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"{hostname} dns cache flushed.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Hits\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Misses\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Hostname\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Download Sync\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Download Sync Reset\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modify Job\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Current Frequency\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"New Frequency\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Every {jobScheduleDays, plural, one {day} other {{jobScheduleDays} days}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Every {jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Every {jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Every {jobScheduleSeconds, plural, one {second} other {{jobScheduleSeconds} seconds}}\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Failures\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Flush Cache\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Flush DNS Cache\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Hit Rate\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Hits\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Image Cache Cleanup\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Image Cache\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"When enabled in settings, Seerr will proxy and cache images from pre-configured external sources. Cached images are saved into your config folder. You can find the files in <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Images Cached\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Total Cache Size\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4 Fallbacks\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Jellyfin Full Library Scan\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Jellyfin Recently Added Scan\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Something went wrong while saving the job.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Job edited successfully!\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} canceled.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Job Name\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Jobs\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr performs certain maintenance tasks as regularly-scheduled jobs, but they can also be manually triggered below. Manually running a job will not alter its schedule.\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Jobs & Cache\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} started.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Type\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Misses\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Next Execution\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plex Full Library Scan\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plex Recently Added Scan\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex Refresh Token\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex Watchlist Sync\",\n  \"components.Settings.SettingsJobsCache.process\": \"Process\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Process Blocklisted Tags\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr Scan\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Run Now\",\n  \"components.Settings.SettingsJobsCache.size\": \"Size\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr Scan\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Unknown Job\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Users' Avatars\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Copied log message to clipboard.\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Copy to Clipboard\",\n  \"components.Settings.SettingsLogs.extraData\": \"Additional Data\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Debug\",\n  \"components.Settings.SettingsLogs.filterError\": \"Error\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Warning\",\n  \"components.Settings.SettingsLogs.label\": \"Label\",\n  \"components.Settings.SettingsLogs.level\": \"Severity\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Log Details\",\n  \"components.Settings.SettingsLogs.logs\": \"Logs\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"You can also view these logs directly via <code>stdout</code>, or in <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.message\": \"Message\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pause\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Resume\",\n  \"components.Settings.SettingsLogs.showall\": \"Show All Logs\",\n  \"components.Settings.SettingsLogs.time\": \"Timestamp\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"View Details\",\n  \"components.Settings.SettingsMain.apikey\": \"API Key\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"Copied API key to clipboard.\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Application Title\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Application URL\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Blocklist Content with Tags\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Limit Content Blocklisted per Tag\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"The \\\"Process Blocklisted Tags\\\" job will blocklist this many pages into each sort. Larger numbers will create a more accurate blocklist, but use more space.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Automatically add content with tags to the blocklist using the \\\"Process Blocklisted Tags\\\" job\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Enable Image Caching\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Cache externally sourced images (requires a significant amount of disk space)\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Discover Region\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filter content by regional availability\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Allow Special Episodes Requests\",\n  \"components.Settings.SettingsMain.general\": \"General\",\n  \"components.Settings.SettingsMain.generalsettings\": \"General Settings\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Configure global and default settings for Seerr.\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Hide Available Media\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Hide available media from the discover pages but not search results\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Hide Blocklisted Items\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Hide blocklisted items from discover pages for all users with the \\\"Manage Blocklist\\\" permission\",\n  \"components.Settings.SettingsMain.locale\": \"Display Language\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Discover Language\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filter content by original language\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Allow Partial Series Requests\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Streaming Region\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Show streaming sites by regional availability\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Something went wrong while generating a new API key.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"New API key generated successfully!\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Something went wrong while saving settings.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Settings saved successfully!\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"You must provide an application title\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"You must provide a valid URL\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL must not end in a trailing slash\",\n  \"components.Settings.SettingsMain.validationUrl\": \"You must provide a valid URL\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URL must not end in a trailing slash\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube URL\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"Base URL for YouTube videos if a self-hosted YouTube instance is used.\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"API Request Timeout\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Maximum time (in seconds) to wait for responses from external services like Radarr/Sonarr. Set to 0 for no timeout.\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Enable CSRF Protection\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"Do NOT enable this setting unless you understand what you are doing!\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Set external API access to read-only (requires HTTPS)\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNS Cache\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"DNS Cache Maximum TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"DNS Cache Minimum TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"Do NOT enable this if you are experiencing issues with DNS lookups\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Enable caching of DNS lookups to optimize performance and avoid making unnecessary API calls\",\n  \"components.Settings.SettingsNetwork.docs\": \"documentation\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Force IPv4 Resolution First\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Force Seerr to resolve IPv4 addresses first instead of IPv6\",\n  \"components.Settings.SettingsNetwork.network\": \"Network\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Network parameters from your container/system should be used instead of these settings. See the {docs} for more information.\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Network Settings\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Configure network settings for your Seerr instance.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Proxy Ignored Addresses\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Use ',' as a separator, and '*.' as a wildcard for subdomains\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Bypass Proxy for Local Addresses\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) Proxy\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Send ALL outgoing HTTP/HTTPS requests through a proxy server (host/port). Does NOT enable HTTPS, SSL, or certificate configuration.\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Proxy Hostname\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Proxy Password\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Proxy Port\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Use SSL For Proxy\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Proxy Username\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Something went wrong while saving settings.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Settings saved successfully!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Enable Proxy Support\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Allow Seerr to correctly register client IP addresses behind a proxy\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"You must provide a valid timeout value\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"You must provide a valid maximum TTL\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"You must provide a valid minimum TTL\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"You must provide a valid port\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"At least one authentication method must be selected.\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Default Permissions\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Initial permissions assigned to new users\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Enable Local Sign-In\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Allow users to sign in using their email address and password\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Login Methods\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Configure login methods for users.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Enable {mediaServerName} Sign-In\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Allow users to sign in using their {mediaServerName} account\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Global Movie Request Limit\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Enable New {mediaServerName} Sign-In\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Allow {mediaServerName} users to sign in without first being imported\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Something went wrong while saving settings.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"User settings saved successfully!\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Global Series Request Limit\",\n  \"components.Settings.SettingsUsers.userSettings\": \"User Settings\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Configure global and default user settings.\",\n  \"components.Settings.SettingsUsers.users\": \"Users\",\n  \"components.Settings.SonarrModal.add\": \"Add Server\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Anime Series Type\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime Tags\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime Language Profile\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime Quality Profile\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime Root Folder\",\n  \"components.Settings.SonarrModal.apiKey\": \"API Key\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL Base\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Add New 4K Sonarr Server\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Add New Sonarr Server\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Default 4K Server\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Default Server\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Edit 4K Sonarr Server\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Edit Sonarr Server\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Enable Automatic Search\",\n  \"components.Settings.SonarrModal.externalUrl\": \"External URL\",\n  \"components.Settings.SonarrModal.hostname\": \"Hostname or IP Address\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Language Profile\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Loading tags…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Loading language profiles…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Loading quality profiles…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Loading root folders…\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Monitor New Seasons\",\n  \"components.Settings.SonarrModal.notagoptions\": \"No tags.\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Quality Profile\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Root Folder\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Season Folders\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Select language profile\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Select quality profile\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Select root folder\",\n  \"components.Settings.SonarrModal.selecttags\": \"Select tags\",\n  \"components.Settings.SonarrModal.seriesType\": \"Series Type\",\n  \"components.Settings.SonarrModal.server4k\": \"4K Server\",\n  \"components.Settings.SonarrModal.servername\": \"Server Name\",\n  \"components.Settings.SonarrModal.ssl\": \"Use SSL\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Enable Scan\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Tag Requests\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Automatically add an additional tag with the requester's user ID & display name\",\n  \"components.Settings.SonarrModal.tags\": \"Tags\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Test connection to load language profiles\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Test connection to load quality profiles\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Test connection to load root folders\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Test connection to load tags\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Failed to connect to Sonarr.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr connection established successfully!\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"You must provide an API key\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"You must provide a valid URL\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL must not end in a trailing slash\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Base URL must have a leading slash\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Base URL must not end in a trailing slash\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"You must provide a valid hostname or IP address\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"You must select a language profile\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"You must provide a server name\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"You must provide a valid port number\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"You must select a quality profile\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"You must select a root folder\",\n  \"components.Settings.activeProfile\": \"Active Profile\",\n  \"components.Settings.addradarr\": \"Add Radarr Server\",\n  \"components.Settings.address\": \"Address\",\n  \"components.Settings.addrule\": \"New Override Rule\",\n  \"components.Settings.addsonarr\": \"Add Sonarr Server\",\n  \"components.Settings.advancedTooltip\": \"Incorrectly configuring this setting may result in broken functionality\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"All chosen metadata providers are operational\",\n  \"components.Settings.animeMetadataProvider\": \"Anime metadata provider\",\n  \"components.Settings.apiKey\": \"API key\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Paste blocklist tag configuration below.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Import Blocklisted Tag Configuration\",\n  \"components.Settings.blocklistedTagsText\": \"Blocklisted Tags\",\n  \"components.Settings.cancelscan\": \"Cancel Scan\",\n  \"components.Settings.chooseProvider\": \"Choose metadata providers for different content types\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Are you sure you want to clear the blocklisted tags?\",\n  \"components.Settings.clickTest\": \"Click on the \\\"Test\\\" button to check connectivity with metadata providers\",\n  \"components.Settings.connectionTestFailed\": \"Connection test failed\",\n  \"components.Settings.copyBlocklistedTags\": \"Copied blocklisted tags to clipboard.\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Nothing to copy\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Copy blocklisted tag configuration\",\n  \"components.Settings.currentlibrary\": \"Current Library: {name}\",\n  \"components.Settings.default\": \"Default\",\n  \"components.Settings.default4k\": \"Default 4K\",\n  \"components.Settings.deleteServer\": \"Delete {serverType} Server\",\n  \"components.Settings.deleteserverconfirm\": \"Are you sure you want to delete this server?\",\n  \"components.Settings.email\": \"Email\",\n  \"components.Settings.enablessl\": \"Use SSL\",\n  \"components.Settings.experimentalTooltip\": \"Enabling this setting may result in unexpected application behavior\",\n  \"components.Settings.externalUrl\": \"External URL\",\n  \"components.Settings.failed\": \"Does not work\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Failed to save metadata provider settings\",\n  \"components.Settings.general\": \"General\",\n  \"components.Settings.hostname\": \"Hostname or IP Address\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Import blocklisted tag configuration\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} is not a TMDB keyword.\",\n  \"components.Settings.invalidurlerror\": \"Unable to connect to {mediaServerName} server.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Forgot Password URL\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName} Settings\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Optionally configure the internal and external endpoints for your {mediaServerName} server. In most cases, the external URL is different to the internal URL. A custom password reset URL can also be set for {mediaServerName} login, in case you would like to redirect to a different password reset page. You can also change the Jellyfin API key, which was automatically generated previously.\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Something went wrong while saving {mediaServerName} settings.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName} settings saved successfully!\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Custom authentication with Automatic Library Grouping not supported\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Something went wrong while syncing libraries\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"No libraries were found\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName} Libraries\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"The libraries {mediaServerName} scans for titles. Click the button below if no libraries are listed.\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName} Settings\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Configure the settings for your {mediaServerName} server. {mediaServerName} scans your {mediaServerName} libraries to see what content is available.\",\n  \"components.Settings.librariesRemaining\": \"Libraries Remaining: {count}\",\n  \"components.Settings.manualscan\": \"Manual Library Scan\",\n  \"components.Settings.manualscanDescription\": \"Normally, this will only be run once every 24 hours. Seerr 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!\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normally, this will only be run once every 24 hours. Seerr will check your {mediaServerName} server's recently added more aggressively. If this is your first time configuring Seerr, a one-time full manual library scan is recommended!\",\n  \"components.Settings.manualscanJellyfin\": \"Manual Library Scan\",\n  \"components.Settings.mediaTypeMovie\": \"movie\",\n  \"components.Settings.mediaTypeSeries\": \"series\",\n  \"components.Settings.menuAbout\": \"About\",\n  \"components.Settings.menuGeneralSettings\": \"General\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.menuJobs\": \"Jobs & Cache\",\n  \"components.Settings.menuLogs\": \"Logs\",\n  \"components.Settings.menuMetadataProviders\": \"Metadata Providers\",\n  \"components.Settings.menuNetwork\": \"Network\",\n  \"components.Settings.menuNotifications\": \"Notifications\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Services\",\n  \"components.Settings.menuUsers\": \"Users\",\n  \"components.Settings.metadataProviderSelection\": \"Metadata Provider Selection\",\n  \"components.Settings.metadataProviderSettings\": \"Metadata Providers\",\n  \"components.Settings.metadataSettings\": \"Settings for metadata provider\",\n  \"components.Settings.metadataSettingsSaved\": \"Metadata provider settings saved\",\n  \"components.Settings.no\": \"No\",\n  \"components.Settings.noDefault4kServer\": \"A 4K {serverType} server must be marked as default in order to enable users to submit 4K {mediaType} requests.\",\n  \"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 <strong>NOT</strong> be designated as a 4K server.\",\n  \"components.Settings.noDefaultServer\": \"At least one {serverType} server must be marked as default in order for {mediaType} requests to be processed.\",\n  \"components.Settings.noSpecialCharacters\": \"Configuration must be a comma delimited list of TMDB keyword ids, and must not start or end with a comma.\",\n  \"components.Settings.nooptions\": \"No results.\",\n  \"components.Settings.notTested\": \"Not Tested\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Configure and enable notification agents.\",\n  \"components.Settings.notifications\": \"Notifications\",\n  \"components.Settings.notificationsettings\": \"Notification Settings\",\n  \"components.Settings.notrunning\": \"Not Running\",\n  \"components.Settings.operational\": \"Operational\",\n  \"components.Settings.overrideRules\": \"Override Rules\",\n  \"components.Settings.overrideRulesDescription\": \"Override rules allow you to specify properties that will be replaced if a request matches the rule.\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.plexlibraries\": \"Plex Libraries\",\n  \"components.Settings.plexlibrariesDescription\": \"The libraries Seerr scans for titles. Set up and save your Plex connection settings, then click the button below if no libraries are listed.\",\n  \"components.Settings.plexsettings\": \"Plex Settings\",\n  \"components.Settings.plexsettingsDescription\": \"Configure the settings for your Plex server. Seerr scans your Plex libraries to determine content availability.\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.providerStatus\": \"Metadata Provider Status\",\n  \"components.Settings.radarrsettings\": \"Radarr Settings\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr must be restarted for changes to this setting to take effect\",\n  \"components.Settings.save\": \"Save Changes\",\n  \"components.Settings.saving\": \"Saving…\",\n  \"components.Settings.scan\": \"Sync Libraries\",\n  \"components.Settings.scanbackground\": \"Scanning will run in the background. You can continue the setup process in the meantime.\",\n  \"components.Settings.scanning\": \"Syncing…\",\n  \"components.Settings.searchKeywords\": \"Search keywords…\",\n  \"components.Settings.seriesMetadataProvider\": \"Series metadata provider\",\n  \"components.Settings.serverLocal\": \"local\",\n  \"components.Settings.serverRemote\": \"remote\",\n  \"components.Settings.serverSecure\": \"secure\",\n  \"components.Settings.serverpreset\": \"Server\",\n  \"components.Settings.serverpresetLoad\": \"Press the button to load available servers\",\n  \"components.Settings.serverpresetManualMessage\": \"Manual configuration\",\n  \"components.Settings.serverpresetRefreshing\": \"Retrieving servers…\",\n  \"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.\",\n  \"components.Settings.services\": \"Services\",\n  \"components.Settings.settingUpPlexDescription\": \"To set up Plex, you can either enter the details manually or select a server retrieved from <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Press the button to the right of the dropdown to fetch the list of available servers.\",\n  \"components.Settings.settings\": \"Settings\",\n  \"components.Settings.sonarrsettings\": \"Sonarr Settings\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Start Scan\",\n  \"components.Settings.starttyping\": \"Starting typing to search.\",\n  \"components.Settings.syncJellyfin\": \"Sync Libraries\",\n  \"components.Settings.syncing\": \"Syncing\",\n  \"components.Settings.tautulliApiKey\": \"API Key\",\n  \"components.Settings.tautulliSettings\": \"Tautulli Settings\",\n  \"components.Settings.tautulliSettingsDescription\": \"Optionally configure the settings for your Tautulli server. Seerr fetches watch history data for your Plex media from Tautulli.\",\n  \"components.Settings.timeout\": \"Timeout\",\n  \"components.Settings.tip\": \"Tip\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"TMDB provider does not work, please select another metadata provider\",\n  \"components.Settings.toastPlexConnecting\": \"Attempting to connect to Plex…\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Failed to connect to Plex.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex connection established successfully!\",\n  \"components.Settings.toastPlexRefresh\": \"Retrieving server list from Plex…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Failed to retrieve Plex server list.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Plex server list retrieved successfully!\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Something went wrong while saving Tautulli settings.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli settings saved successfully!\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"TVDB provider does not work, please select another metadata provider\",\n  \"components.Settings.urlBase\": \"URL Base\",\n  \"components.Settings.validationApiKey\": \"You must provide an API key\",\n  \"components.Settings.validationHostnameRequired\": \"You must provide a valid hostname or IP address\",\n  \"components.Settings.validationPortRequired\": \"You must provide a valid port number\",\n  \"components.Settings.validationUrl\": \"You must provide a valid URL\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL base must have a leading slash\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"URL base must not end in a trailing slash\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL must not end in a trailing slash\",\n  \"components.Settings.valueRequired\": \"You must provide a value.\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Web App</WebAppLink> URL\",\n  \"components.Settings.webAppUrlTip\": \"Optionally direct users to the web app on your server instead of the \\\"hosted\\\" web app\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Settings.yes\": \"Yes\",\n  \"components.Setup.back\": \"Go back\",\n  \"components.Setup.configemby\": \"Configure Emby\",\n  \"components.Setup.configjellyfin\": \"Configure Jellyfin\",\n  \"components.Setup.configplex\": \"Configure Plex\",\n  \"components.Setup.configuremediaserver\": \"Configure Media Server\",\n  \"components.Setup.configureservices\": \"Configure Services\",\n  \"components.Setup.continue\": \"Continue\",\n  \"components.Setup.finish\": \"Finish Setup\",\n  \"components.Setup.finishing\": \"Finishing…\",\n  \"components.Setup.librarieserror\": \"Validation failed. Please toggle the libraries again to continue.\",\n  \"components.Setup.servertype\": \"Choose Server Type\",\n  \"components.Setup.setup\": \"Setup\",\n  \"components.Setup.signin\": \"Sign In\",\n  \"components.Setup.signinMessage\": \"Get started by signing in\",\n  \"components.Setup.signinWithEmby\": \"Enter your Emby details\",\n  \"components.Setup.signinWithJellyfin\": \"Enter your Jellyfin details\",\n  \"components.Setup.signinWithPlex\": \"Enter your Plex details\",\n  \"components.Setup.subtitle\": \"Get started by choosing your media server\",\n  \"components.Setup.welcome\": \"Welcome to Seerr\",\n  \"components.StatusBadge.managemedia\": \"Manage {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Open in {arr}\",\n  \"components.StatusBadge.playonplex\": \"Play on {mediaServerName}\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Updated\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Please click the button below to reload the application.\",\n  \"components.StatusChecker.reloadApp\": \"Reload {applicationTitle}\",\n  \"components.StatusChecker.restartRequired\": \"Server Restart Required\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Please restart the server to apply the updated settings.\",\n  \"components.TitleCard.addToWatchList\": \"Add to watchlist\",\n  \"components.TitleCard.cleardata\": \"Clear Data\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} Not Found\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.TitleCard.watchlistCancel\": \"watchlist for <strong>{title}</strong> canceled.\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> Removed from watchlist  successfully!\",\n  \"components.TitleCard.watchlistError\": \"Something went wrong. Please try again.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> added to watchlist  successfully!\",\n  \"components.TvDetails.Season.noepisodes\": \"Episode list unavailable.\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Something went wrong while retrieving season data.\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Full Series Cast\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Full Series Crew\",\n  \"components.TvDetails.addtowatchlist\": \"Add To Watchlist\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.cast\": \"Cast\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Episode} other {# Episodes}}\",\n  \"components.TvDetails.episodeRuntime\": \"Episode Runtime\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutes\",\n  \"components.TvDetails.firstAirDate\": \"First Air Date\",\n  \"components.TvDetails.manageseries\": \"Manage Series\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Network} other {Networks}}\",\n  \"components.TvDetails.nextAirDate\": \"Next Air Date\",\n  \"components.TvDetails.originallanguage\": \"Original Language\",\n  \"components.TvDetails.originaltitle\": \"Original Title\",\n  \"components.TvDetails.overview\": \"Overview\",\n  \"components.TvDetails.overviewunavailable\": \"Overview unavailable.\",\n  \"components.TvDetails.play\": \"Play on {mediaServerName}\",\n  \"components.TvDetails.play4k\": \"Play 4K on {mediaServerName}\",\n  \"components.TvDetails.productioncountries\": \"Production {countryCount, plural, one {Country} other {Countries}}\",\n  \"components.TvDetails.recommendations\": \"Recommendations\",\n  \"components.TvDetails.removefromwatchlist\": \"Remove From Watchlist\",\n  \"components.TvDetails.reportissue\": \"Report an Issue\",\n  \"components.TvDetails.rtaudiencescore\": \"Rotten Tomatoes Audience Score\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.TvDetails.seasonnumber\": \"Season {seasonNumber}\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Season} other {# Seasons}}\",\n  \"components.TvDetails.seasonstitle\": \"Seasons\",\n  \"components.TvDetails.showtype\": \"Series Type\",\n  \"components.TvDetails.similar\": \"Similar Series\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.streamingproviders\": \"Currently Streaming On\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB User Score\",\n  \"components.TvDetails.viewfullcrew\": \"View Full Crew\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> Removed from watchlist successfully!\",\n  \"components.TvDetails.watchlistError\": \"Something went wrong. Please try again.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> added to watchlist successfully!\",\n  \"components.TvDetails.watchtrailer\": \"Watch Trailer\",\n  \"components.UserList.accounttype\": \"Type\",\n  \"components.UserList.admin\": \"Admin\",\n  \"components.UserList.autogeneratepassword\": \"Automatically Generate Password\",\n  \"components.UserList.autogeneratepasswordTip\": \"Email a server-generated password to the user\",\n  \"components.UserList.bulkedit\": \"Bulk Edit\",\n  \"components.UserList.create\": \"Create\",\n  \"components.UserList.created\": \"Joined\",\n  \"components.UserList.createlocaluser\": \"Create Local User\",\n  \"components.UserList.creating\": \"Creating…\",\n  \"components.UserList.deleteconfirm\": \"Are you sure you want to delete this user? All of their request data will be permanently removed.\",\n  \"components.UserList.deleteuser\": \"Delete User\",\n  \"components.UserList.edituser\": \"Edit User Permissions\",\n  \"components.UserList.email\": \"Email Address\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} imported successfully!\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {user} other {users}} imported successfully!\",\n  \"components.UserList.importfromJellyfin\": \"Import {mediaServerName} Users\",\n  \"components.UserList.importfromJellyfinerror\": \"Something went wrong while importing {mediaServerName} users.\",\n  \"components.UserList.importfrommediaserver\": \"Import {mediaServerName} Users\",\n  \"components.UserList.importfromplex\": \"Import Plex Users\",\n  \"components.UserList.importfromplexerror\": \"Something went wrong while importing Plex users.\",\n  \"components.UserList.localLoginDisabled\": \"The <strong>Enable Local Sign-In</strong> setting is currently disabled.\",\n  \"components.UserList.localuser\": \"Local User\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName} User\",\n  \"components.UserList.newJellyfinsigninenabled\": \"The <strong>Enable New {mediaServerName} Sign-In</strong> setting is currently enabled. {mediaServerName} users with library access do not need to be imported in order to sign in.\",\n  \"components.UserList.newplexsigninenabled\": \"The <strong>Enable New Plex Sign-In</strong> setting is currently enabled. Plex users with library access do not need to be imported in order to sign in.\",\n  \"components.UserList.noJellyfinuserstoimport\": \"There are no {mediaServerName} users to import.\",\n  \"components.UserList.nouserstoimport\": \"There are no Plex users to import.\",\n  \"components.UserList.owner\": \"Owner\",\n  \"components.UserList.password\": \"Password\",\n  \"components.UserList.passwordinfodescription\": \"Configure an application URL and enable email notifications to allow automatic password generation.\",\n  \"components.UserList.plexuser\": \"Plex User\",\n  \"components.UserList.role\": \"Role\",\n  \"components.UserList.sortCreated\": \"Join Date\",\n  \"components.UserList.sortDisplayName\": \"Display Name\",\n  \"components.UserList.sortRequests\": \"Request Count\",\n  \"components.UserList.totalrequests\": \"Requests\",\n  \"components.UserList.user\": \"User\",\n  \"components.UserList.usercreatedfailed\": \"Something went wrong while creating the user.\",\n  \"components.UserList.usercreatedfailedexisting\": \"The provided email address is already in use by another user.\",\n  \"components.UserList.usercreatedsuccess\": \"User created successfully!\",\n  \"components.UserList.userdeleted\": \"User deleted successfully!\",\n  \"components.UserList.userdeleteerror\": \"Something went wrong while deleting the user.\",\n  \"components.UserList.userfail\": \"Something went wrong while saving user permissions.\",\n  \"components.UserList.userlist\": \"User List\",\n  \"components.UserList.username\": \"Username\",\n  \"components.UserList.users\": \"Users\",\n  \"components.UserList.userssaved\": \"User permissions saved successfully!\",\n  \"components.UserList.validationEmail\": \"Email required\",\n  \"components.UserList.validationUsername\": \"You must provide an username\",\n  \"components.UserList.validationpasswordminchars\": \"Password is too short; should be a minimum of 8 characters\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Joined {joindate}\",\n  \"components.UserProfile.ProfileHeader.profile\": \"View Profile\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Edit Settings\",\n  \"components.UserProfile.ProfileHeader.userid\": \"User ID: {userid}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Enter your {mediaServerName} credentials to link your account with {applicationName}.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"This account is already linked to a {applicationName} user\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Unable to connect to {mediaServerName} using your credentials\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"An unknown error occurred\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Password\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"You must provide a password\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Link\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Adding…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Link {mediaServerName} Account\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Username\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"You must provide a username\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Account Type\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Admin\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Display Language\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord User ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"The <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> associated with your Discord user account\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Discover Region\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Filter content by regional availability\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Display Name\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Override Global Limit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"General\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"General Settings\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Default ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Local User\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName} User\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Movie Request Limit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Discover Language\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filter content by original language\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Owner\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex User\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Auto-Request Movies\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Automatically request movies on your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Auto-Request Series\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Automatically request series on your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Discover Region\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filter content by regional availability\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Role\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Save Changes\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Saving…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Series Request Limit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Streaming Region\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Show streaming sites by regional availability\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Something went wrong while saving settings.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"This email is already taken!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Another user already has this username. You must set an email\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Settings saved successfully!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"User\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"You must provide a valid Discord user ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Valid email required\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Email required\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Unable to delete linked account.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"An unknown error occurred\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Linked Accounts\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"These external accounts are linked to your {applicationName} account.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"You do not have any external accounts linked to your account.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"You do not have permission to modify this user's linked accounts.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"This account is already linked to a Plex user\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Unable to connect to Plex using your credentials\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Active Subscription\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Browser\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Created\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Delete Subscription\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Device\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Disable web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Something went wrong while disabling web push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Enable web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Something went wrong while enabling web push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Engine\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Manage Devices\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"You have no web push subscriptions to show.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Operating System\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Subscription deleted.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Something went wrong while deleting the user subscription.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"type\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Unknown\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Web push has been disabled.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Web push has been enabled.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Web push notification settings failed to save.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Web push notification settings saved successfully!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Device Default\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"User ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"The <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> associated with your user account\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Discord notification settings failed to save.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord notification settings saved successfully!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Email notification settings failed to save.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Email notification settings saved successfully!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notifications\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Notification Settings\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"PGP Public Key\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Encrypt email messages using <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Access Token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Create a token from your <PushbulletSettingsLink>Account Settings</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Pushbullet notification settings failed to save.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet notification settings saved successfully!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Application API Token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Register an application</ApplicationRegistrationLink> for use with {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"User or Group Key\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Pushover notification settings failed to save.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover notification settings saved successfully!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Send Silently\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Send notifications with no sound\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Notification Sound\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chat ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Start a chat</TelegramBotLink>, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Thread/Topic ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"If your group-chat has topics enabled, you can specify a thread/topic's ID here\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Telegram notification settings failed to save.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram notification settings saved successfully!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"You must provide a valid user ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"You must provide a valid PGP public key\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"You must provide an access token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"You must provide a valid application token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"You must provide a valid user or group key\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"You must provide a valid chat ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"The thread/topic ID must be a positive whole number\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Confirm Password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Current Password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"New Password\",\n  \"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.\\\"\",\n  \"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.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"You do not have permission to modify this user's password.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Something went wrong while saving the password.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Something went wrong while saving the password. Was your current password entered correctly?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Password saved successfully!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"You must confirm the new password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Passwords must match\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"You must provide your current password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"You must provide a new password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Password is too short; should be a minimum of 8 characters\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Permissions\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Something went wrong while saving settings.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Permissions saved successfully!\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"You cannot modify your own permissions.\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Password\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"General\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Linked Accounts\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notifications\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Permissions\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"You do not have permission to modify this user's settings.\",\n  \"components.UserProfile.emptywatchlist\": \"Media added to your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> will appear here.\",\n  \"components.UserProfile.limit\": \"{remaining} of {limit}\",\n  \"components.UserProfile.localWatchlist\": \"{username}'s Watchlist\",\n  \"components.UserProfile.movierequests\": \"Movie Requests\",\n  \"components.UserProfile.pastdays\": \"{type} (past {days} days)\",\n  \"components.UserProfile.plexwatchlist\": \"Plex Watchlist\",\n  \"components.UserProfile.recentlywatched\": \"Recently Watched\",\n  \"components.UserProfile.recentrequests\": \"Recent Requests\",\n  \"components.UserProfile.requestsperdays\": \"{limit} remaining\",\n  \"components.UserProfile.seriesrequest\": \"Series Requests\",\n  \"components.UserProfile.totalrequests\": \"Total Requests\",\n  \"components.UserProfile.unlimited\": \"Unlimited\",\n  \"i18n.addToBlocklist\": \"Add to Blocklist\",\n  \"i18n.advanced\": \"Advanced\",\n  \"i18n.all\": \"All\",\n  \"i18n.approve\": \"Approve\",\n  \"i18n.approved\": \"Approved\",\n  \"i18n.areyousure\": \"Are you sure?\",\n  \"i18n.available\": \"Available\",\n  \"i18n.back\": \"Back\",\n  \"i18n.blocklist\": \"Blocklist\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> has already been blocklisted.\",\n  \"i18n.blocklistError\": \"Something went wrong. Please try again.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> was successfully blocklisted.\",\n  \"i18n.blocklisted\": \"Blocklisted\",\n  \"i18n.cancel\": \"Cancel\",\n  \"i18n.canceling\": \"Canceling…\",\n  \"i18n.close\": \"Close\",\n  \"i18n.collection\": \"Collection\",\n  \"i18n.completed\": \"Completed\",\n  \"i18n.decline\": \"Decline\",\n  \"i18n.declined\": \"Declined\",\n  \"i18n.delete\": \"Delete\",\n  \"i18n.deleted\": \"Deleted\",\n  \"i18n.deleting\": \"Deleting…\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.edit\": \"Edit\",\n  \"i18n.error\": \"Something went wrong. Please try again.\",\n  \"i18n.experimental\": \"Experimental\",\n  \"i18n.failed\": \"Failed\",\n  \"i18n.import\": \"Import\",\n  \"i18n.importing\": \"Importing…\",\n  \"i18n.loading\": \"Loading…\",\n  \"i18n.movie\": \"Movie\",\n  \"i18n.movies\": \"Movies\",\n  \"i18n.next\": \"Next\",\n  \"i18n.noresults\": \"No results.\",\n  \"i18n.notrequested\": \"Not Requested\",\n  \"i18n.open\": \"Open\",\n  \"i18n.partiallyavailable\": \"Partially Available\",\n  \"i18n.pending\": \"Pending\",\n  \"i18n.previous\": \"Previous\",\n  \"i18n.processing\": \"Processing\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> was successfully removed from the Blocklist.\",\n  \"i18n.removefromBlocklist\": \"Remove from Blocklist\",\n  \"i18n.request\": \"Request\",\n  \"i18n.request4k\": \"Request in 4K\",\n  \"i18n.requested\": \"Requested\",\n  \"i18n.requesting\": \"Requesting…\",\n  \"i18n.resolved\": \"Resolved\",\n  \"i18n.restartRequired\": \"Restart Required\",\n  \"i18n.resultsperpage\": \"Display {pageSize} results per page\",\n  \"i18n.retry\": \"Retry\",\n  \"i18n.retrying\": \"Retrying…\",\n  \"i18n.save\": \"Save Changes\",\n  \"i18n.saving\": \"Saving…\",\n  \"i18n.settings\": \"Settings\",\n  \"i18n.showingresults\": \"Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results\",\n  \"i18n.specials\": \"Specials\",\n  \"i18n.status\": \"Status\",\n  \"i18n.test\": \"Test\",\n  \"i18n.testing\": \"Testing…\",\n  \"i18n.tvshow\": \"Series\",\n  \"i18n.tvshows\": \"Series\",\n  \"i18n.unavailable\": \"Unavailable\",\n  \"i18n.usersettings\": \"User Settings\",\n  \"i18n.view\": \"View\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"Internal Server Error\",\n  \"pages.oops\": \"Oops\",\n  \"pages.pagenotfound\": \"Page Not Found\",\n  \"pages.returnHome\": \"Return Home\",\n  \"pages.serviceunavailable\": \"Service Unavailable\",\n  \"pages.somethingwentwrong\": \"Something Went Wrong\"\n}\n"
  },
  {
    "path": "src/i18n/locale/es.json",
    "content": "{\n  \"components.Settings.SonarrModal.ssl\": \"Usar SSL\",\n  \"components.Settings.SonarrModal.servername\": \"Nombre del Servidor\",\n  \"components.Settings.SonarrModal.server4k\": \"Servidor 4K\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Selecciona la carpeta raíz\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Selecciona un perfil de calidad\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Carpetas por Temporada\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Carpeta Raíz\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Perfil de Calidad\",\n  \"components.Settings.SonarrModal.port\": \"Puerto\",\n  \"components.Settings.SonarrModal.hostname\": \"Nombre de Host o Dirección IP\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Editar Servidor Sonarr\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Servidor por Defecto\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Añadir Nuevo Servidor Sonarr\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL de base\",\n  \"components.Settings.SonarrModal.apiKey\": \"Clave API\",\n  \"components.Settings.SonarrModal.add\": \"Agregar Servidor\",\n  \"components.Settings.SettingsAbout.version\": \"Versión\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Peticiones Totales\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Contenido Total\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Discursiones en GitHub\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Soporte\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Debes seleccionar una carpeta raíz\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Debes seleccionar un perfil de calidad\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Debes proporcionar un número de puerto válido\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Debes proporcionar un nombre de servidor\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Debes proporcionar un nombre de host o dirección IP válido\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Debes proporcionar la clave API\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"¡Conexión con Radarr establecida con éxito!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Error al connectar al Radarr.\",\n  \"components.Settings.RadarrModal.ssl\": \"Usar SSL\",\n  \"components.Settings.RadarrModal.servername\": \"Nombre del Servidor\",\n  \"components.Settings.RadarrModal.server4k\": \"Servidor 4K\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Selecciona la carpeta raíz\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Selecciona un perfil de calidad\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Selecciona Disponibilidad Mínima\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Carpeta Raíz\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Perfil de Calidad\",\n  \"components.Settings.RadarrModal.port\": \"Puerto\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Disponibilidad Mínima\",\n  \"components.Settings.RadarrModal.hostname\": \"Nombre de Host o Dirección IP\",\n  \"components.Settings.RadarrModal.editradarr\": \"Editar Servidor Radarr\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Servidor por Defecto\",\n  \"components.Settings.RadarrModal.createradarr\": \"Añadir Nuevo Servidor Radarr\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL de base\",\n  \"components.Settings.RadarrModal.apiKey\": \"Clave API\",\n  \"components.Settings.RadarrModal.add\": \"Agregar Servidor\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Debes proporcionar un número de puerto válido\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Debes proporcionar un nombre válido de host o una dirección IP\",\n  \"components.Settings.Notifications.smtpPort\": \"Puerto SMTP\",\n  \"components.Settings.Notifications.smtpHost\": \"Host SMTP\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"¡Ajustes de notificación de Email guardados con éxito!\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Fallo al guardar ajustes de notificación de Email.\",\n  \"components.Settings.Notifications.emailsender\": \"Dirección del Remitente\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"¡Ajustes de notificación de Discord guardados con éxito!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Fallo al guardar ajustes de notificación de Discord.\",\n  \"components.Settings.Notifications.authUser\": \"Usuario SMTP\",\n  \"components.Settings.Notifications.authPass\": \"Contraseña SMTP\",\n  \"components.Settings.Notifications.agentenabled\": \"Habilitar Agente\",\n  \"components.Search.searchresults\": \"Resultado de la búsqueda\",\n  \"components.RequestModal.selectseason\": \"Seleccionar Temporada(s)\",\n  \"components.RequestModal.seasonnumber\": \"Temporada {number}\",\n  \"components.RequestModal.season\": \"Temporada\",\n  \"components.RequestModal.requestseasons\": \"Solicitar {seasonCount} {seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestModal.requestfrom\": \"La solicitud de {username} está pendiente de aprobación.\",\n  \"components.RequestModal.requestadmin\": \"Esta solicitud será aprobada automáticamente.\",\n  \"components.RequestModal.requestSuccess\": \"¡<strong>{title}</strong> solicitada con éxito!\",\n  \"components.RequestModal.requestCancel\": \"Solicitud para <strong>{title}</strong> cancelada.\",\n  \"components.RequestModal.pendingrequest\": \"Solicitud pendiente\",\n  \"components.RequestModal.numberofepisodes\": \"# de Episodios\",\n  \"components.RequestModal.cancel\": \"Cancelar Petición\",\n  \"components.RequestList.requests\": \"Solicitudes\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.PersonDetails.ascharacter\": \"como {character}\",\n  \"components.PersonDetails.appearsin\": \"Apariciones\",\n  \"components.MovieDetails.similar\": \"Títulos Similares\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutos\",\n  \"components.MovieDetails.revenue\": \"Recaudado\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Fecha} other {Fechas}} de Lanzamiento\",\n  \"components.MovieDetails.cast\": \"Reparto\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Reparto Completo\",\n  \"components.MovieDetails.recommendations\": \"Recomendaciones\",\n  \"components.MovieDetails.overviewunavailable\": \"Resumen indisponible.\",\n  \"components.MovieDetails.overview\": \"Resumen\",\n  \"components.MovieDetails.originallanguage\": \"Idioma Original\",\n  \"components.MovieDetails.budget\": \"Presupuesto\",\n  \"components.Layout.UserDropdown.signout\": \"Cerrar Sesión\",\n  \"components.Layout.Sidebar.users\": \"Usuarios\",\n  \"components.Layout.Sidebar.settings\": \"Ajustes\",\n  \"components.Layout.Sidebar.requests\": \"Solicitudes\",\n  \"components.Layout.Sidebar.dashboard\": \"Descubrir\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Buscar Películas y Series\",\n  \"components.Discover.upcomingmovies\": \"Próximas Películas\",\n  \"components.Discover.upcoming\": \"Próximas Películas\",\n  \"components.Discover.trending\": \"Tendencias\",\n  \"components.Discover.recentrequests\": \"Peticiones Recientes\",\n  \"components.Discover.recentlyAdded\": \"Agregado Recientemente\",\n  \"components.Discover.populartv\": \"Series Populares\",\n  \"components.Discover.popularmovies\": \"Películas Populares\",\n  \"components.Settings.addsonarr\": \"Agregar servidor Sonarr\",\n  \"components.Settings.address\": \"Dirección\",\n  \"components.Settings.addradarr\": \"Agregar servidor Radarr\",\n  \"components.Settings.activeProfile\": \"Perfil activo\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Debes seleccionar una carpeta raíz\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Debes seleccionar un perfil\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Debes proporcionar un número de puerto valido\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Debes proporcionar un nombre de servidor\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Debes proporcionar un nombre de host o dirección IP válido\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Debes proporcionar la clave API\",\n  \"components.Settings.menuLogs\": \"Registro\",\n  \"pages.returnHome\": \"Volver al Inicio\",\n  \"pages.oops\": \"Ups\",\n  \"i18n.unavailable\": \"No Disponible\",\n  \"i18n.tvshows\": \"Series\",\n  \"i18n.processing\": \"Procesando\",\n  \"i18n.pending\": \"Pendiente\",\n  \"i18n.partiallyavailable\": \"Parcialmente Disponible\",\n  \"i18n.movies\": \"Películas\",\n  \"i18n.delete\": \"Eliminar\",\n  \"i18n.declined\": \"Rechazado\",\n  \"i18n.decline\": \"Rechazar\",\n  \"i18n.cancel\": \"Cancelar\",\n  \"i18n.available\": \"Disponible\",\n  \"i18n.approved\": \"Aprobado\",\n  \"i18n.approve\": \"Aprobar\",\n  \"components.UserList.userlist\": \"Lista de usuarios\",\n  \"components.UserList.user\": \"Usuario\",\n  \"components.UserList.totalrequests\": \"Solicitudes\",\n  \"components.UserList.role\": \"Rol\",\n  \"components.UserList.plexuser\": \"Usuario de Plex\",\n  \"components.UserList.created\": \"Unido\",\n  \"components.UserList.admin\": \"Administrador\",\n  \"components.TvDetails.similar\": \"Series Similares\",\n  \"components.TvDetails.recommendations\": \"Recomendaciones\",\n  \"components.TvDetails.overviewunavailable\": \"Resumen no disponible.\",\n  \"components.TvDetails.overview\": \"Resumen\",\n  \"components.TvDetails.originallanguage\": \"Idioma original\",\n  \"components.TvDetails.cast\": \"Reparto\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Reparto completo de la serie\",\n  \"components.Setup.welcome\": \"Bienvenido a Seerr\",\n  \"components.Setup.signinMessage\": \"Comience iniciando sesión con su cuenta de Plex\",\n  \"components.Setup.finishing\": \"Finalizando…\",\n  \"components.Setup.finish\": \"Finalizar configuración\",\n  \"components.Setup.continue\": \"Continuar\",\n  \"components.Setup.configureservices\": \"Configurar servicios\",\n  \"components.Settings.validationPortRequired\": \"Debes proporcionar un número de puerto válido\",\n  \"components.Settings.validationHostnameRequired\": \"Debes proporcionar un nombre de host o dirección IP válido\",\n  \"components.Settings.startscan\": \"Iniciar Escaneo\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.sonarrsettings\": \"Ajustes de Sonarr\",\n  \"components.Settings.radarrsettings\": \"Ajustes de Radarr\",\n  \"components.Settings.port\": \"Puerto\",\n  \"components.Settings.plexsettingsDescription\": \"Configure los ajustes de su servidor Plex. Seerr escanea tu biblioteca para determinar la disponibilidad de contenidos.\",\n  \"components.Settings.plexsettings\": \"Ajustes de Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"Las bibliotecas en las que Seerr 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.\",\n  \"components.Settings.plexlibraries\": \"Bibliotecas Plex\",\n  \"components.Settings.notrunning\": \"Sin ejecutarse\",\n  \"components.Settings.notificationsettings\": \"Configuración de notificaciones\",\n  \"components.Settings.menuServices\": \"Servicios\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Notificaciones\",\n  \"components.Settings.menuJobs\": \"Tareas y Caché\",\n  \"components.Settings.menuGeneralSettings\": \"General\",\n  \"components.Settings.menuAbout\": \"Acerca de\",\n  \"components.Settings.manualscanDescription\": \"Normalmente, esto sólo se ejecutará una vez cada 24 horas. Seerr comprobará de forma más agresiva los añadidos recientemente de su servidor Plex. ¡Si es la primera vez que configura Plex, se recomienda un escaneo manual completo de la biblioteca!\",\n  \"components.Settings.manualscan\": \"Escaneo Manual de Biblioteca\",\n  \"components.Settings.librariesRemaining\": \"Bibliotecas restantes: {count}\",\n  \"components.Settings.hostname\": \"Nombre de host o Dirección IP\",\n  \"components.Settings.deleteserverconfirm\": \"¿Está seguro de que desea eliminar este servidor?\",\n  \"components.Settings.default4k\": \"4K predeterminado\",\n  \"components.Settings.default\": \"Predeterminado\",\n  \"components.Settings.currentlibrary\": \"Biblioteca actual: {name}\",\n  \"components.Settings.cancelscan\": \"Cancelar Escaneo\",\n  \"i18n.deleting\": \"Eliminando…\",\n  \"components.UserList.userdeleteerror\": \"Algo salió mal al eliminar al usuario.\",\n  \"components.UserList.userdeleted\": \"¡Usuario eliminado con éxito!\",\n  \"components.UserList.deleteuser\": \"Eliminar usuario\",\n  \"components.UserList.deleteconfirm\": \"¿Está seguro de que desea eliminar este usuario? Se eliminarán todas sus solicitudes de forma permanente.\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Probar conexión para cargar carpetas raíz\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Probar conexión para cargar perfiles de calidad\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Cargando carpetas raíz…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Cargando perfiles de calidad…\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Debes seleccionar disponibilidad mínima\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Prueba la conexión para cargar carpetas raíz\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Prueba la conexión para cargar perfiles de calidad\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Cargando carpetas raíz…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Cargando perfiles de calidad…\",\n  \"i18n.close\": \"Cerrar\",\n  \"components.TvDetails.showtype\": \"Tipos de Series\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Red} other {Redes}}\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Carpeta raíz de anime\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Perfil de calidad de anime\",\n  \"components.Settings.SettingsAbout.timezone\": \"Zona horaria\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Ver en GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Ver registro de cambios\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Cambios de la versión {version}\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Versiones\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"La fecha de lanzamiento no está actualmente disponible.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Última Versión\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Actual\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Estudio} other {Estudios}}\",\n  \"components.UserList.importfromplexerror\": \"Algo salió mal importando usuarios de Plex.\",\n  \"components.UserList.importfromplex\": \"Importar Usuarios de Plex\",\n  \"components.UserList.importedfromplex\": \"<strong> {userCount} </strong> Plex {userCount, plural, one {usuario} other {usuarios}} importado correctamente!\",\n  \"components.TvDetails.viewfullcrew\": \"Ver Equipo Completo\",\n  \"components.TvDetails.firstAirDate\": \"Primera fecha de emisión\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Equipo completo de la serie\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Permitir certificados autofirmados\",\n  \"components.PersonDetails.crewmember\": \"Equipo\",\n  \"components.MovieDetails.viewfullcrew\": \"Ver Equipo Completo\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Equipo Completo\",\n  \"components.CollectionDetails.requestcollection\": \"Solicitar Colección\",\n  \"components.CollectionDetails.overview\": \"Resumen\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Películas\",\n  \"i18n.retry\": \"Reintentar\",\n  \"i18n.requested\": \"Solicitado\",\n  \"i18n.failed\": \"Fallido\",\n  \"components.TvDetails.watchtrailer\": \"Ver Trailer\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"¡Ajustes de notificación de Slack guardados con éxito!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Fallo al guardar ajustes de notificación de Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Habilitar Agente\",\n  \"components.RequestList.RequestItem.failedretry\": \"Algo salió mal al reintentar la solicitud.\",\n  \"components.MovieDetails.watchtrailer\": \"Ver Trailer\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Envía una notificación cuando se solicita nuevo contenido que requiere ser aprobado.\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentación\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Debes proporcionar un ID de chat válido\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Debes proporcionar un token de autorización del bot\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"¡Se han guardado los ajustes de notificación de Telegram con éxito!\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"La configuración de notificaciones de Telegram no se pudo guardar.\",\n  \"components.Settings.Notifications.senderName\": \"Nombre del remitente\",\n  \"components.Settings.Notifications.chatId\": \"ID de chat\",\n  \"components.Settings.Notifications.botAPI\": \"Token de Autorización del Bot\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Petición pendiente de aprobar\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Envía una notificación cuando el contenido no se agrega a los servicios (Radarr / Sonarr).\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Procesamiento de Petición Fallida\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Envía una notificación cuando el contenido solicitado está disponible.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Petición Disponible\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Envía una notificación cuando el contenido solicitado es aprobado manualmente.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Petición Aprobada\",\n  \"i18n.request\": \"Solicitar\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Debes proporcionar una clave de usuario o grupo válida\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Debes proporcionar un token de aplicación válido\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Clave de usuario o grupo\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"¡Se han guardado los ajustes de notificación de Pushover!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"No se pudo guardar la configuración de notificaciones de Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Agente habilitado\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token de aplicación API\",\n  \"components.RequestList.sortModified\": \"Última modificación\",\n  \"components.RequestList.sortAdded\": \"Más Reciente\",\n  \"components.RequestList.showallrequests\": \"Mostrar todas las solicitudes\",\n  \"components.RequestBlock.requestoverrides\": \"Anulaciones de solicitudes\",\n  \"i18n.edit\": \"Editar\",\n  \"components.UserList.validationpasswordminchars\": \"La contraseña es demasiado corta; debe tener 8 caracteres como mínimo\",\n  \"components.UserList.usercreatedsuccess\": \"¡Usuario creado con éxito!\",\n  \"components.UserList.usercreatedfailed\": \"Algo salió mal al intentar crear al usuario.\",\n  \"components.UserList.passwordinfodescription\": \"Configura una URL de aplicación y habilita las notificaciones por email para poder utilizar las contraseñas generadas automáticamente.\",\n  \"components.UserList.password\": \"Contraseña\",\n  \"components.UserList.localuser\": \"Usuario local\",\n  \"components.UserList.email\": \"Dirección de correo electrónico\",\n  \"components.UserList.creating\": \"Creando…\",\n  \"components.UserList.createlocaluser\": \"Crear usuario local\",\n  \"components.UserList.create\": \"Crear\",\n  \"components.UserList.autogeneratepassword\": \"Generar Contraseña Automáticamente\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"¡Configuración de notificación de webhook guardada con éxito!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"No se pudo guardar la configuración de notificación de webhook.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Debes proporcionar un payload de JSON válido\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Ayuda de variable de plantilla\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"¡Payload de JSON restablecido con éxito!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Restablecer predeterminado\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Payload de JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Encabezado de autorización\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Habilitar Agente\",\n  \"components.RequestModal.requestedited\": \"¡Solicitud para <strong>{title}</strong> modificada con éxito!\",\n  \"components.RequestModal.requestcancelled\": \"Solicitud para <strong>{title}</strong> cancelada.\",\n  \"components.RequestModal.pending4krequest\": \"Solicitud 4K Pendiente\",\n  \"components.RequestModal.errorediting\": \"Algo salió mal al editar la solicitud.\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Carpeta Raíz\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Perfil de calidad\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Servidor de destino\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Predeterminado)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Esta serie es un anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avanzadas\",\n  \"components.RequestButton.viewrequest4k\": \"Ver Solicitud 4K\",\n  \"components.RequestButton.viewrequest\": \"Ver Solicitud\",\n  \"components.RequestButton.requestmore4k\": \"Solicitar más en 4K\",\n  \"components.RequestButton.requestmore\": \"Solicitar más\",\n  \"components.RequestButton.declinerequests\": \"Rechazar {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.declinerequest4k\": \"Rechazar Solicitud 4K\",\n  \"components.RequestButton.declinerequest\": \"Rechazar Solicitud\",\n  \"components.RequestButton.decline4krequests\": \"Rechazar {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.approverequests\": \"Aprobar {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.approverequest4k\": \"Aprobar Solicitud 4K\",\n  \"components.RequestButton.approverequest\": \"Aprobar Solicitud\",\n  \"components.RequestButton.approve4krequests\": \"Aprobar {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestBlock.server\": \"Servidor de Destino\",\n  \"components.RequestBlock.rootfolder\": \"Carpeta Raíz\",\n  \"components.RequestBlock.profilechanged\": \"Perfil de Calidad\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Ver más\",\n  \"components.Login.validationpasswordrequired\": \"Se requiere contraseña\",\n  \"components.Login.validationemailrequired\": \"Debes indicar una dirección de email válida\",\n  \"components.Login.signinwithoverseerr\": \"Usa tu cuenta de {applicationTitle}\",\n  \"components.Login.password\": \"Contraseña\",\n  \"components.Login.loginerror\": \"Algo salió mal al intentar iniciar sesión.\",\n  \"components.Login.email\": \"Dirección de correo electrónico\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Petición Rechazada\",\n  \"components.RequestModal.autoapproval\": \"Aprobación Automática\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Envía notificaciones cuando las solicitudes sean rechazadas.\",\n  \"i18n.experimental\": \"Experimental\",\n  \"components.Login.signingin\": \"Iniciando sesión…\",\n  \"components.Login.signin\": \"Iniciar Sesión\",\n  \"components.Login.signinwithplex\": \"Usa tu cuenta de Plex\",\n  \"components.Login.signinheader\": \"Inicia sesión para continuar\",\n  \"components.PermissionEdit.request4k\": \"Solicitar 4K\",\n  \"components.PermissionEdit.request\": \"Solicitar\",\n  \"components.PermissionEdit.admin\": \"Administrador\",\n  \"components.Discover.discover\": \"Descubre\",\n  \"components.Layout.UserDropdown.settings\": \"Ajustes\",\n  \"components.Layout.UserDropdown.myprofile\": \"Perfil\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Series en {language}\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Series de {genre}\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Películas de {studio}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Series de {network}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Películas\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Películas de {genre}\",\n  \"i18n.loading\": \"Cargando…\",\n  \"components.ResetPassword.emailresetlink\": \"Enviar enlace de recuperación por email\",\n  \"components.ResetPassword.email\": \"Dirección de Email\",\n  \"components.ResetPassword.confirmpassword\": \"Confirmar Contraseña\",\n  \"components.RequestModal.requesterror\": \"Algo fue mal al realizar la solicitud.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"No se ha podido emparejar automáticamente tu solicitud. Por favor, seleccione el correcto de la lista.\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Pedir como\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Perfil de Idioma\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestList.RequestItem.requested\": \"Pedida\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} por {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Modificado\",\n  \"components.RegionSelector.regionServerDefault\": \"({Region}) por defecto\",\n  \"components.RegionSelector.regionDefault\": \"Todas las Regiones\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Conceder permiso para ver las solicitudes de otros usuarios.\",\n  \"components.PermissionEdit.viewrequests\": \"Ver Solicitudes\",\n  \"components.PermissionEdit.usersDescription\": \"Concede permisos para gestionar usuarios. Los usuarios con este permiso no pueden modificar usuarios o conceder privilegios de Administrador.\",\n  \"components.PermissionEdit.users\": \"Gestión de Usuarios\",\n  \"components.PermissionEdit.requestDescription\": \"Concede permisos para solicitar contenidos que no sean 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Concede permisos para solicitar series en 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"Pedir Series 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Concede permisos para solicitar películas en 4K.\",\n  \"components.PermissionEdit.request4kDescription\": \"Concede permisos para solicitar contenidos en 4K.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Concede permisos para gestionar las solicitudes de contenidos. Todas las solicitudes de un usuario con este permiso serán aprobadas automáticamente.\",\n  \"components.PermissionEdit.request4kMovies\": \"Solicita Películas 4K\",\n  \"components.PermissionEdit.managerequests\": \"Gestionar Solicitudes\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Concede aprobación automática para todas las solicitudes de series no 4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Auto-Aprueba Series\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Concede aprobación automática para todas las solicitudes de películas no 4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Auto-Aprueba Películas\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Concede aprobación automática para todas las solicitudes que no sean 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Concede aprobación automática para todas las solicitudes de series 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Auto-Aprueba Series 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Concede aprobación automática para todas las solicitudes de películas 4K.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Auto-Aprueba Películas 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Concede aprobación automática para todas las solicitudes de contenidos 4K.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Auto-Aprobación 4K\",\n  \"components.PermissionEdit.autoapprove\": \"Auto-Aprobación\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Concede permisos para configurar opciones avanzadas en las solicitudes.\",\n  \"components.PermissionEdit.advancedrequest\": \"Solicitudes Avanzadas\",\n  \"components.PermissionEdit.adminDescription\": \"Acceso completo de administrador. Ignora otras comprobaciones de permisos.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Envía notificaciones cuando los usuarios solicitan nuevos contenidos que se aprueban automáticamente.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Petición Aprobada Automáticamente\",\n  \"components.MovieDetails.markavailable\": \"Marcar como Disponible\",\n  \"components.MovieDetails.mark4kavailable\": \"Marcar como Disponible en 4K\",\n  \"components.Login.forgotpassword\": \"¿Contraseña olvidada?\",\n  \"components.Discover.upcomingtv\": \"Próximas Series\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Géneros de Series\",\n  \"components.Discover.StudioSlider.studios\": \"Estudios\",\n  \"components.Discover.NetworkSlider.networks\": \"Cadenas de TV\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Géneros de Películas\",\n  \"components.CollectionDetails.requestcollection4k\": \"Pedir Colección en 4K\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"El montaje del volumen <code>{appDataPath}</code> no se ha configurado correctamente. Todos los datos se eliminarán cuando el contenedor se pare o reinicie.\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Permisos por Defecto\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Tarea Desconocida\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Escaneo de Sonarr\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Ejecutar Ahora\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Escaneo de Radarr\",\n  \"components.Settings.SettingsJobsCache.process\": \"Procesamiento\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Escaneo de Recien Añadidos de Plex\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Escaneo Completo de la Biblioteca de Plex\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Próxima Ejecución\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tipo\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} comenzada.\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Overserr realiza ciertas tareas de mantenimiento como Tareas Programadas, pero también pueden lanzarse manualmente a continuación. Lanzar una tarea manual no altera su programación.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Tareas Programadas\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Nombre de Tarea Programada\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} cancelada.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Vaciar Caché\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Reiniciar Descarga Sincronizada\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Descarga Sincronizada\",\n  \"components.Settings.SettingsJobsCache.command\": \"Comando\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Cancelar Tarea Programada\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Valor del Tamaño\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Nombre de Caché\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Fallos\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Tamaño de Clave\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Claves Totales\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Consultas\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} caché limpiada.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Overseer cachea peticiones a APIs externas para optimizar el rendimiento y evitar llamadas innecesarias a esas APIs.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Caché\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"La base de la URL no debe terminar en una barra al final\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"La base de la URL debe tener una barra al principio\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"La URL no puede acabar con una barra\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Debes indicar una URL válida\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Habilitar Escaneo\",\n  \"components.Settings.RadarrModal.externalUrl\": \"URL externa\",\n  \"components.Settings.Notifications.validationUrl\": \"Debes indicar una URL válida\",\n  \"components.Settings.Notifications.validationEmail\": \"Debes indicar una dirección de email válida\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Enviar notificaciones sin sonido\",\n  \"components.Settings.Notifications.sendSilently\": \"Enviar silenciosamente\",\n  \"components.Settings.Notifications.botUsername\": \"Nombre de usuario del Bot\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL del Bot Avatar\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Debes indicar una URL válida\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Debes indicar una URL válida\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Debes indicar un token de acceso\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"¡Los ajustes de notificación Pushbullet se han guardado con éxito!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Fallo al guardar los ajustes de la notificación Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Habilitar Agente\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Token de Acceso\",\n  \"components.Search.search\": \"Buscar\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Debes indicar una contraseña\",\n  \"components.ResetPassword.validationpasswordminchars\": \"La contraseña es demasiado corta; debería tener al menos 8 caracteres\",\n  \"components.ResetPassword.validationpasswordmatch\": \"La contraseña debe coincidir\",\n  \"components.ResetPassword.validationemailrequired\": \"Debes indicar una dirección de email valida\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"¡Contraseña reiniciada con éxito!\",\n  \"components.ResetPassword.resetpassword\": \"Reiniciar contraseña\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Un enlace para reiniciar la contraseña se enviará a la dirección de email indicada si está asociada a un usuario valido.\",\n  \"components.ResetPassword.password\": \"Contraseña\",\n  \"components.ResetPassword.gobacklogin\": \"Volver a la Página de Login\",\n  \"components.RequestModal.alreadyrequested\": \"Ya Pedida\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Géneros de Series\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Géneros de Películas\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Ajustes de Notificaciones\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID de Usuario\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Usuario\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"¡Ajustes guardados con éxito!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Algo fue mal al guardar los ajustes.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rol\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Región en sección \\\"Descubre\\\"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Usuario en Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Propietario\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Idioma de la sección \\\"Descubre\\\"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Usuario Local\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Ajustes Generales\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Nombre a mostrar\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrador\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Tipo de Cuenta\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Id de Usuario: {userid}\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Editar Ajustes\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Ver Perfil\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Unido el {joindate}\",\n  \"components.UserList.validationEmail\": \"Debes indicar un dirección de email válida\",\n  \"components.UserList.userssaved\": \"¡Permisos de usuario guardados con éxito!\",\n  \"components.UserList.users\": \"Usuarios\",\n  \"components.UserList.userfail\": \"Algo fue mal al guardar los permisos del usuario.\",\n  \"components.UserList.sortRequests\": \"Número de Solicitudes\",\n  \"components.UserList.sortDisplayName\": \"Nombre a mostrar\",\n  \"components.UserList.sortCreated\": \"Fecha de Unión\",\n  \"components.UserList.owner\": \"Propietario\",\n  \"components.UserList.edituser\": \"Editar Permisos de Usuario\",\n  \"components.UserList.bulkedit\": \"Edición Masiva\",\n  \"components.UserList.accounttype\": \"Tipo\",\n  \"components.TvDetails.nextAirDate\": \"Próxima Emisión\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutos\",\n  \"components.TvDetails.episodeRuntime\": \"Duración del Episodio\",\n  \"components.Setup.setup\": \"Configuración\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"¡Recibida la lista de servidores de Plex con éxito!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Fallo al obtener la lista de servidores de Plex.\",\n  \"components.Settings.toastPlexRefresh\": \"Obteniendo la lista de servidores desde Plex…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"¡Conexión al servidor Plex establecida con éxito!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Fallo al conectar con Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"Intentando conectar con Plex…\",\n  \"components.Settings.settingUpPlexDescription\": \"Para configurar Plex, puedes introducir manualmente los detalles o seleccionar un servidor obtenido de <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Pulsa el botón de la derecha del desplegable para obtener los servidores disponibles.\",\n  \"components.Settings.serverpresetRefreshing\": \"Obteniendo servidores…\",\n  \"components.Settings.serverpresetManualMessage\": \"Configuración manual\",\n  \"components.Settings.serverpresetLoad\": \"Presiona el botón para obtener los servidores disponibles\",\n  \"components.Settings.serverpreset\": \"Servidor\",\n  \"components.Settings.serverRemote\": \"remoto\",\n  \"components.Settings.serverLocal\": \"local\",\n  \"components.Settings.scanning\": \"Sincronizando…\",\n  \"components.Settings.scan\": \"Sincronizar Bibliotecas\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Configura y habilita los agentes de notificaciones.\",\n  \"components.Settings.menuUsers\": \"Usuarios\",\n  \"components.Settings.email\": \"Email\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Debes seleccionar un perfil de idioma\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"La URL BASE no puede terminar con una barra\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"La URL Base debe comenzar con una barra\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"La URL no puede terminar con una barra\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Debe indicar una URL válida\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"¡Conexión establecida con Sonarr con éxito!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Fallo al conectar con Sonarr.\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Probar conexión para obtener los perfiles de idioma\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Habilitar Escaneo\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Seleccionar Perfil de Idioma\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Cargando perfiles de idioma…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Perfil de Idioma\",\n  \"components.Settings.SonarrModal.externalUrl\": \"URL Externa\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Perfil de Idioma para Anime\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Configura los ajustes de usuarios globales y por defecto.\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Ajustes de Usuario\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"¡Ajustes de usuario guardados con éxito!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Algo fue mal mientras se guardaban los cambios.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Habilitar Autenticación Local\",\n  \"components.Settings.SettingsLogs.time\": \"Marca de tiempo (timestamp)\",\n  \"components.Settings.SettingsLogs.showall\": \"Mostrar todos los logs\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pausar\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Reanudar\",\n  \"components.Settings.SettingsLogs.message\": \"Mensaje\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Puede ver estos logs directamente via <code>stdout</code> o en <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.logs\": \"Registros\",\n  \"components.Settings.SettingsLogs.level\": \"Severidad\",\n  \"components.Settings.SettingsLogs.label\": \"Etiqueta\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Advertencia\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.SettingsLogs.filterError\": \"Error\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Depuración\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Firmar mensajes de email encriptados usando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Clave Privada PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Firmar mensajes de email usando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPassword\": \"Contraseña de PGP\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nueva Contraseña\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Contraseña Actual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Confirmar Contraseña\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Debes indicar un Id de chat válido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Debes indicar un Id de usuario válido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Comienza un chat</TelegramBotLink>, añade el <GetIdBotLink>@get_id_bot</GetIdBotLink>, y envía el comando <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID del Chat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Enviar notificaciones sin sonido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Enviar de forma silenciosa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notificaciones\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"El <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> asociado a su cuenta de usuario\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtrar contenido por disponibilidad regional\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtrar contenido por idioma original\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"General\",\n  \"components.Settings.services\": \"Servicios\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Notificaciones\",\n  \"components.Settings.SettingsUsers.users\": \"Usuarios\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Tareas y Caché\",\n  \"components.Settings.SettingsAbout.about\": \"Acerca de\",\n  \"components.ResetPassword.passwordreset\": \"Reinicio de Contraseña\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"No tienes permiso para modificar estos ajustes de usuario.\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Temporada} other {# Temporadas}}\",\n  \"pages.somethingwentwrong\": \"Algo fue mal\",\n  \"pages.serviceunavailable\": \"Servicio No Disponible\",\n  \"pages.pagenotfound\": \"Página No Encontrada\",\n  \"pages.internalservererror\": \"Error Interno del Servidor\",\n  \"i18n.usersettings\": \"Ajustes de Usuario\",\n  \"i18n.settings\": \"Ajustes\",\n  \"i18n.advanced\": \"Avanzado\",\n  \"components.UserProfile.recentrequests\": \"Solicitudes Recientes\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Permisos\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notificaciones\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"General\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Contraseña\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"No puedes modificar tus propios permisos.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"¡Permisos guardados con éxito!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Algo fue mal al guardar los ajustes.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Permisos\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"La contraseña es muy corta; debería tener, al menos, 8 caracteres\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Debes proporcionar una nueva contraseña\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Debes indicar tu contraseña actual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Las contraseñas deben coincidir\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Debes confirmar la nueva contraseña\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"¡Contraseña guardada correctamente!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Algo fue mal al guardar la contraseña. ¿Has introducido correctamente tu contraseña actual?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Algo fue mal al guardar la contraseña.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Contraseña\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"No tienes permiso para modificar la contraseña del usuario.\",\n  \"components.Settings.enablessl\": \"Usar SSL\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Detalles del Log\",\n  \"components.Settings.SettingsLogs.extraData\": \"Datos Adicionales\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Copiar al Portapapeles\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Copiar log al portapapeles.\",\n  \"components.UserList.nouserstoimport\": \"No hay usuarios de Plex para importar.\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Nacido el {birthdate}\",\n  \"components.PersonDetails.alsoknownas\": \"También Conocido como: {names}\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.view\": \"Ver\",\n  \"i18n.tvshow\": \"Series\",\n  \"i18n.testing\": \"Probando…\",\n  \"i18n.test\": \"Probar\",\n  \"i18n.status\": \"Estado\",\n  \"i18n.showingresults\": \"Mostrando <strong>{from}</strong> a <strong>{to}</strong> de <strong>{total}</strong> resultados\",\n  \"i18n.saving\": \"Guardando…\",\n  \"i18n.save\": \"Guardar Cambios\",\n  \"i18n.resultsperpage\": \"Mostrar {pageSize} resultados por página\",\n  \"i18n.requesting\": \"Pidiendo…\",\n  \"i18n.request4k\": \"Pedir en 4K\",\n  \"i18n.previous\": \"Anterior\",\n  \"i18n.notrequested\": \"No Solicitado\",\n  \"i18n.noresults\": \"Sin resultados.\",\n  \"i18n.next\": \"Adelante\",\n  \"i18n.movie\": \"Película\",\n  \"i18n.canceling\": \"Cancelando…\",\n  \"i18n.back\": \"Atrás\",\n  \"i18n.areyousure\": \"¿Estás Seguro?\",\n  \"i18n.all\": \"Todas\",\n  \"components.UserProfile.unlimited\": \"Ilimitadas\",\n  \"components.UserProfile.totalrequests\": \"Solicitudes Totales\",\n  \"components.UserProfile.seriesrequest\": \"Solicitudes de Series\",\n  \"components.UserProfile.requestsperdays\": \"{limit} restantes\",\n  \"components.UserProfile.pastdays\": \"{type} (últimos {days} días)\",\n  \"components.UserProfile.movierequests\": \"Solicitudes de Películas\",\n  \"components.UserProfile.limit\": \"{remaining} de {limit}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Límite de Solicitudes de Series\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Límite de Solicitudes de Películas\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Límite global de Sobreescritura\",\n  \"components.TvDetails.originaltitle\": \"Título Original\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Límite Global de Solicitudes de Series\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Límite Global de Solicitudes de Películas\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {temporada} other {temporadas}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"temporada\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Este usuario necesita tener al menos <strong>{seasons}</strong> {seasons, plural, one {solicitud de temporada} other {solicitudes de temporadas}} restante(s) para poder enviar una solicitud para esta serie.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Necesitas tener al menos <strong>{seasons}</strong> {seasons, plural, one {solicitud de temporada} other {solicitudes de temporadas}} restante(s) para poder enviar una solicitud para esta serie.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {solicitud} other {solicitudes}} restante(s)\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Puedes ver un resumen de los límites de solicitudes de estos usuarios en sus <ProfileLink>páginas de perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Puedes ver un resumen de tus límites de peticiones en tu <ProfileLink>página de perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"No te quedan suficientes solicitudes de temporadas restantes\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {película} other {películas}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"película\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Este usuario tiene permitido <strong>{limit}</strong> {type} cada <strong>{days}</strong> días.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Se te permite pedir <strong>{limit}</strong> {type} cada <strong>{days}</strong> días.\",\n  \"components.QuotaSelector.unlimited\": \"Ilimitadas\",\n  \"components.MovieDetails.originaltitle\": \"Título Original\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Todos los Idiomas\",\n  \"components.LanguageSelector.languageServerDefault\": \"({language}) por defecto\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {cambio} other {cambios}} por detrás\",\n  \"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.\",\n  \"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\\\"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Debes introducir una clave pública PGP valida\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"¡Ajustes de notificaciones de Telegram guardados correctamente!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Error al guardar los ajustes de notificaciones de Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Encriptar mensajes por email usando <OpenPgpLink>OpenPGP2</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Clave Pública PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"¡Ajustes de notificación por email guardados correctamente!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Error al guardar los ajustes de notificaciones por email.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"¡Los ajustes de notificaciones de Discord se han guardado correctamente!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"No se han podido guardar los ajustes de notificaciones de Discord.\",\n  \"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 administradores podrán modificar el servidor usado al procesar nuevas solicitudes antes de su aprobación.\",\n  \"components.Settings.mediaTypeMovie\": \"película\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Probar conexión para cargar etiquetas\",\n  \"components.Settings.SonarrModal.tags\": \"Etiquetas\",\n  \"components.Settings.SonarrModal.selecttags\": \"Seleccionar etiquetas\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Sin etiquetas.\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Cargando etiquetas…\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Modificar servidor 4K Sonarr\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Servidor 4K por defecto\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Añadir nuevo servidor Sonarr 4K\",\n  \"components.Settings.SonarrModal.animeTags\": \"Etiquetas Anime\",\n  \"components.Settings.noDefaultServer\": \"Al menos un servidor {serverType} debe marcarse como por defecto para que las solicitudes de {mediaType} sean procesadas.\",\n  \"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} <strong>NO</strong> debería marcarse como un servidor 4k.\",\n  \"components.Settings.mediaTypeSeries\": \"serie\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Actualizado\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Desactualizado\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Probar conexión para cargar etiquetas\",\n  \"components.Settings.RadarrModal.tags\": \"Etiquetas\",\n  \"components.Settings.RadarrModal.selecttags\": \"Seleccionar etiquetas\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Sin etiquetas.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Cargando etiquetas…\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Modificar servidor Radarr 4K\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Servidor 4K por defecto\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Añadir un nuevo servidor Radarr 4K\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Debes indicar una clave privada PGP\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Debes indicar una contraseña PGP\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Permite a los usuarios iniciar también un chat con tu bot y configurar sus propias notificaciones\",\n  \"components.RequestModal.pendingapproval\": \"Tu solicitud está pendiente de aprobación.\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Etiquetas\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Seleccionar etiquetas\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Sin etiquetas.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} No Encontrado\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Borrar Solicitud\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Cancelar Solicitud\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} No Encontrado\",\n  \"components.RequestCard.deleterequest\": \"Borrar Solicitud\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Tipos de Notificación\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr (Estable)\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Jellyseer (Desarrollo)\",\n  \"components.Layout.VersionStatus.outofdate\": \"Desactualizado\",\n  \"components.UserList.autogeneratepasswordTip\": \"Envía por email una contraseña al usuario generada por el servidor\",\n  \"i18n.retrying\": \"Reintentando…\",\n  \"components.Settings.serverSecure\": \"seguro\",\n  \"components.UserList.usercreatedfailedexisting\": \"La dirección de email proporcionada ya está en uso por otro usuario.\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Habilitar Búsqueda Automática\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Habilitar Búsqueda Automática\",\n  \"components.RequestModal.edit\": \"Editar Solicitud\",\n  \"components.RequestList.RequestItem.editrequest\": \"Editar Solicitud\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Mostrar Idioma\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Settings.noDefault4kServer\": \"Un servidor 4K de {serverType} debe ser marcado por defecto para poder habilitar las solicitudes 4K de {mediaType} de los usuarios.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Habilitar inicio de sesión de usuarios de Plex sin importarse previamente\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Habilitar nuevo inicio de sesión de Plex\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"¡Notificación de Telegram enviada con éxito!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Enviando notificación de prueba de Telegram…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Fallo al enviar notificación de prueba de Telegram.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"¡Notificación por Email de prueba enviada!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Enviando notificación de prueba por Email…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Fallo al enviar la notificación de prueba por Email.\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"¡Notificación de prueba enviada de Discord!\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Enviando notificación de prueba de Discord…\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Fallo al enviar notificación de prueba de Discord.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"¡Notificación de prueba de Webhook enviada!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Enviando notificación de prueba de Webhook…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Fallo al enviar la notificación de prueba de Webhook.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"¡Ajustes de notificación de Web Push guardados con éxito!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Fallo al guardar los ajustes de notificación de Web Push.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"¡Notificación de prueba de Web Push enviada!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Enviando notificación de prueba de Web Push…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Fallo al enviar la notificación de prueba de Web Push.\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Habilitar Agente\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"¡Notificación de prueba de Slack enviada!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Enviando notificación de prueba de Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Fallo al enviar la notificación de prueba de Slack.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"¡Notificación de prueba de Pushover enviada!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Enviando notificación de prueba de Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Fallo al enviar la notificación de prueba de Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"¡Notificación de prueba de Pushbullet enviada!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Enviando notificación de prueba de Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Fallo al enviar notificación de prueba de Pushbullet.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Conceder permisos para solicitar series que no sean 4k.\",\n  \"components.PermissionEdit.requestTv\": \"Solicitar Series\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Conceder permisos para solicitar películas que no sean 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Solicitar películas\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Solicitado\",\n  \"components.RequestCard.failedretry\": \"Algo fue mal al reintentar la solicitud.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Notificar cuando otros usuarios envíen nuevas solicitudes que requieran aprobación.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Notificar cuando las solicitudes de contenido fallen al añadirse a Radarr o Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Notificar cuando tus contenidos solicitados sean rechazados.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Notificar cuando tus contenidos solicitados estén disponibles.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Notificar cuando las solicitudes sean aprobadas.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Notificar cuando otros usuarios envíen nuevas solicitudes que se aprueben automáticamente.\",\n  \"components.MovieDetails.showmore\": \"Mostrar más\",\n  \"components.MovieDetails.showless\": \"Mostrar menos\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Mostrar idioma\",\n  \"components.DownloadBlock.estimatedtime\": \"Estimación de {time}\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Usa siempre STARTTLS\",\n  \"components.TvDetails.streamingproviders\": \"Emisión Actual en\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"({language}) por defecto\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Para recibir notificaciones web push, Seerr debe servirse mediante HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.Settings.Notifications.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Permite a los usuarios registrarse consumo email y password, en lugar de la OAuth de Plex\",\n  \"components.Settings.webAppUrl\": \"Url de la <WebAppLink>Web App</WebAppLink>\",\n  \"components.Settings.Notifications.encryption\": \"Método de Encriptación\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Usa STARTTLS si está disponible\",\n  \"components.Settings.Notifications.encryptionNone\": \"Ninguna\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Crea un token desde tu <PushbulletSettingsLink>Opciones de Cuenta</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registrar una aplicación</ApplicationRegistrationLink> para su uso con Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Tu <UsersGroupsLink>identificador de usuario o grupo</UsersGroupsLink> de 30 caracteres\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {temporada} other {temporadas}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {película} other {películas}}\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.Settings.Notifications.chatIdTip\": \"Empieza un chat con tu bot, añade el <GetIdBotLink>@get_id_bot</GetIdBotLink> e indica el comando <code>/my_id</code>\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Usa TLS Implícito\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Crea una <DiscordWebhookLink>integración webhook</DiscordWebhookLink> en tu servidor\",\n  \"components.MovieDetails.streamingproviders\": \"Emisión Actual en\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{películas} per {quotaDays} {días}</quotaUnits>\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Crea una integración con un <WebhookLink>Webhook de Entrada</WebhookLink>\",\n  \"components.Settings.webAppUrlTip\": \"Dirige a los usuarios, opcionalmente, a la web app en tu servidor, en lugar de la app alojada en Plex\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {día} other {días}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{temporadas} per {quotaDays} {días}</quotaUnits>\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Crea un bot</CreateBotLink> para usar con Seerr\",\n  \"components.Settings.Notifications.encryptionTip\": \"Normalmente, TLS Implícito usa el puerto 465 y STARTTLS usa el puerto 587\",\n  \"components.UserList.localLoginDisabled\": \"El ajuste para <strong>Habilitar el Inicio de Sesión Local</strong> está actualmente deshabilitado.\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Permisos iniciales asignados a nuevos usuarios\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Estás utilizando la rama de <code>desarrollo</code> de Seerr, la cual solo se recomienda para aquellos que contribuyen al desarrollo o al soporte de las pruebas de nuevos desarrollos.\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Cada {jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Cada {jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Algo fue mal al guardar la tarea programada.\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modificar tarea programada\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Nueva frecuencia\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"¡Tarea programada modificada con éxito!\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"¿Estás seguro de querer borrar este comentario?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Borrar Comentario\",\n  \"components.IssueDetails.IssueComment.edit\": \"Modificar Comentario\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Escrito por {username} el {relativeTime}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Escrito por {username} el {relativeTime} (Modificado)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Debes introducir un mensaje\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Borrar Incidencia\",\n  \"components.IssueDetails.IssueDescription.description\": \"Descripción\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Modificar Descripción\",\n  \"components.IssueDetails.allepisodes\": \"Todos los Episodios\",\n  \"components.IssueDetails.allseasons\": \"Todas las Temporadas\",\n  \"components.IssueDetails.closeissue\": \"Cerrar Incidencia\",\n  \"components.IssueDetails.closeissueandcomment\": \"Cerrar con Comentarios\",\n  \"components.IssueDetails.comments\": \"Comentarios\",\n  \"components.IssueDetails.deleteissue\": \"Borrar Incidencia\",\n  \"components.IssueDetails.deleteissueconfirm\": \"¿Estás seguro de querer borrar esta incidencia?\",\n  \"components.IssueDetails.episode\": \"Episodio {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Incidencia\",\n  \"components.IssueDetails.issuetype\": \"Tipo\",\n  \"components.IssueDetails.lastupdated\": \"Última Actualización\",\n  \"components.IssueDetails.leavecomment\": \"Commentario\",\n  \"components.IssueDetails.nocomments\": \"Sin comentarios.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} abierta {relativeTime} por {username}\",\n  \"components.IssueDetails.openin4karr\": \"Abrir en {arr} 4K\",\n  \"components.IssueDetails.openinarr\": \"Abrir en {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Ver en 4K en {mediaServerName}\",\n  \"components.IssueDetails.playonplex\": \"Ver en {mediaServerName}\",\n  \"components.IssueDetails.problemepisode\": \"Episodio Afectado\",\n  \"components.IssueDetails.problemseason\": \"Temporada Afectada\",\n  \"components.IssueDetails.reopenissue\": \"Reabrir Incidencia\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Reabrir con Comentarios\",\n  \"components.IssueDetails.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Algo fue mal mientras se modificaba la descripción de la incidencia.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"¡La descripción de la incidencia se ha modificado correctamente!\",\n  \"components.IssueDetails.toastissuedeleted\": \"¡Incidencia eliminada correctamente!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Algo fue mal mientras se eliminaba la incidencia.\",\n  \"components.IssueDetails.toaststatusupdated\": \"¡Estado de la incidencia actualizado con éxito!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Algo fue mal mientras se actualizaba el estado de la incidencia.\",\n  \"components.IssueDetails.unknownissuetype\": \"Desconocido\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Episodio} other {Episodios}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Estado\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tipo\",\n  \"components.IssueList.IssueItem.opened\": \"Abierta\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} por {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Episodio Afectado\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Desconocida\",\n  \"components.IssueList.IssueItem.viewissue\": \"Ver Incidencia\",\n  \"components.IssueList.issues\": \"Incidencias\",\n  \"components.IssueList.showallissues\": \"Mostrar Todas las Incidencias\",\n  \"components.IssueList.sortAdded\": \"Más Reciente\",\n  \"components.IssueList.sortModified\": \"Última Modificación\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Todos los Episodios\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Todas las Temporadas\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episodio {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extras\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Episodio Afectado\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Temporada Afectada\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Por favor envíe una explicación detallada de la incidencia encontrada.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Reportar Incidencia\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Enviar Incidencia\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Algo fue mal mientras se enviaba la incidencia.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"¡Incidencia reportada por <strong>{title}</strong> enviada con éxito!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Ver Incidencia\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Debes escribir una descripción\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"¿Qué sucede?\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueModal.issueOther\": \"Otro\",\n  \"components.IssueModal.issueSubtitles\": \"Subtítulo\",\n  \"components.IssueModal.issueVideo\": \"Vídeo\",\n  \"components.Layout.Sidebar.issues\": \"Incidencias\",\n  \"components.ManageSlideOver.downloadstatus\": \"Estado de la Descarga\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Limpiar Datos de los Contenidos\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Esto eliminará irreversiblemente todos los datos de {mediaType}, incluyendo todas las solicitudes. Si este elemento existe en la biblioteca de {mediaServerName}, la información de los contenidos se recreará en el siguiente escaneado.\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Incidencias Abiertas\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Sin solicitudes.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Solicitudes\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Gestionar {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Marcar como Disponible en 4K\",\n  \"components.ManageSlideOver.markavailable\": \"Marcar como Disponible\",\n  \"components.ManageSlideOver.movie\": \"película\",\n  \"components.ManageSlideOver.openarr\": \"Abrir en {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Abrir en 4K {arr}\",\n  \"components.ManageSlideOver.tvshow\": \"series\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Notificar cuando otros usuarios comenten incidencias.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Notificar cuando se reabran incidencias por otros usuarios.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Notificar cuando otros usuarios resuelvan incidencias.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Comentario de Incidencia\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Envía notificaciones cuando las incidencias reciben nuevos comentarios.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Incidencia Reportada\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Enviar notificaciones cuando las incidencias sean reportadas.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Incidencia Reabierta\",\n  \"i18n.import\": \"Importar\",\n  \"i18n.importing\": \"Importando…\",\n  \"components.MovieDetails.digitalrelease\": \"Lanzamiento Digital\",\n  \"components.MovieDetails.physicalrelease\": \"Lanzamiento Físico\",\n  \"components.MovieDetails.theatricalrelease\": \"Lanzamiento en cines\",\n  \"components.IssueDetails.commentplaceholder\": \"Añadir un comentario…\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Marcar Todas las Temporadas como Disponible en 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Marcar Todas las Temporadas como Disponible\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatometer de Rotten Tomatoes\",\n  \"components.MovieDetails.rtaudiencescore\": \"Puntuación audiencia de Rotten Tomatoes\",\n  \"components.Discover.plexwatchlist\": \"Tu Lista de Visualización de Plex\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Tu lista de seguimiento de Plex\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Contenido\",\n  \"components.MovieDetails.managemovie\": \"Administrar Película\",\n  \"components.MovieDetails.reportissue\": \"Reportar una Incidencia\",\n  \"components.AirDateBadge.airedrelative\": \"Emitido {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Emitiendo {relativeTime}\",\n  \"components.ManageSlideOver.pastdays\": \"Últimos {days, number} Días\",\n  \"components.Discover.CreateSlider.addSlider\": \"Crear deslizador\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Crear deslizador personalizado\",\n  \"components.Discover.CreateSlider.addfail\": \"Error al crear deslizador nuevo.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Nuevo deslizador creado y guardado de los ajustes personalizados.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Modificar deslizador\",\n  \"components.Discover.CreateSlider.editfail\": \"Fallo al editar deslizador.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Sin resultados.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Proporcione un ID de categoría de TMDB\",\n  \"components.Discover.CreateSlider.needresults\": \"Necesita tener al menos un resultado en la búsqueda.\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Proporcione una ID de TMDB de la palabra clave\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Deslizador editado y ajustes personalizados guardados.\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Proporcione una consulta a buscar\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Buscar categorías…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Buscar palabras clave…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Buscar estudios…\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Proporcione la ID de TMDB del estudio\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Proporcione la ID de TMDB de la cadena\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Nombre del deslizador\",\n  \"components.Discover.CreateSlider.starttyping\": \"Escriba para buscar.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Debe proporcionar un valor.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Películas\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Debe proporcionar un título.\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Error al borrar deslizador.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Deslizador eliminado con éxito.\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Borrar\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Alternar Visibilidad\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Contenido añadido a tu <PlexWatchlistSupportLink> lista de visualización de Plex </PlexWatchlistSupportLink> aparecerá aquí.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Vista de Visualización de Plex\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Series\",\n  \"components.Discover.createnewslider\": \"Crear Nuevo Deslizador\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Añadido Recientemente\",\n  \"components.Discover.moviegenres\": \"Géneros de Películas\",\n  \"components.Discover.networks\": \"Cadenas\",\n  \"components.Discover.emptywatchlist\": \"Contenido añadido a tu <PlexWatchlistSupportLink> lista de visualización de Plex </PlexWatchlistSupportLink> aparecerá aquí.\",\n  \"components.Discover.resettodefault\": \"Restablecer valores Predeterminados\",\n  \"components.Discover.resetwarning\": \"Restablecer todos los deslizadores por defecto. ¡Esto también borrará los deslizadores personalizados!\",\n  \"components.Discover.resetfailed\": \"Algo falló restableciendo los ajustes personalizados de recomendaciones.\",\n  \"components.Discover.resetsuccess\": \"Se ha restablecido correctamente la configuración de personalización de Descubrir.\",\n  \"components.Discover.stopediting\": \"Dejar de Editar\",\n  \"components.Discover.tmdbmoviegenre\": \"Género de películas TMDB\",\n  \"components.Discover.tmdbmoviekeyword\": \"Palabras clave de la película de TMDB\",\n  \"components.Discover.tmdbnetwork\": \"Cadena TMDB\",\n  \"components.Discover.studios\": \"Estudios\",\n  \"components.Discover.tvgenres\": \"Géneros de Series\",\n  \"components.Discover.tmdbsearch\": \"Búsqueda TMDB\",\n  \"components.Discover.tmdbstudio\": \"Estudio TMDB\",\n  \"components.Discover.tmdbtvgenre\": \"Género de Series TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Palabra clave de Series TMDB\",\n  \"components.Discover.updatefailed\": \"Algo falló al actualizar las opciones personalizadas de recomendaciones.\",\n  \"components.Discover.updatesuccess\": \"Opciones personalizadas de recomendaciones actualizadas.\",\n  \"components.ManageSlideOver.opentautulli\": \"Abrir en Tautulli\",\n  \"components.ManageSlideOver.playedby\": \"Reproducido Por\",\n  \"components.MovieDetails.tmdbuserscore\": \"Puntuación de usuario de TMDB\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Películas\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularidad Ascendente\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularidad descendente\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Fecha de salida Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Título (A-Z) Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Título (Z-A) Descendente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Ratio TMDB Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Ratio TMDB Descendente\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Fecha de salida Descendente\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularidad Ascendente\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularidad Descendente\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Título (A-Z) Ascendente\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Título (Z-A) Descendente\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Series\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Puntuación TMDB Ascendente\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Fecha de Primera Emisión Ascendente\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Fecha de Primera Emisión Descendente\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Puntuación TMDB Descendente\",\n  \"components.Discover.FilterSlideover.keywords\": \"Palabras claves\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtros\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Limpiar Filtros Activos\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Primera Fecha de Emisión\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Idioma Original\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Fecha de Publicación\",\n  \"components.Discover.FilterSlideover.studio\": \"Estudio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Puntuación de Usuarios de TMDB\",\n  \"components.Discover.FilterSlideover.to\": \"A\",\n  \"components.Discover.FilterSlideover.from\": \"Desde\",\n  \"components.Discover.FilterSlideover.genres\": \"Géneros\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Puntuaciones entre {minValue} y {maxValue}\",\n  \"components.Discover.customizediscover\": \"Personalizar Descubre\",\n  \"components.Layout.Sidebar.browsetv\": \"Series\",\n  \"components.Layout.Sidebar.browsemovies\": \"Películas\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Peticiones de Películas\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avanzado\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Contenido 4K\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Temporada {seasonNumber} Episodio {episodeNumber}\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Peticiones de Series\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Petición Enviada Automáticamente\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Lista de seguimiento Plex\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Servicios de Streaming\",\n  \"components.Layout.UserDropdown.requests\": \"Peticiones\",\n  \"components.TvDetails.reportissue\": \"Informar de un problema\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomatómetro de Rotten Tomatoes\",\n  \"components.TvDetails.seasonstitle\": \"Temporadas\",\n  \"components.TvDetails.tmdbuserscore\": \"Puntuación de Usuarios de TMDB\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Debe seleccionar al menos un tipo de notificación\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Reciba notificaciones cuando se envíen nuevas solicitudes de contenido para elementos de su lista de seguimiento de Plex.\",\n  \"components.PermissionEdit.autorequestDescription\": \"Conceder permiso para enviar solicitudes de medios que no sean 4K a través de Plex Watchlist.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Solicitar Películas automáticamente\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} Duración en minutos\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Conceder permiso para ver las listas de seguimiento de Plex de otros usuarios.\",\n  \"components.RequestBlock.decline\": \"Rechazar solicitud\",\n  \"components.RequestBlock.lastmodifiedby\": \"Última Modificación Por\",\n  \"components.RequestBlock.requestdate\": \"Fecha de Solicitud\",\n  \"components.RequestCard.declinerequest\": \"Rechazar Solicitud\",\n  \"components.RequestCard.tvdbid\": \"Identificador de TheTVDB\",\n  \"components.RequestModal.requestseries4ktitle\": \"Solicitar Serie en 4K\",\n  \"components.RequestModal.requestseasons4k\": \"Solicitar {seasonCount} {seasonCount, plural, one {Season} other {Seasons}} en 4K\",\n  \"components.RequestModal.selectmovies\": \"Seleccionar Película(s)\",\n  \"components.Selector.showmore\": \"Mostrar más\",\n  \"components.Selector.searchStudios\": \"Buscar estudios…\",\n  \"components.Selector.nooptions\": \"Sin resultados.\",\n  \"components.Selector.searchKeywords\": \"Buscar palabras clave…\",\n  \"components.Selector.showless\": \"Ver menos\",\n  \"components.Selector.searchGenres\": \"Seleccionar géneros…\",\n  \"components.Selector.starttyping\": \"Escriba para buscar.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"La URL no debe terminar con una barra al final\",\n  \"components.Settings.Notifications.enableMentions\": \"Activar menciones\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Frecuencia actual\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Tamaño total de la caché\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Imágenes en caché\",\n  \"components.Settings.SettingsMain.general\": \"General\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Configuración general\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Ocultar Contenido disponible\",\n  \"components.StatusBadge.managemedia\": \"Gestionar {mediaType}\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Configure los ajustes globales y por defecto de Seerr.\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Algo ha ido mal al guardar los ajustes.\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Debe proporcionar una URL válida\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Debe proporcionar un título de solicitud\",\n  \"components.Settings.tautulliApiKey\": \"Clave API\",\n  \"components.StatusBadge.openinarr\": \"Abrir en {arr}\",\n  \"components.StatusBadge.playonplex\": \"Ver en Plex\",\n  \"components.StatusChecker.reloadApp\": \"Recargar {applicationTitle}\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} No Encontrado\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Algo ha ido mal al obtener los datos de la temporada.\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Episodio} other {# Episodios}}\",\n  \"components.TvDetails.rtaudiencescore\": \"Puntuación audiencia de Rotten Tomatoes\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"El <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> asociado a su cuenta de usuario de Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Solicitar Películas automáticamente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Solicite películas automáticamente en su <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Solicite series automáticamente series en su <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.emptywatchlist\": \"Los medios añadidos a su <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> aparecerán aquí.\",\n  \"components.UserProfile.plexwatchlist\": \"Lista de seguimiento Plex\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Filtro Activo} other {# Filtros Activos}}\",\n  \"components.MovieDetails.productioncountries\": \"Producción {countryCount, plural, one {País} other {Países}}\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Cuando está habilitado en la configuración, Seerr obtendrá y almacenará en caché imágenes de fuentes externas preconfiguradas. Las imágenes almacenadas en caché se guardan en la carpeta de configuración. Puede encontrar los archivos en <code>{appDataPath}/cache/images</code>.\",\n  \"components.PermissionEdit.autorequest\": \"Auto solicitar\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Conceder permiso para enviar solicitudes de películas que no sean 4K a través de Plex Watchlist.\",\n  \"components.RequestBlock.approve\": \"Aprobar solicitud\",\n  \"components.RequestCard.approverequest\": \"Aprobar Solicitud\",\n  \"components.RequestCard.cancelrequest\": \"Cancelar Solicitud\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Conceder permiso para enviar solicitudes de series que no sean 4K a través de Plex Watchlist.\",\n  \"components.RequestCard.editrequest\": \"Editar Solicitud\",\n  \"components.RequestBlock.delete\": \"Eliminar solicitud\",\n  \"components.RequestBlock.edit\": \"Editar solicitud\",\n  \"components.RequestBlock.requestedby\": \"Solicitado Por\",\n  \"components.RequestCard.unknowntitle\": \"Título Desconocido\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Título Desconocido\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"No se ha podido encontrar ninguna coincidencia para esta serie.\",\n  \"components.RequestModal.requestseriestitle\": \"Solicitar Serie\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Solicitar Película en 4K\",\n  \"components.RequestModal.approve\": \"Aprobar Solicitud\",\n  \"components.RequestModal.requestApproved\": \"¡Solicitud de <strong>{title}</strong> aprobada!\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Solicitar Colección en 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Solicitar Colección\",\n  \"components.RequestModal.requestmovietitle\": \"Solicitar Película\",\n  \"components.Settings.urlBase\": \"Base URL\",\n  \"components.Settings.validationUrl\": \"Debe proporcionar una URL válida\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Haga clic en el botón de abajo para recargar la aplicación.\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Reinicie el servidor para aplicar la configuración actualizada.\",\n  \"components.TitleCard.cleardata\": \"Limpiar Datos\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID de usuario de Discord\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"No se ha podido enviar la notificación de prueba de Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Enviando notificación de prueba de Gotify…\",\n  \"components.StatusChecker.restartRequired\": \"Es necesario reiniciar el servidor\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"¡La configuración de notificaciones de Gotify se ha guardado correctamente!\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL del servidor\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Debe proporcionar un token de aplicación\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Debe proporcionar una URL válida\",\n  \"components.Settings.RadarrModal.released\": \"Publicado\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Concede permiso para ver la lista de contenidos añadidos recientemente.\",\n  \"components.PermissionEdit.viewrecent\": \"Ver recientemente añadido\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Algo salió mal al guardar la configuración de Tautulli.\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"La base de la URL debe tener una barra al principio\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Actualizado\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Ver detalles\",\n  \"components.Settings.SettingsMain.apikey\": \"Clave API\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL de la aplicación\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Activar el caché de imágenes\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Idioma en Descubre\",\n  \"components.Settings.SettingsMain.locale\": \"Idioma de visualización\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrar contenidos por idioma original\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Permitir Solicitudes Parciales de Series\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Algo ha ido mal al generar una nueva clave API.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"¡Nueva clave API generada con éxito!\",\n  \"components.Settings.advancedTooltip\": \"Una configuración incorrecta de este parámetro puede afectar a la funcionalidad\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr debe reiniciarse para que los cambios en esta configuración surtan efecto\",\n  \"components.TvDetails.seasonnumber\": \"Temporada {seasonNumber}\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.UserList.newplexsigninenabled\": \"El ajuste <strong>Enable New Plex Sign-In</strong> está actualmente activado. Los usuarios de Plex con acceso a la biblioteca no necesitan ser importados para abrir sesión.\",\n  \"components.ManageSlideOver.alltime\": \"Tiempo total\",\n  \"components.RequestModal.requestmovies\": \"Solicitar {count} {count, plugarl, one {Película} other {Películas}}\",\n  \"components.Settings.tautulliSettings\": \"Configuración de Tautulli\",\n  \"components.Settings.validationUrlTrailingSlash\": \"La URL no debe terminar con una barra al final\",\n  \"components.PermissionEdit.autorequestSeries\": \"Solicitar series automáticamente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Solicitar series automáticamente\",\n  \"components.PermissionEdit.viewwatchlists\": \"Ver listas de seguimiento de Plex\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Etiqueta de canal\",\n  \"components.RequestBlock.languageprofile\": \"Perfil lingüístico\",\n  \"components.RequestModal.requestmovies4k\": \"Solicitar {count} {count, plugarl, one {Película} other {Películas}} en 4K\",\n  \"components.Settings.RadarrModal.inCinemas\": \"En Cines\",\n  \"components.UserProfile.recentlywatched\": \"Vistos recientemente\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Habilitar agente\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"No se han guardado los ajustes de notificación de Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"¡Notificación de prueba de Gotify enviada!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token de aplicación\",\n  \"components.TvDetails.manageseries\": \"Gestionar Series\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Directorio de datos\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Filtro Activo} other {# Filtros Activos}}\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Filtro Activo} other {# Filtros Activos}}\",\n  \"components.Discover.FilterSlideover.runtime\": \"Duración\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {reproducir} other {reproducir}}\",\n  \"components.Settings.RadarrModal.announced\": \"Anunciado\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Sincronización de la lista de seguimiento de Plex\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Titulo de la aplicación\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Almacenamiento en caché de imágenes de origen externo (requiere una cantidad significativa de espacio en disco)\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"¡Ajustes guardados correctamente!\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"La URL no debe terminar con una barra al final\",\n  \"components.Settings.tautulliSettingsDescription\": \"Opcionalmente configure los ajustes para su servidor Tautulli. Seerr obtiene de Tautulli los datos del historial de visionado de los medios de Plex.\",\n  \"components.TitleCard.tvdbid\": \"Identificador de TheTVDB\",\n  \"components.TvDetails.Season.noepisodes\": \"Lista de episodios no disponible.\",\n  \"components.TvDetails.productioncountries\": \"Producción {countryCount, plural, one {País} other {Países}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Debe proporcionar un ID de Discord válido\",\n  \"i18n.restartRequired\": \"Reinicio necesario\",\n  \"components.Settings.deleteServer\": \"Eliminar servidor {serverType}\",\n  \"components.Settings.experimentalTooltip\": \"Activar esta opción puede provocar un comportamiento inesperado de la aplicación\",\n  \"components.Settings.externalUrl\": \"URL externa\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"¡Configuración de Tautulli guardada con éxito!\",\n  \"components.Settings.validationApiKey\": \"Debe proporcionar una clave API\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"La base de la URL no debe terminar en una barra al final\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"Identificador de TheTVDB\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Limpieza de la caché de imágenes\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Caché de imágenes\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Cada {jobScheduleSeconds, plural, one {second} other {{jobScheduleSeconds} seconds}}\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Sincronización de la disponibilidad de medios\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Servicios de streaming de películas TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Servicios de TV en streaming TMDB\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Recuento de votos de los usuarios de TMDB\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Número de votos entre {minValue} y {maxValue}\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Solicitudes de etiquetas\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Solicitudes de etiquetas\",\n  \"i18n.collection\": \"Colección\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Añadir automáticamente una etiqueta adicional con el nombre de usuario y el nombre para mostrar del solicitante\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Añadir automáticamente una etiqueta adicional con el nombre de usuario y el nombre para mostrar del solicitante\",\n  \"components.MovieDetails.imdbuserscore\": \"Puntuación de los usuarios de IMDB\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Se requiere una contraseña.\",\n  \"components.Login.credentialerror\": \"El usuario o contraseña es incorrecto.\",\n  \"components.Login.initialsignin\": \"Conectar\",\n  \"components.Login.initialsigningin\": \"Conectando…\",\n  \"components.Login.emailtooltip\": \"No es necesario asociar la dirección con su instancia de {mediaServerName}.\",\n  \"components.Login.saving\": \"Añadiendo…\",\n  \"components.Login.title\": \"Añadir Email\",\n  \"components.Login.username\": \"Nombre de usuario\",\n  \"components.Login.validationEmailFormat\": \"El email es inválido\",\n  \"components.Login.validationEmailRequired\": \"Debes proporcional un email\",\n  \"components.Login.validationemailformat\": \"Se requiere de un email válido\",\n  \"components.Login.validationhostformat\": \"Se requiere de una URL válida\",\n  \"components.Login.validationusernamerequired\": \"Se requiere un nombre de usuario\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Esto eliminará de manera irreversible esta {mediaType} de {arr}, incluyendo todos los archivos.\",\n  \"i18n.open\": \"Abierto\",\n  \"components.MovieDetails.downloadstatus\": \"Estado de la descarga\",\n  \"components.MovieDetails.openradarr\": \"Abrir Película en Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"Abrir Película 4K en Radarr\",\n  \"components.MovieDetails.play\": \"Reproducir en {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Reproducir 4K en {mediaServerName}\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Incidencia Resuelta\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Notificame cuando haya nuevos comentarios en incidencias que haya abierto.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Notificame cuando otros usuarios reporten incidencias.\",\n  \"components.PermissionEdit.viewissues\": \"Ver incidencias\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Dar permiso para administrar incidencias.\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Dar permiso para ver incidencias reportadas por otros usuarios.\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Sonido de Notificacion\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Escanear Añadidos Recientemente de Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Escaneo Completo de la libreria de Jellyfin\",\n  \"components.Settings.jellyfinSettings\": \"Ajustes de {mediaServerName}\",\n  \"components.Settings.jellyfinsettings\": \"Ajustes de {mediaServerName}\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Algo salió mal al guardar la configuración de {mediaServerName}.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"¡La configuración de {mediaServerName} se guardó correctamente!\",\n  \"components.Settings.jellyfinlibraries\": \"Bibliotecas {mediaServerName}\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"La biblioteca {mediaServerName} busca títulos. Haga clic en el botón a continuación si no aparece ninguna biblioteca.\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalmente, esto sólo se ejecutará una vez cada 24 horas. Seerr comprobará de forma más agresiva los añadidos recientemente de su servidor {mediaServerName}. ¡Si es la primera vez que configura Seerr, se recomienda un escaneo manual completo de la biblioteca!\",\n  \"components.Settings.save\": \"Guardar Cambios\",\n  \"components.Settings.saving\": \"Guardando…\",\n  \"components.Settings.syncing\": \"Sincronizando\",\n  \"components.Settings.timeout\": \"Tiempo agotado\",\n  \"components.Setup.signinWithPlex\": \"Usa tu cuenta de Plex\",\n  \"components.Setup.configuremediaserver\": \"Configurar servidor multimedia\",\n  \"components.TitleCard.addToWatchList\": \"Añadir a lista de seguimiento\",\n  \"components.TitleCard.watchlistCancel\": \"Lista de seguimiento para <strong>{title}</strong> cancelada.\",\n  \"components.TitleCard.watchlistError\": \"Algo salió mal, intenta de nuevo.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> añadido correctamente a la lista de seguimiento!\",\n  \"components.TvDetails.play\": \"Reproducir en {mediaServerName}\",\n  \"components.UserList.importfromJellyfin\": \"Importar Usuarios de {mediaServerName}\",\n  \"components.UserList.mediaServerUser\": \"Usuario de {mediaServerName}\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} importado correctamente!\",\n  \"components.UserList.importfromJellyfinerror\": \"Se produjo un error al importar usuarios de {mediaServerName}.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Guardar Cambios\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Dispositivo Predeterminado\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Sonido de Notificacion\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Fallo al guardar los ajustes de la notificación Pushbullet.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"¡Los ajustes de notificación Pushbullet se han guardado con éxito!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Token de aplicación API\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Clave de usuario o grupo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Tu <UsersGroupsLink>identificador de usuario o grupo</UsersGroupsLink> de 30 caracteres\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"¡Se han guardado los ajustes de notificación de Pushover!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registrar una aplicación</ApplicationRegistrationLink> para usar con {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Debes proporcionar una clave de usuario o grupo válida\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL requerida\",\n  \"i18n.resolved\": \"Resuelto\",\n  \"components.UserList.importfrommediaserver\": \"Importar Usuarios de {mediaServerName}\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Dispositivo Predeterminado\",\n  \"components.ManageSlideOver.removearr\": \"Eliminar de {arr}\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Enviar notificación cuando se reabran incidencias.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Se requiere una dirección de email.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Token de Acceso\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Debes proporcionar un token de aplicación válido\",\n  \"components.Settings.syncJellyfin\": \"Sincronizar Bibliotecas\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"La dirección de correo es inválida.\",\n  \"components.Login.description\": \"Como es la primera vez que inicias sesión en {applicationName}, es necesario añadir una dirección de email válida.\",\n  \"components.Login.save\": \"Añadir\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Enviar notificación cuando se resuelvan incidencias.\",\n  \"components.PermissionEdit.manageissues\": \"Administrar incidencias\",\n  \"components.PermissionEdit.createissues\": \"Notificar incidencia\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Guardando…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Debes indicar un token de acceso\",\n  \"components.Login.signinwithjellyfin\": \"Utiliza tu cuenta de {mediaServerName}\",\n  \"components.ManageSlideOver.removearr4k\": \"Eliminar de {arr} 4K\",\n  \"components.TvDetails.play4k\": \"Reproducir 4K en {mediaServerName}\",\n  \"components.Setup.signin\": \"Iniciar Sesión\",\n  \"components.Setup.signinWithJellyfin\": \"Utiliza tu cuenta de {mediaServerName}\",\n  \"components.UserList.noJellyfinuserstoimport\": \"No hay usuarios de {mediaServerName} que importar.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Usuario de {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Crea un token desde tu <PushbulletSettingsLink>Opciones de Cuenta</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"No se pudo guardar la configuración de notificaciones de Pushover.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Recibir notificaciones cuando se vuelvan a abrir incidencias que haya reportado.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Reciba notificaciones cuando se resuelvan las incidencias que haya reportado.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Dar permiso para informar incidencias.\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Requerir email de usuario\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Tipo de Serie Anime\",\n  \"components.Settings.SonarrModal.seriesType\": \"Tipo Serie\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Opcionalmente, configure los puntos finales internos y externos para su servidor {mediaServerName}. En la mayoría de los casos, la URL externa es diferente a la URL interna. También se puede configurar una URL de restablecimiento de contraseña personalizada para el inicio de sesión de {mediaServerName}, en caso de que desee redirigir a una página de restablecimiento de contraseña diferente.\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Configure los ajustes para su servidor {mediaServerName}. {mediaServerName} escanea sus bibliotecas de {mediaServerName} para ver qué contenido está disponible.\",\n  \"components.Settings.manualscanJellyfin\": \"Escanear Libreria Manualmente\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> Eliminado correctamente de la lista de seguimiento!\",\n  \"components.UserList.newJellyfinsigninenabled\": \"La configuración <strong>Habilitar nuevo inicio de sesión de {mediaServerName}</strong> está actualmente habilitada. Los usuarios de {mediaServerName} con acceso a la biblioteca no necesitan ser importados para poder iniciar sesión.\",\n  \"components.UserProfile.localWatchlist\": \"Lista de seguimiento de {username}\",\n  \"components.Login.urlBase\": \"Base de la URL\",\n  \"components.Discover.FilterSlideover.status\": \"Estatus\",\n  \"components.Login.servertype\": \"Tipo de servidor\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Series próximas\",\n  \"components.Login.hostname\": \"URL de {mediaServerName}\",\n  \"components.Login.back\": \"Volver atrás\",\n  \"components.Login.adminerror\": \"Debes usar una cuenta de administrador para iniciar sesión.\",\n  \"components.Login.enablessl\": \"Ultilizar SSL\",\n  \"components.Login.invalidurlerror\": \"No se ha podido conectar con el servidor de {mediaServerName}.\",\n  \"components.Login.loginwithapp\": \"Iniciar sesión con {appName}\",\n  \"components.Login.noadminerror\": \"No se ha encontrado un usuario administrativo en el servidor.\",\n  \"components.Login.orsigninwith\": \"O inicia sesión con\",\n  \"components.Login.port\": \"Puerto\",\n  \"components.Login.validationPortRequired\": \"Debes proveer un número de puerto válido\",\n  \"components.Discover.FilterSlideover.certification\": \"Calificación de contenido\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Excluir palabras clave\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Descripción del problema\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\",\n  \"i18n.removefromBlocklist\": \"Quitar de la lista negra\",\n  \"component.BlocklistBlock.blocklistdate\": \"Fecha de bloqueo\",\n  \"component.BlocklistBlock.blocklistedby\": \"Bloqueado por\",\n  \"component.BlocklistModal.blocklisting\": \"Lista de bloqueo\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> no está bloqueado.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Gestionar medios bloqueados.\",\n  \"components.Blocklist.blocklistdate\": \"fecha\",\n  \"components.Blocklist.blocklistedby\": \"{date} por {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Ajuste de bloqueos\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Etiquetas bloqueadas\",\n  \"components.Blocklist.filterManual\": \"Manual\",\n  \"components.Blocklist.mediaName\": \"Nombre\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb id\",\n  \"components.Blocklist.mediaType\": \"Tipo\",\n  \"components.Blocklist.showAllBlocklisted\": \"Mostrar todos los medios bloqueados\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Imposible conectar a {services}. Alguna información puede no estar disponible.\",\n  \"components.Layout.Sidebar.blocklist\": \"Bloqueo\"\n}\n"
  },
  {
    "path": "src/i18n/locale/es_MX.json",
    "content": "{\n  \"components.Settings.SonarrModal.ssl\": \"Usar SSL\",\n  \"components.Settings.SonarrModal.servername\": \"Nombre del Servidor\",\n  \"components.Settings.SonarrModal.server4k\": \"Servidor 4K\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Selecciona la carpeta raíz\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Selecciona un perfil de calidad\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Carpetas por Temporada\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Carpeta Raíz\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Perfil de Calidad\",\n  \"components.Settings.SonarrModal.port\": \"Puerto\",\n  \"components.Settings.SonarrModal.hostname\": \"Nombre de Host o Dirección IP\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Editar Servidor Sonarr\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Servidor por Defecto\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Añadir Nuevo Servidor Sonarr\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL de base\",\n  \"components.Settings.SonarrModal.apiKey\": \"Clave API\",\n  \"components.Settings.SonarrModal.add\": \"Agregar Servidor\",\n  \"components.Settings.SettingsAbout.version\": \"Versión\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Peticiones Totales\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Contenido Total\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Discursiones en GitHub\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Soporte\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Debes seleccionar una carpeta raíz\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Debes seleccionar un perfil de calidad\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Debes proporcionar un número de puerto válido\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Debes proporcionar un nombre de servidor\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Debes proporcionar un nombre de host o dirección IP válido\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Debes proporcionar la clave API\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"¡Conexión con Radarr establecida con éxito!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Error al connectar al Radarr.\",\n  \"components.Settings.RadarrModal.ssl\": \"Usar SSL\",\n  \"components.Settings.RadarrModal.servername\": \"Nombre del Servidor\",\n  \"components.Settings.RadarrModal.server4k\": \"Servidor 4K\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Selecciona la carpeta raíz\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Selecciona un perfil de calidad\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Selecciona Disponibilidad Mínima\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Carpeta Raíz\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Perfil de Calidad\",\n  \"components.Settings.RadarrModal.port\": \"Puerto\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Disponibilidad Mínima\",\n  \"components.Settings.RadarrModal.hostname\": \"Nombre de Host o Dirección IP\",\n  \"components.Settings.RadarrModal.editradarr\": \"Editar Servidor Radarr\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Servidor por Defecto\",\n  \"components.Settings.RadarrModal.createradarr\": \"Añadir Nuevo Servidor Radarr\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL de base\",\n  \"components.Settings.RadarrModal.apiKey\": \"Clave API\",\n  \"components.Settings.RadarrModal.add\": \"Agregar Servidor\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Debes proporcionar un número de puerto válido\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Debes proporcionar un nombre válido de host o una dirección IP\",\n  \"components.Settings.Notifications.smtpPort\": \"Puerto SMTP\",\n  \"components.Settings.Notifications.smtpHost\": \"Host SMTP\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"¡Ajustes de notificación de Email guardados con éxito!\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Fallo al guardar ajustes de notificación de Email.\",\n  \"components.Settings.Notifications.emailsender\": \"Dirección del Remitente\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"¡Ajustes de notificación de Discord guardados con éxito!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Fallo al guardar ajustes de notificación de Discord.\",\n  \"components.Settings.Notifications.authUser\": \"Usuario SMTP\",\n  \"components.Settings.Notifications.authPass\": \"Contraseña SMTP\",\n  \"components.Settings.Notifications.agentenabled\": \"Habilitar Agente\",\n  \"components.Search.searchresults\": \"Resultado de la búsqueda\",\n  \"components.RequestModal.selectseason\": \"Seleccionar Temporada(s)\",\n  \"components.RequestModal.seasonnumber\": \"Temporada {number}\",\n  \"components.RequestModal.season\": \"Temporada\",\n  \"components.RequestModal.requestseasons\": \"Solicitar {seasonCount} {seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestModal.requestfrom\": \"La solicitud de {username} está pendiente de aprobación.\",\n  \"components.RequestModal.requestadmin\": \"Esta solicitud será aprobada automáticamente.\",\n  \"components.RequestModal.requestSuccess\": \"¡<strong>{title}</strong> solicitada con éxito!\",\n  \"components.RequestModal.requestCancel\": \"Solicitud para <strong>{title}</strong> cancelada.\",\n  \"components.RequestModal.pendingrequest\": \"Solicitud pendiente\",\n  \"components.RequestModal.numberofepisodes\": \"# de Episodios\",\n  \"components.RequestModal.cancel\": \"Cancelar Petición\",\n  \"components.RequestList.requests\": \"Solicitudes\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.PersonDetails.ascharacter\": \"como {character}\",\n  \"components.PersonDetails.appearsin\": \"Apariciones\",\n  \"components.MovieDetails.similar\": \"Títulos Similares\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutos\",\n  \"components.MovieDetails.revenue\": \"Recaudado\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Fecha} other {Fechas}} de Lanzamiento\",\n  \"components.MovieDetails.cast\": \"Reparto\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Reparto Completo\",\n  \"components.MovieDetails.recommendations\": \"Recomendaciones\",\n  \"components.MovieDetails.overviewunavailable\": \"Resumen indisponible.\",\n  \"components.MovieDetails.overview\": \"Resumen\",\n  \"components.MovieDetails.originallanguage\": \"Idioma Original\",\n  \"components.MovieDetails.budget\": \"Presupuesto\",\n  \"components.Layout.UserDropdown.signout\": \"Cerrar Sesión\",\n  \"components.Layout.Sidebar.users\": \"Usuarios\",\n  \"components.Layout.Sidebar.settings\": \"Ajustes\",\n  \"components.Layout.Sidebar.requests\": \"Solicitudes\",\n  \"components.Layout.Sidebar.dashboard\": \"Descubrir\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Buscar Películas y Series\",\n  \"components.Discover.upcomingmovies\": \"Próximas Películas\",\n  \"components.Discover.upcoming\": \"Próximas Películas\",\n  \"components.Discover.trending\": \"Tendencias\",\n  \"components.Discover.recentrequests\": \"Peticiones Recientes\",\n  \"components.Discover.recentlyAdded\": \"Agregado Recientemente\",\n  \"components.Discover.populartv\": \"Series Populares\",\n  \"components.Discover.popularmovies\": \"Películas Populares\",\n  \"components.Settings.addsonarr\": \"Agregar servidor Sonarr\",\n  \"components.Settings.address\": \"Dirección\",\n  \"components.Settings.addradarr\": \"Agregar servidor Radarr\",\n  \"components.Settings.activeProfile\": \"Perfil activo\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Debes seleccionar una carpeta raíz\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Debes seleccionar un perfil\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Debes proporcionar un número de puerto valido\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Debes proporcionar un nombre de servidor\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Debes proporcionar un nombre de host o dirección IP válido\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Debes proporcionar la clave API\",\n  \"components.Settings.menuLogs\": \"Registro\",\n  \"pages.returnHome\": \"Volver al Inicio\",\n  \"pages.oops\": \"Ups\",\n  \"i18n.unavailable\": \"No Disponible\",\n  \"i18n.tvshows\": \"Series\",\n  \"i18n.processing\": \"Procesando\",\n  \"i18n.pending\": \"Pendiente\",\n  \"i18n.partiallyavailable\": \"Parcialmente Disponible\",\n  \"i18n.movies\": \"Películas\",\n  \"i18n.delete\": \"Eliminar\",\n  \"i18n.declined\": \"Rechazado\",\n  \"i18n.decline\": \"Rechazar\",\n  \"i18n.cancel\": \"Cancelar\",\n  \"i18n.available\": \"Disponible\",\n  \"i18n.approved\": \"Aprobado\",\n  \"i18n.approve\": \"Aprobar\",\n  \"components.UserList.userlist\": \"Lista de usuarios\",\n  \"components.UserList.user\": \"Usuario\",\n  \"components.UserList.totalrequests\": \"Solicitudes\",\n  \"components.UserList.role\": \"Rol\",\n  \"components.UserList.plexuser\": \"Usuario de Plex\",\n  \"components.UserList.created\": \"Unido\",\n  \"components.UserList.admin\": \"Administrador\",\n  \"components.TvDetails.similar\": \"Series Similares\",\n  \"components.TvDetails.recommendations\": \"Recomendaciones\",\n  \"components.TvDetails.overviewunavailable\": \"Resumen no disponible.\",\n  \"components.TvDetails.overview\": \"Resumen\",\n  \"components.TvDetails.originallanguage\": \"Idioma original\",\n  \"components.TvDetails.cast\": \"Reparto\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Reparto completo de la serie\",\n  \"components.Setup.welcome\": \"Bienvenido a Jellyseerr\",\n  \"components.Setup.signinMessage\": \"Comience iniciando sesión con su cuenta de Plex\",\n  \"components.Setup.finishing\": \"Finalizando…\",\n  \"components.Setup.finish\": \"Finalizar configuración\",\n  \"components.Setup.continue\": \"Continuar\",\n  \"components.Setup.configureservices\": \"Configurar servicios\",\n  \"components.Settings.validationPortRequired\": \"Debes proporcionar un número de puerto válido\",\n  \"components.Settings.validationHostnameRequired\": \"Debes proporcionar un nombre de host o dirección IP válido\",\n  \"components.Settings.startscan\": \"Iniciar Escaneo\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.sonarrsettings\": \"Ajustes de Sonarr\",\n  \"components.Settings.radarrsettings\": \"Ajustes de Radarr\",\n  \"components.Settings.port\": \"Puerto\",\n  \"components.Settings.plexsettingsDescription\": \"Configure los ajustes de su servidor Plex. Jellyseerr escanea tu biblioteca para determinar la disponibilidad de contenidos.\",\n  \"components.Settings.plexsettings\": \"Ajustes de Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"Las bibliotecas en las que Jellyseerr 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.\",\n  \"components.Settings.plexlibraries\": \"Bibliotecas Plex\",\n  \"components.Settings.notrunning\": \"Sin ejecutarse\",\n  \"components.Settings.notificationsettings\": \"Configuración de notificaciones\",\n  \"components.Settings.menuServices\": \"Servicios\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Notificaciones\",\n  \"components.Settings.menuJobs\": \"Tareas y Caché\",\n  \"components.Settings.menuGeneralSettings\": \"General\",\n  \"components.Settings.menuAbout\": \"Acerca de\",\n  \"components.Settings.manualscanDescription\": \"Normalmente, esto sólo se ejecutará una vez cada 24 horas. Jellyseerr comprobará de forma más agresiva los añadidos recientemente de su servidor Plex. ¡Si es la primera vez que configura Plex, se recomienda un escaneo manual completo de la biblioteca!\",\n  \"components.Settings.manualscan\": \"Escaneo Manual de Biblioteca\",\n  \"components.Settings.librariesRemaining\": \"Bibliotecas restantes: {count}\",\n  \"components.Settings.hostname\": \"Nombre de host o Dirección IP\",\n  \"components.Settings.deleteserverconfirm\": \"¿Está seguro de que desea eliminar este servidor?\",\n  \"components.Settings.default4k\": \"4K predeterminado\",\n  \"components.Settings.default\": \"Predeterminado\",\n  \"components.Settings.currentlibrary\": \"Biblioteca actual: {name}\",\n  \"components.Settings.cancelscan\": \"Cancelar Escaneo\",\n  \"i18n.deleting\": \"Eliminando…\",\n  \"components.UserList.userdeleteerror\": \"Algo salió mal al eliminar al usuario.\",\n  \"components.UserList.userdeleted\": \"¡Usuario eliminado con éxito!\",\n  \"components.UserList.deleteuser\": \"Eliminar usuario\",\n  \"components.UserList.deleteconfirm\": \"¿Está seguro de que desea eliminar este usuario? Se eliminarán todas sus solicitudes de forma permanente.\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Probar conexión para cargar carpetas raíz\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Probar conexión para cargar perfiles de calidad\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Cargando carpetas raíz…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Cargando perfiles de calidad…\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Debes seleccionar disponibilidad mínima\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Prueba la conexión para cargar carpetas raíz\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Prueba la conexión para cargar perfiles de calidad\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Cargando carpetas raíz…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Cargando perfiles de calidad…\",\n  \"i18n.close\": \"Cerrar\",\n  \"components.TvDetails.showtype\": \"Tipos de Series\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Red} other {Redes}}\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Carpeta raíz de anime\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Perfil de calidad de anime\",\n  \"components.Settings.SettingsAbout.timezone\": \"Zona horaria\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Ver en GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Ver registro de cambios\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Cambios de la versión {version}\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Versiones\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"La fecha de lanzamiento no está actualmente disponible.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Última Versión\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Actual\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Estudio} other {Estudios}}\",\n  \"components.UserList.importfromplexerror\": \"Algo salió mal importando usuarios de Plex.\",\n  \"components.UserList.importfromplex\": \"Importar Usuarios de Plex\",\n  \"components.UserList.importedfromplex\": \"<strong> {userCount} </strong> Plex {userCount, plural, one {usuario} other {usuarios}} importado correctamente!\",\n  \"components.TvDetails.viewfullcrew\": \"Ver Equipo Completo\",\n  \"components.TvDetails.firstAirDate\": \"Primera fecha de emisión\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Equipo completo de la serie\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Permitir certificados autofirmados\",\n  \"components.PersonDetails.crewmember\": \"Equipo\",\n  \"components.MovieDetails.viewfullcrew\": \"Ver Equipo Completo\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Equipo Completo\",\n  \"components.CollectionDetails.requestcollection\": \"Solicitar Colección\",\n  \"components.CollectionDetails.overview\": \"Resumen\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Películas\",\n  \"i18n.retry\": \"Reintentar\",\n  \"i18n.requested\": \"Solicitado\",\n  \"i18n.failed\": \"Fallido\",\n  \"components.TvDetails.watchtrailer\": \"Ver Trailer\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"¡Ajustes de notificación de Slack guardados con éxito!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Fallo al guardar ajustes de notificación de Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Habilitar Agente\",\n  \"components.RequestList.RequestItem.failedretry\": \"Algo salió mal al reintentar la solicitud.\",\n  \"components.MovieDetails.watchtrailer\": \"Ver Trailer\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Envía una notificación cuando se solicita nuevo contenido que requiere ser aprobado.\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentación\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Debes proporcionar un ID de chat válido\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Debes proporcionar un token de autorización del bot\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"¡Se han guardado los ajustes de notificación de Telegram con éxito!\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"La configuración de notificaciones de Telegram no se pudo guardar.\",\n  \"components.Settings.Notifications.senderName\": \"Nombre del remitente\",\n  \"components.Settings.Notifications.chatId\": \"ID de chat\",\n  \"components.Settings.Notifications.botAPI\": \"Token de Autorización del Bot\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Petición pendiente de aprobar\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Envía una notificación cuando el contenido no se agrega a los servicios (Radarr / Sonarr).\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Procesamiento de Petición Fallida\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Envía una notificación cuando el contenido solicitado está disponible.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Petición Disponible\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Envía una notificación cuando el contenido solicitado es aprobado manualmente.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Petición Aprobada\",\n  \"i18n.request\": \"Solicitar\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Debes proporcionar una clave de usuario o grupo válida\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Debes proporcionar un token de aplicación válido\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Clave de usuario o grupo\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"¡Se han guardado los ajustes de notificación de Pushover!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"No se pudo guardar la configuración de notificaciones de Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Agente habilitado\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token de aplicación API\",\n  \"components.RequestList.sortModified\": \"Última modificación\",\n  \"components.RequestList.sortAdded\": \"Más Reciente\",\n  \"components.RequestList.showallrequests\": \"Mostrar todas las solicitudes\",\n  \"components.RequestBlock.requestoverrides\": \"Anulaciones de solicitudes\",\n  \"i18n.edit\": \"Editar\",\n  \"components.UserList.validationpasswordminchars\": \"La contraseña es demasiado corta; debe tener 8 caracteres como mínimo\",\n  \"components.UserList.usercreatedsuccess\": \"¡Usuario creado con éxito!\",\n  \"components.UserList.usercreatedfailed\": \"Algo salió mal al intentar crear al usuario.\",\n  \"components.UserList.passwordinfodescription\": \"Configura una URL de aplicación y habilita las notificaciones por email para poder utilizar las contraseñas generadas automáticamente.\",\n  \"components.UserList.password\": \"Contraseña\",\n  \"components.UserList.localuser\": \"Usuario local\",\n  \"components.UserList.email\": \"Dirección de correo electrónico\",\n  \"components.UserList.creating\": \"Creando…\",\n  \"components.UserList.createlocaluser\": \"Crear usuario local\",\n  \"components.UserList.create\": \"Crear\",\n  \"components.UserList.autogeneratepassword\": \"Generar Contraseña Automáticamente\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"¡Configuración de notificación de webhook guardada con éxito!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"No se pudo guardar la configuración de notificación de webhook.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Debes proporcionar un payload de JSON válido\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Ayuda de variable de plantilla\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"¡Payload de JSON restablecido con éxito!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Restablecer predeterminado\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Payload de JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Encabezado de autorización\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Habilitar Agente\",\n  \"components.RequestModal.requestedited\": \"¡Solicitud para <strong>{title}</strong> modificada con éxito!\",\n  \"components.RequestModal.requestcancelled\": \"Solicitud para <strong>{title}</strong> cancelada.\",\n  \"components.RequestModal.pending4krequest\": \"Solicitud 4K Pendiente\",\n  \"components.RequestModal.errorediting\": \"Algo salió mal al editar la solicitud.\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Carpeta Raíz\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Perfil de calidad\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Servidor de destino\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Predeterminado)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Esta serie es un anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avanzadas\",\n  \"components.RequestButton.viewrequest4k\": \"Ver Solicitud 4K\",\n  \"components.RequestButton.viewrequest\": \"Ver Solicitud\",\n  \"components.RequestButton.requestmore4k\": \"Solicitar más en 4K\",\n  \"components.RequestButton.requestmore\": \"Solicitar más\",\n  \"components.RequestButton.declinerequests\": \"Rechazar {requestCount, plural, one {solicitud} other {{requestCount} solicitudes}}\",\n  \"components.RequestButton.declinerequest4k\": \"Rechazar Solicitud 4K\",\n  \"components.RequestButton.declinerequest\": \"Rechazar Solicitud\",\n  \"components.RequestButton.decline4krequests\": \"Rechazar {requestCount, plural, one {solicitud en 4K} other {{requestCount} solicitudes en 4K}}\",\n  \"components.RequestButton.approverequests\": \"Aprobar {requestCount, plural, one {solicitud} other {{requestCount} solicitudes}}\",\n  \"components.RequestButton.approverequest4k\": \"Aprobar Solicitud 4K\",\n  \"components.RequestButton.approverequest\": \"Aprobar Solicitud\",\n  \"components.RequestButton.approve4krequests\": \"Aprobar {requestCount, plural, one {petición en 4K} other {requestCount} peticiones en 4K}}\",\n  \"components.RequestBlock.server\": \"Servidor de Destino\",\n  \"components.RequestBlock.rootfolder\": \"Carpeta Raíz\",\n  \"components.RequestBlock.profilechanged\": \"Perfil de Calidad\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Ver más\",\n  \"components.Login.validationpasswordrequired\": \"Se requiere contraseña\",\n  \"components.Login.validationemailrequired\": \"Debes indicar una dirección de email válida\",\n  \"components.Login.signinwithoverseerr\": \"Usa tu cuenta de {applicationTitle}\",\n  \"components.Login.password\": \"Contraseña\",\n  \"components.Login.loginerror\": \"Algo salió mal al intentar iniciar sesión.\",\n  \"components.Login.email\": \"Dirección de correo electrónico\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Petición Rechazada\",\n  \"components.RequestModal.autoapproval\": \"Aprobación Automática\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Envía notificaciones cuando las solicitudes sean rechazadas.\",\n  \"i18n.experimental\": \"Experimental\",\n  \"components.Login.signingin\": \"Iniciando sesión…\",\n  \"components.Login.signin\": \"Iniciar Sesión\",\n  \"components.Login.signinwithplex\": \"Usa tu cuenta de Plex\",\n  \"components.Login.signinheader\": \"Inicia sesión para continuar\",\n  \"components.PermissionEdit.request4k\": \"Solicitar 4K\",\n  \"components.PermissionEdit.request\": \"Solicitar\",\n  \"components.PermissionEdit.admin\": \"Administrador\",\n  \"components.Discover.discover\": \"Descubre\",\n  \"components.Layout.UserDropdown.settings\": \"Ajustes\",\n  \"components.Layout.UserDropdown.myprofile\": \"Perfil\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Series en {language}\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Series de {genre}\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Películas de {studio}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Series de {network}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Películas\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Películas de {genre}\",\n  \"i18n.loading\": \"Cargando…\",\n  \"components.ResetPassword.emailresetlink\": \"Enviar enlace de recuperación por email\",\n  \"components.ResetPassword.email\": \"Dirección de Email\",\n  \"components.ResetPassword.confirmpassword\": \"Confirmar Contraseña\",\n  \"components.RequestModal.requesterror\": \"Algo fue mal al realizar la solicitud.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"No se ha podido emparejar automáticamente tu solicitud. Por favor, seleccione el correcto de la lista.\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Pedir como\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Perfil de Idioma\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestList.RequestItem.requested\": \"Pedida\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} por {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Modificado\",\n  \"components.RegionSelector.regionServerDefault\": \"({Region}) por defecto\",\n  \"components.RegionSelector.regionDefault\": \"Todas las Regiones\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Conceder permiso para ver las solicitudes de otros usuarios.\",\n  \"components.PermissionEdit.viewrequests\": \"Ver Solicitudes\",\n  \"components.PermissionEdit.usersDescription\": \"Concede permisos para gestionar usuarios. Los usuarios con este permiso no pueden modificar usuarios o conceder privilegios de Administrador.\",\n  \"components.PermissionEdit.users\": \"Gestión de Usuarios\",\n  \"components.PermissionEdit.requestDescription\": \"Concede permisos para solicitar contenidos que no sean 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Concede permisos para solicitar series en 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"Pedir Series 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Concede permisos para solicitar películas en 4K.\",\n  \"components.PermissionEdit.request4kDescription\": \"Concede permisos para solicitar contenidos en 4K.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Concede permisos para gestionar las solicitudes de contenidos. Todas las solicitudes de un usuario con este permiso serán aprobadas automáticamente.\",\n  \"components.PermissionEdit.request4kMovies\": \"Solicita Películas 4K\",\n  \"components.PermissionEdit.managerequests\": \"Gestionar Solicitudes\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Concede aprobación automática para todas las solicitudes de series no 4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Auto-Aprueba Series\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Concede aprobación automática para todas las solicitudes de películas no 4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Auto-Aprueba Películas\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Concede aprobación automática para todas las solicitudes que no sean 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Concede aprobación automática para todas las solicitudes de series 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Auto-Aprueba Series 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Concede aprobación automática para todas las solicitudes de películas 4K.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Auto-Aprueba Películas 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Concede aprobación automática para todas las solicitudes de contenidos 4K.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Auto-Aprobación 4K\",\n  \"components.PermissionEdit.autoapprove\": \"Auto-Aprobación\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Concede permisos para configurar opciones avanzadas en las solicitudes.\",\n  \"components.PermissionEdit.advancedrequest\": \"Solicitudes Avanzadas\",\n  \"components.PermissionEdit.adminDescription\": \"Acceso completo de administrador. Ignora otras comprobaciones de permisos.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Envía notificaciones cuando los usuarios solicitan nuevos contenidos que se aprueban automáticamente.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Petición Aprobada Automáticamente\",\n  \"components.MovieDetails.markavailable\": \"Marcar como Disponible\",\n  \"components.MovieDetails.mark4kavailable\": \"Marcar como Disponible en 4K\",\n  \"components.Login.forgotpassword\": \"¿Contraseña olvidada?\",\n  \"components.Discover.upcomingtv\": \"Próximas Series\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Géneros de Series\",\n  \"components.Discover.StudioSlider.studios\": \"Estudios\",\n  \"components.Discover.NetworkSlider.networks\": \"Cadenas de TV\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Géneros de Películas\",\n  \"components.CollectionDetails.requestcollection4k\": \"Pedir Colección en 4K\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"El montaje del volumen <code>{appDataPath}</code> no se ha configurado correctamente. Todos los datos se eliminarán cuando el contenedor se pare o reinicie.\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Permisos por Defecto\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Tarea Desconocida\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Escaneo de Sonarr\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Ejecutar Ahora\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Escaneo de Radarr\",\n  \"components.Settings.SettingsJobsCache.process\": \"Procesamiento\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Escaneo de Recien Añadidos de Plex\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Escaneo Completo de la Biblioteca de Plex\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Próxima Ejecución\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tipo\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} comenzada.\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Overserr realiza ciertas tareas de mantenimiento como Tareas Programadas, pero también pueden lanzarse manualmente a continuación. Lanzar una tarea manual no altera su programación.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Tareas Programadas\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Nombre de Tarea Programada\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} cancelada.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Vaciar Caché\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Reiniciar Descarga Sincronizada\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Descarga Sincronizada\",\n  \"components.Settings.SettingsJobsCache.command\": \"Comando\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Cancelar Tarea Programada\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Valor del Tamaño\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Nombre de Caché\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Fallos\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Tamaño de Clave\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Claves Totales\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Consultas\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} caché limpiada.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Overseer cachea peticiones a APIs externas para optimizar el rendimiento y evitar llamadas innecesarias a esas APIs.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Caché\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"La base de la URL no debe terminar en una barra al final\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"La base de la URL debe tener una barra al principio\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"La URL no puede acabar con una barra\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Debes indicar una URL válida\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Habilitar Escaneo\",\n  \"components.Settings.RadarrModal.externalUrl\": \"URL externa\",\n  \"components.Settings.Notifications.validationUrl\": \"Debes indicar una URL válida\",\n  \"components.Settings.Notifications.validationEmail\": \"Debes indicar una dirección de email válida\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Enviar notificaciones sin sonido\",\n  \"components.Settings.Notifications.sendSilently\": \"Enviar silenciosamente\",\n  \"components.Settings.Notifications.botUsername\": \"Nombre de usuario del Bot\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL del Bot Avatar\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Debes indicar una URL válida\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Debes indicar una URL válida\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Debes indicar un token de acceso\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"¡Los ajustes de notificación Pushbullet se han guardado con éxito!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Fallo al guardar los ajustes de la notificación Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Habilitar Agente\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Token de Acceso\",\n  \"components.Search.search\": \"Buscar\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Debes indicar una contraseña\",\n  \"components.ResetPassword.validationpasswordminchars\": \"La contraseña es demasiado corta; debería tener al menos 8 caracteres\",\n  \"components.ResetPassword.validationpasswordmatch\": \"La contraseña debe coincidir\",\n  \"components.ResetPassword.validationemailrequired\": \"Debes indicar una dirección de email valida\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"¡Contraseña reiniciada con éxito!\",\n  \"components.ResetPassword.resetpassword\": \"Reiniciar contraseña\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Un enlace para reiniciar la contraseña se enviará a la dirección de email indicada si está asociada a un usuario valido.\",\n  \"components.ResetPassword.password\": \"Contraseña\",\n  \"components.ResetPassword.gobacklogin\": \"Volver a la Página de Login\",\n  \"components.RequestModal.alreadyrequested\": \"Ya Pedida\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Géneros de Series\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Géneros de Películas\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Ajustes de Notificaciones\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID de Usuario\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Usuario\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"¡Ajustes guardados con éxito!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Algo fue mal al guardar los ajustes.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rol\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Región en sección \\\"Descubre\\\"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Usuario en Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Propietario\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Idioma de la sección \\\"Descubre\\\"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Usuario Local\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Ajustes Generales\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Nombre a mostrar\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrador\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Tipo de Cuenta\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Id de Usuario: {userid}\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Editar Ajustes\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Ver Perfil\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Unido el {joindate}\",\n  \"components.UserList.validationEmail\": \"Debes indicar un dirección de email válida\",\n  \"components.UserList.userssaved\": \"¡Permisos de usuario guardados con éxito!\",\n  \"components.UserList.users\": \"Usuarios\",\n  \"components.UserList.userfail\": \"Algo fue mal al guardar los permisos del usuario.\",\n  \"components.UserList.sortRequests\": \"Número de Solicitudes\",\n  \"components.UserList.sortDisplayName\": \"Nombre a mostrar\",\n  \"components.UserList.sortCreated\": \"Fecha de Unión\",\n  \"components.UserList.owner\": \"Propietario\",\n  \"components.UserList.edituser\": \"Editar Permisos de Usuario\",\n  \"components.UserList.bulkedit\": \"Edición Masiva\",\n  \"components.UserList.accounttype\": \"Tipo\",\n  \"components.TvDetails.nextAirDate\": \"Próxima Emisión\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutos\",\n  \"components.TvDetails.episodeRuntime\": \"Duración del Episodio\",\n  \"components.Setup.setup\": \"Configuración\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"¡Recibida la lista de servidores de Plex con éxito!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Fallo al obtener la lista de servidores de Plex.\",\n  \"components.Settings.toastPlexRefresh\": \"Obteniendo la lista de servidores desde Plex…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"¡Conexión al servidor Plex establecida con éxito!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Fallo al conectar con Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"Intentando conectar con Plex…\",\n  \"components.Settings.settingUpPlexDescription\": \"Para configurar Plex, puedes introducir manualmente los detalles o seleccionar un servidor obtenido de <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Pulsa el botón de la derecha del desplegable para obtener los servidores disponibles.\",\n  \"components.Settings.serverpresetRefreshing\": \"Obteniendo servidores…\",\n  \"components.Settings.serverpresetManualMessage\": \"Configuración manual\",\n  \"components.Settings.serverpresetLoad\": \"Presiona el botón para obtener los servidores disponibles\",\n  \"components.Settings.serverpreset\": \"Servidor\",\n  \"components.Settings.serverRemote\": \"remoto\",\n  \"components.Settings.serverLocal\": \"local\",\n  \"components.Settings.scanning\": \"Sincronizando…\",\n  \"components.Settings.scan\": \"Sincronizar Bibliotecas\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Configura y habilita los agentes de notificaciones.\",\n  \"components.Settings.menuUsers\": \"Usuarios\",\n  \"components.Settings.email\": \"Email\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Debes seleccionar un perfil de idioma\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"La URL BASE no puede terminar con una barra\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"La URL Base debe comenzar con una barra\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"La URL no puede terminar con una barra\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Debe indicar una URL válida\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"¡Conexión establecida con Sonarr con éxito!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Fallo al conectar con Sonarr.\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Probar conexión para obtener los perfiles de idioma\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Habilitar Escaneo\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Seleccionar Perfil de Idioma\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Cargando perfiles de idioma…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Perfil de Idioma\",\n  \"components.Settings.SonarrModal.externalUrl\": \"URL Externa\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Perfil de Idioma para Anime\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Configura los ajustes de usuarios globales y por defecto.\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Ajustes de Usuario\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"¡Ajustes de usuario guardados con éxito!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Algo fue mal mientras se guardaban los cambios.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Habilitar Autenticación Local\",\n  \"components.Settings.SettingsLogs.time\": \"Marca de tiempo (timestamp)\",\n  \"components.Settings.SettingsLogs.showall\": \"Mostrar todos los logs\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pausar\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Reanudar\",\n  \"components.Settings.SettingsLogs.message\": \"Mensaje\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Puede ver estos logs directamente via <code>stdout</code> o en <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.logs\": \"Registros\",\n  \"components.Settings.SettingsLogs.level\": \"Severidad\",\n  \"components.Settings.SettingsLogs.label\": \"Etiqueta\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Advertencia\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.SettingsLogs.filterError\": \"Error\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Depuración\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Firmar mensajes de email encriptados usando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Clave Privada PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Firmar mensajes de email usando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPassword\": \"Contraseña de PGP\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nueva Contraseña\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Contraseña Actual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Confirmar Contraseña\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Debes indicar un Id de chat válido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Debes indicar un Id de usuario válido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Comienza un chat</TelegramBotLink>, añade el <GetIdBotLink>@get_id_bot</GetIdBotLink>, y envía el comando <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID del Chat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Enviar notificaciones sin sonido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Enviar de forma silenciosa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notificaciones\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"El <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> asociado a su cuenta de usuario\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtrar contenido por disponibilidad regional\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtrar contenido por idioma original\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"General\",\n  \"components.Settings.services\": \"Servicios\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Notificaciones\",\n  \"components.Settings.SettingsUsers.users\": \"Usuarios\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Tareas y Caché\",\n  \"components.Settings.SettingsAbout.about\": \"Acerca de\",\n  \"components.ResetPassword.passwordreset\": \"Reinicio de Contraseña\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"No tienes permiso para modificar estos ajustes de usuario.\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Temporada} other {# Temporadas}}\",\n  \"pages.somethingwentwrong\": \"Algo fue mal\",\n  \"pages.serviceunavailable\": \"Servicio No Disponible\",\n  \"pages.pagenotfound\": \"Página No Encontrada\",\n  \"pages.internalservererror\": \"Error Interno del Servidor\",\n  \"i18n.usersettings\": \"Ajustes de Usuario\",\n  \"i18n.settings\": \"Ajustes\",\n  \"i18n.advanced\": \"Avanzado\",\n  \"components.UserProfile.recentrequests\": \"Solicitudes Recientes\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Permisos\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notificaciones\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"General\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Contraseña\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"No puedes modificar tus propios permisos.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"¡Permisos guardados con éxito!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Algo fue mal al guardar los ajustes.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Permisos\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"La contraseña es muy corta; debería tener, al menos, 8 caracteres\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Debes proporcionar una nueva contraseña\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Debes indicar tu contraseña actual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Las contraseñas deben coincidir\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Debes confirmar la nueva contraseña\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"¡Contraseña guardada correctamente!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Algo fue mal al guardar la contraseña. ¿Has introducido correctamente tu contraseña actual?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Algo fue mal al guardar la contraseña.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Contraseña\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"No tienes permiso para modificar la contraseña del usuario.\",\n  \"components.Settings.enablessl\": \"Usar SSL\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Detalles del Log\",\n  \"components.Settings.SettingsLogs.extraData\": \"Datos Adicionales\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Copiar al Portapapeles\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Copiar log al portapapeles.\",\n  \"components.UserList.nouserstoimport\": \"No hay usuarios de Plex para importar.\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Nacido el {birthdate}\",\n  \"components.PersonDetails.alsoknownas\": \"También Conocido como: {names}\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.view\": \"Ver\",\n  \"i18n.tvshow\": \"Series\",\n  \"i18n.testing\": \"Probando…\",\n  \"i18n.test\": \"Probar\",\n  \"i18n.status\": \"Estado\",\n  \"i18n.showingresults\": \"Mostrando <strong>{from}</strong> a <strong>{to}</strong> de <strong>{total}</strong> resultados\",\n  \"i18n.saving\": \"Guardando…\",\n  \"i18n.save\": \"Guardar Cambios\",\n  \"i18n.resultsperpage\": \"Mostrar {pageSize} resultados por página\",\n  \"i18n.requesting\": \"Pidiendo…\",\n  \"i18n.request4k\": \"Pedir en 4K\",\n  \"i18n.previous\": \"Anterior\",\n  \"i18n.notrequested\": \"No Solicitado\",\n  \"i18n.noresults\": \"Sin resultados.\",\n  \"i18n.next\": \"Adelante\",\n  \"i18n.movie\": \"Película\",\n  \"i18n.canceling\": \"Cancelando…\",\n  \"i18n.back\": \"Atrás\",\n  \"i18n.areyousure\": \"¿Estás Seguro?\",\n  \"i18n.all\": \"Todas\",\n  \"components.UserProfile.unlimited\": \"Ilimitadas\",\n  \"components.UserProfile.totalrequests\": \"Solicitudes Totales\",\n  \"components.UserProfile.seriesrequest\": \"Solicitudes de Series\",\n  \"components.UserProfile.requestsperdays\": \"{limit} restantes\",\n  \"components.UserProfile.pastdays\": \"{type} (últimos {days} días)\",\n  \"components.UserProfile.movierequests\": \"Solicitudes de Películas\",\n  \"components.UserProfile.limit\": \"{remaining} de {limit}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Límite de Solicitudes de Series\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Límite de Solicitudes de Películas\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Límite global de Sobreescritura\",\n  \"components.TvDetails.originaltitle\": \"Título Original\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Límite Global de Solicitudes de Series\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Límite Global de Solicitudes de Películas\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {temporada} other {temporadas}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"temporada\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Este usuario necesita tener al menos <strong>{seasons}</strong> {seasons, plural, one {solicitud de temporada} other {solicitudes de temporadas}} restante(s) para poder enviar una solicitud para esta serie.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Necesitas tener al menos <strong>{seasons}</strong> {seasons, plural, one {solicitud de temporada} other {solicitudes de temporadas}} restante(s) para poder enviar una solicitud para esta serie.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {solicitud} other {solicitudes}} restante(s)\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Puedes ver un resumen de los límites de solicitudes de estos usuarios en sus <ProfileLink>páginas de perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Puedes ver un resumen de tus límites de peticiones en tu <ProfileLink>página de perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"No te quedan suficientes solicitudes de temporadas restantes\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {película} other {películas}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"película\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Este usuario tiene permitido <strong>{limit}</strong> {type} cada <strong>{days}</strong> días.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Se te permite pedir <strong>{limit}</strong> {type} cada <strong>{days}</strong> días.\",\n  \"components.QuotaSelector.unlimited\": \"Ilimitadas\",\n  \"components.MovieDetails.originaltitle\": \"Título Original\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Todos los Idiomas\",\n  \"components.LanguageSelector.languageServerDefault\": \"({Language}) por defecto\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {cambio} other {cambios}} por detrás\",\n  \"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.\",\n  \"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\\\"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Debes introducir una clave pública PGP valida\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"¡Ajustes de notificaciones de Telegram guardados correctamente!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Error al guardar los ajustes de notificaciones de Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Encriptar mensajes por email usando <OpenPgpLink>OpenPGP2</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Clave Pública PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"¡Ajustes de notificación por email guardados correctamente!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Error al guardar los ajustes de notificaciones por email.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"¡Los ajustes de notificaciones de Discord se han guardado correctamente!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"No se han podido guardar los ajustes de notificaciones de Discord.\",\n  \"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 administradores podrán modificar el servidor usado al procesar nuevas solicitudes antes de su aprobación.\",\n  \"components.Settings.mediaTypeMovie\": \"película\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Probar conexión para cargar etiquetas\",\n  \"components.Settings.SonarrModal.tags\": \"Etiquetas\",\n  \"components.Settings.SonarrModal.selecttags\": \"Seleccionar etiquetas\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Sin etiquetas.\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Cargando etiquetas…\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Modificar servidor 4K Sonarr\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Servidor 4K por defecto\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Añadir nuevo servidor Sonarr 4K\",\n  \"components.Settings.SonarrModal.animeTags\": \"Etiquetas Anime\",\n  \"components.Settings.noDefaultServer\": \"Al menos un servidor {serverType} debe marcarse como por defecto para que las solicitudes de {mediaType} sean procesadas.\",\n  \"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} <strong>NO</strong> debería marcarse como un servidor 4k.\",\n  \"components.Settings.mediaTypeSeries\": \"serie\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Actualizado\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Desactualizado\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Probar conexión para cargar etiquetas\",\n  \"components.Settings.RadarrModal.tags\": \"Etiquetas\",\n  \"components.Settings.RadarrModal.selecttags\": \"Seleccionar etiquetas\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Sin etiquetas.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Cargando etiquetas…\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Modificar servidor Radarr 4K\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Servidor 4K por defecto\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Añadir un nuevo servidor Radarr 4K\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Debes indicar una clave privada PGP\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Debes indicar una contraseña PGP\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Permite a los usuarios iniciar también un chat con tu bot y configurar sus propias notificaciones\",\n  \"components.RequestModal.pendingapproval\": \"Tu solicitud está pendiente de aprobación.\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Etiquetas\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Seleccionar etiquetas\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Sin etiquetas.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} No Encontrado\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Borrar Solicitud\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Cancelar Solicitud\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} No Encontrado\",\n  \"components.RequestCard.deleterequest\": \"Borrar Solicitud\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Tipos de Notificación\",\n  \"components.Layout.VersionStatus.streamstable\": \"Overseer (Estable)\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Overseer (Desarrollo)\",\n  \"components.Layout.VersionStatus.outofdate\": \"Desactualizado\",\n  \"components.UserList.autogeneratepasswordTip\": \"Envía por email una contraseña al usuario generada por el servidor\",\n  \"i18n.retrying\": \"Reintentando…\",\n  \"components.Settings.serverSecure\": \"seguro\",\n  \"components.UserList.usercreatedfailedexisting\": \"La dirección de email proporcionada ya está en uso por otro usuario.\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Habilitar Búsqueda Automática\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Habilitar Búsqueda Automática\",\n  \"components.RequestModal.edit\": \"Editar Solicitud\",\n  \"components.RequestList.RequestItem.editrequest\": \"Editar Solicitud\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Mostrar Idioma\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Settings.noDefault4kServer\": \"Un servidor 4K de {serverType} debe ser marcado por defecto para poder habilitar las solicitudes 4K de {mediaType} de los usuarios.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Habilitar inicio de sesión de usuarios de Plex sin importarse previamente\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Habilitar nuevo inicio de sesión de Plex\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"¡Notificación de Telegram enviada con éxito!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Enviando notificación de prueba de Telegram…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Fallo al enviar notificación de prueba de Telegram.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"¡Notificación por Email de prueba enviada!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Enviando notificación de prueba por Email…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Fallo al enviar la notificación de prueba por Email.\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"¡Notificación de prueba enviada de Discord!\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Enviando notificación de prueba de Discord…\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Fallo al enviar notificación de prueba de Discord.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"¡Notificación de prueba de Webhook enviada!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Enviando notificación de prueba de Webhook…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Fallo al enviar la notificación de prueba de Webhook.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"¡Ajustes de notificación de Web Push guardados con éxito!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Fallo al guardar los ajustes de notificación de Web Push.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"¡Notificación de prueba de Web Push enviada!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Enviando notificación de prueba de Web Push…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Fallo al enviar la notificación de prueba de Web Push.\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Habilitar Agente\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"¡Notificación de prueba de Slack enviada!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Enviando notificación de prueba de Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Fallo al enviar la notificación de prueba de Slack.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"¡Notificación de prueba de Pushover enviada!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Enviando notificación de prueba de Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Fallo al enviar la notificación de prueba de Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"¡Notificación de prueba de Pushbullet enviada!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Enviando notificación de prueba de Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Fallo al enviar notificación de prueba de Pushbullet.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Conceder permisos para solicitar series que no sean 4k.\",\n  \"components.PermissionEdit.requestTv\": \"Solicitar Series\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Conceder permisos para solicitar películas que no sean 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Solicitar películas\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Solicitado\",\n  \"components.RequestCard.failedretry\": \"Algo fue mal al reintentar la solicitud.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Notificar cuando otros usuarios envíen nuevas solicitudes que requieran aprobación.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Notificar cuando las solicitudes de contenido fallen al añadirse a Radarr o Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Notificar cuando tus contenidos solicitados sean rechazados.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Notificar cuando tus contenidos solicitados estén disponibles.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Notificar cuando las solicitudes sean aprobadas.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Notificar cuando otros usuarios envíen nuevas solicitudes que se aprueben automáticamente.\",\n  \"components.MovieDetails.showmore\": \"Mostrar más\",\n  \"components.MovieDetails.showless\": \"Mostrar menos\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Mostrar idioma\",\n  \"components.DownloadBlock.estimatedtime\": \"Estimación de {time}\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Usa siempre STARTTLS\",\n  \"components.TvDetails.streamingproviders\": \"Emisión Actual en\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"{{Language}} por defecto\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Para recibir notificaciones web push, Jellyseerr debe servirse mediante HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.Settings.Notifications.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Permite a los usuarios registrarse consumo email y password, en lugar de la OAuth de Plex\",\n  \"components.Settings.webAppUrl\": \"Url de la <WebAppLink>Web App</WebAppLink>\",\n  \"components.Settings.Notifications.encryption\": \"Método de Encriptación\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Usa STARTTLS si está disponible\",\n  \"components.Settings.Notifications.encryptionNone\": \"Ninguna\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Crea un token desde tu <PushbulletSettingsLink>Opciones de Cuenta</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registrar una aplicación</ApplicationRegistrationLink> para su uso con Jellyseerr\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Tu <UsersGroupsLink>identificador de usuario o grupo</UsersGroupsLink> de 30 caracteres\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {temporada} other {temporadas}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {película} other {películas}}\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Debes seleccionar, al menos, un tipo de notificación\",\n  \"components.Settings.Notifications.chatIdTip\": \"Empieza un chat con tu bot, añade el <GetIdBotLink>@get_id_bot</GetIdBotLink> e indica el comando <code>/my_id</code>\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Usa TLS Implícito\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Crea una <DiscordWebhookLink>integración webhook</DiscordWebhookLink> en tu servidor\",\n  \"components.MovieDetails.streamingproviders\": \"Emisión Actual en\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{películas} per {quotaDays} {días}</quotaUnits>\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Crea una integración con un <WebhookLink>Webhook de Entrada</WebhookLink>\",\n  \"components.Settings.webAppUrlTip\": \"Dirige a los usuarios, opcionalmente, a la web app en tu servidor, en lugar de la app alojada en Plex\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {día} other {días}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{temporadas} per {quotaDays} {días}</quotaUnits>\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Crea un bot</CreateBotLink> para usar con Jellyseerr\",\n  \"components.Settings.Notifications.encryptionTip\": \"Normalmente, TLS Implícito usa el puerto 465 y STARTTLS usa el puerto 587\",\n  \"components.UserList.localLoginDisabled\": \"El ajuste para <strong>Habilitar el Inicio de Sesión Local</strong> está actualmente deshabilitado.\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Permisos iniciales asignados a nuevos usuarios\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Estás utilizando la rama de <code>develop</code> de Jellyseerr, la cual solo se recomienda para aquellos que contribuyen al desarrollo o al soporte de las pruebas de nuevos desarrollos.\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Cada {jobScheduleMinutes, plural, one {minuto} other {{jobScheduleMinutes} minutos}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Cada {jobScheduleHours, plural, one {hora} other {{jobScheduleHours} horas}}\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Algo fue mal al guardar la tarea programada.\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modificar tarea programada\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Nueva frecuencia\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"¡Tarea programada modificada con éxito!\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"¿Estás seguro de querer borrar este comentario?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Borrar Comentario\",\n  \"components.IssueDetails.IssueComment.edit\": \"Modificar Comentario\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Escrito por {username} el {relativeTime}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Escrito por {username} el {relativeTime} (Modificado)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Debes introducir un mensaje\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Borrar Incidencia\",\n  \"components.IssueDetails.IssueDescription.description\": \"Descripción\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Modificar Descripción\",\n  \"components.IssueDetails.allepisodes\": \"Todos los Episodios\",\n  \"components.IssueDetails.allseasons\": \"Todas las Temporadas\",\n  \"components.IssueDetails.closeissue\": \"Cerrar Incidencia\",\n  \"components.IssueDetails.closeissueandcomment\": \"Cerrar con Comentarios\",\n  \"components.IssueDetails.comments\": \"Comentarios\",\n  \"components.IssueDetails.deleteissue\": \"Borrar Incidencia\",\n  \"components.IssueDetails.deleteissueconfirm\": \"¿Estás seguro de querer borrar esta incidencia?\",\n  \"components.IssueDetails.episode\": \"Episodio {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Incidencia\",\n  \"components.IssueDetails.issuetype\": \"Tipo\",\n  \"components.IssueDetails.lastupdated\": \"Última Actualización\",\n  \"components.IssueDetails.leavecomment\": \"Commentario\",\n  \"components.IssueDetails.nocomments\": \"Sin comentarios.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} abierta {relativeTime} por {username}\",\n  \"components.IssueDetails.openin4karr\": \"Abrir en {arr} 4K\",\n  \"components.IssueDetails.openinarr\": \"Abierta en {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Ver en 4K en {mediaServerName}\",\n  \"components.IssueDetails.playonplex\": \"Ver en {mediaServerName}\",\n  \"components.IssueDetails.problemepisode\": \"Episodio Afectado\",\n  \"components.IssueDetails.problemseason\": \"Temporada Afectada\",\n  \"components.IssueDetails.reopenissue\": \"Reabrir Incidencia\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Reabrir con Comentarios\",\n  \"components.IssueDetails.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Algo fue mal mientras se modificaba la descripción de la incidencia.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"¡La descripción de la incidencia se ha modificado correctamente!\",\n  \"components.IssueDetails.toastissuedeleted\": \"¡Incidencia eliminada correctamente!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Algo fue mal mientras se eliminaba la incidencia.\",\n  \"components.IssueDetails.toaststatusupdated\": \"¡Estado de la incidencia actualizado con éxito!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Algo fue mal mientras se actualizaba el estado de la incidencia.\",\n  \"components.IssueDetails.unknownissuetype\": \"Desconocido\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Episodio} other {Episodios}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Estado\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tipo\",\n  \"components.IssueList.IssueItem.opened\": \"Abierta\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} por {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Episodio Afectado\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Desconocida\",\n  \"components.IssueList.IssueItem.viewissue\": \"Ver Incidencia\",\n  \"components.IssueList.issues\": \"Incidencias\",\n  \"components.IssueList.showallissues\": \"Mostrar Todas las Incidencias\",\n  \"components.IssueList.sortAdded\": \"Más Reciente\",\n  \"components.IssueList.sortModified\": \"Última Modificación\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Todos los Episodios\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Todas las Temporadas\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episodio {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extras\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Episodio Afectado\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Temporada Afectada\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Por favor envíe una explicación detallada de la incidencia encontrada.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Reportar Incidencia\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Enviar Incidencia\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Algo fue mal mientras se enviaba la incidencia.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"¡Incidencia reportada por <strong>{title}</strong> enviada con éxito!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Ver Incidencia\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Debes escribir una descripción\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"¿Qué sucede?\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueModal.issueOther\": \"Otro\",\n  \"components.IssueModal.issueSubtitles\": \"Subtítulo\",\n  \"components.IssueModal.issueVideo\": \"Vídeo\",\n  \"components.Layout.Sidebar.issues\": \"Incidencias\",\n  \"components.ManageSlideOver.downloadstatus\": \"Estado de la Descarga\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Limpiar Datos de los Contenidos\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Esto eliminará irreversiblemente todos los datos de {mediaType}, incluyendo todas las solicitudes. Si este elemento existe en la biblioteca de {mediaServerName}, la información de los contenidos se recreará en el siguiente escaneado.\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Incidencias Abiertas\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Sin solicitudes.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Solicitudes\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Gestionar {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Marcar como Disponible en 4K\",\n  \"components.ManageSlideOver.markavailable\": \"Marcar como Disponible\",\n  \"components.ManageSlideOver.movie\": \"película\",\n  \"components.ManageSlideOver.openarr\": \"Abrir en {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Abrir en 4K {arr}\",\n  \"components.ManageSlideOver.tvshow\": \"series\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Notificar cuando otros usuarios comenten incidencias.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Notificar cuando se reabran incidencias por otros usuarios.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Notificar cuando otros usuarios resuelvan incidencias.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Comentario de Incidencia\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Envía notificaciones cuando las incidencias reciben nuevos comentarios.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Incidencia Reportada\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Enviar notificaciones cuando las incidencias sean reportadas.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Incidencia Reabierta\",\n  \"i18n.import\": \"Importar\",\n  \"i18n.importing\": \"Importando…\",\n  \"components.MovieDetails.digitalrelease\": \"Lanzamiento Digital\",\n  \"components.MovieDetails.physicalrelease\": \"Lanzamiento Físico\",\n  \"components.MovieDetails.theatricalrelease\": \"Lanzamiento en cines\",\n  \"components.IssueDetails.commentplaceholder\": \"Añadir un comentario…\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Marcar Todas las Temporadas como Disponible en 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Marcar Todas las Temporadas como Disponible\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatometer de Rotten Tomatoes\",\n  \"components.MovieDetails.rtaudiencescore\": \"Puntuación audiencia de Rotten Tomatoes\",\n  \"components.Discover.plexwatchlist\": \"Tu Lista de Visualización de Plex\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Tu lista de seguimiento de Plex\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Contenido\",\n  \"components.MovieDetails.managemovie\": \"Administrar Película\",\n  \"components.MovieDetails.reportissue\": \"Reportar una Incidencia\",\n  \"components.AirDateBadge.airedrelative\": \"Emitido {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Emitiendo {relativeTime}\",\n  \"components.ManageSlideOver.pastdays\": \"Últimos {days, number} Días\",\n  \"components.Discover.CreateSlider.addSlider\": \"Crear deslizador\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Crear deslizador personalizado\",\n  \"components.Discover.CreateSlider.addfail\": \"Error al crear deslizador nuevo.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Nuevo deslizador creado y guardado de los ajustes personalizados.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Modificar deslizador\",\n  \"components.Discover.CreateSlider.editfail\": \"Fallo al editar deslizador.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Sin resultados.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Proporcione un ID de categoría de TMDB\",\n  \"components.Discover.CreateSlider.needresults\": \"Necesita tener al menos un resultado en la búsqueda.\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Proporcione una ID de TMDB de la palabra clave\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Deslizador editado y ajustes personalizados guardados.\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Proporcione una consulta a buscar\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Buscar categorías…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Buscar palabras clave…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Buscar estudios…\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Proporcione la ID de TMDB del estudio\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Proporcione la ID de TMDB de la cadena\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Nombre del deslizador\",\n  \"components.Discover.CreateSlider.starttyping\": \"Escriba para buscar.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Debe proporcionar un valor.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Películas\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Debe proporcionar un título.\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Error al borrar deslizador.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Deslizador eliminado con éxito.\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Borrar\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Alternar Visibilidad\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Contenido añadido a tu <PlexWatchlistSupportLink> lista de visualización de Plex </PlexWatchlistSupportLink> aparecerá aquí.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Vista de Visualización de Plex\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Series\",\n  \"components.Discover.createnewslider\": \"Crear Nuevo Deslizador\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Añadido Recientemente\",\n  \"components.Discover.moviegenres\": \"Géneros de Películas\",\n  \"components.Discover.networks\": \"Cadenas\",\n  \"components.Discover.emptywatchlist\": \"Contenido añadido a tu <PlexWatchlistSupportLink> lista de visualización de Plex </PlexWatchlistSupportLink> aparecerá aquí.\",\n  \"components.Discover.resettodefault\": \"Restablecer valores Predeterminados\",\n  \"components.Discover.resetwarning\": \"Restablecer todos los deslizadores por defecto. ¡Esto también borrará los deslizadores personalizados!\",\n  \"components.Discover.resetfailed\": \"Algo falló restableciendo los ajustes personalizados de recomendaciones.\",\n  \"components.Discover.resetsuccess\": \"Se ha restablecido correctamente la configuración de personalización de Descubrir.\",\n  \"components.Discover.stopediting\": \"Dejar de Editar\",\n  \"components.Discover.tmdbmoviegenre\": \"Género de películas TMDB\",\n  \"components.Discover.tmdbmoviekeyword\": \"Palabras clave de la película de TMDB\",\n  \"components.Discover.tmdbnetwork\": \"Cadena TMDB\",\n  \"components.Discover.studios\": \"Estudios\",\n  \"components.Discover.tvgenres\": \"Géneros de Series\",\n  \"components.Discover.tmdbsearch\": \"Búsqueda TMDB\",\n  \"components.Discover.tmdbstudio\": \"Estudio TMDB\",\n  \"components.Discover.tmdbtvgenre\": \"Género de Series TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Palabra clave de Series TMDB\",\n  \"components.Discover.updatefailed\": \"Algo falló al actualizar las opciones personalizadas de recomendaciones.\",\n  \"components.Discover.updatesuccess\": \"Opciones personalizadas de recomendaciones actualizadas.\",\n  \"components.ManageSlideOver.opentautulli\": \"Abrir en Tautulli\",\n  \"components.ManageSlideOver.playedby\": \"Reproducido Por\",\n  \"components.MovieDetails.tmdbuserscore\": \"Puntuación de usuario de TMDB\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Películas\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularidad Ascendente\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularidad descendente\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Fecha de salida Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Título (A-Z) Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Título (Z-A) Descendente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Ratio TMDB Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Ratio TMDB Descendente\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Fecha de salida Descendente\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularidad Ascendente\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularidad Descendente\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Título (A-Z) Ascendente\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Título (Z-A) Descendente\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Series\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Puntuación TMDB Ascendente\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Fecha de Primera Emisión Ascendente\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Fecha de Primera Emisión Descendente\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Puntuación TMDB Descendente\",\n  \"components.Discover.FilterSlideover.keywords\": \"Palabras claves\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtros\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Limpiar Filtros Activos\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Primera Fecha de Emisión\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Idioma Original\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Fecha de Publicación\",\n  \"components.Discover.FilterSlideover.studio\": \"Estudio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Puntuación de Usuarios de TMDB\",\n  \"components.Discover.FilterSlideover.to\": \"A\",\n  \"components.Discover.FilterSlideover.from\": \"Desde\",\n  \"components.Discover.FilterSlideover.genres\": \"Géneros\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Puntuaciones entre {minValue} y {maxValue}\",\n  \"components.Discover.customizediscover\": \"Personalizar Descubre\",\n  \"components.Layout.Sidebar.browsetv\": \"Series\",\n  \"components.Layout.Sidebar.browsemovies\": \"Películas\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Peticiones de Películas\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avanzado\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Contenido 4K\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Temporada {seasonNumber} Episodio {episodeNumber}\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Peticiones de Series\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Petición Enviada Automáticamente\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Lista de seguimiento Plex\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Servicios de Streaming\",\n  \"components.Layout.UserDropdown.requests\": \"Peticiones\",\n  \"components.TvDetails.reportissue\": \"Informar de un problema\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomatómetro de Rotten Tomatoes\",\n  \"components.TvDetails.seasonstitle\": \"Temporadas\",\n  \"components.TvDetails.tmdbuserscore\": \"Puntuación de Usuarios de TMDB\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Debe seleccionar al menos un tipo de notificación\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Reciba notificaciones cuando se envíen nuevas solicitudes de contenido para elementos de su lista de seguimiento de Plex.\",\n  \"components.PermissionEdit.autorequestDescription\": \"Conceder permiso para enviar solicitudes de medios que no sean 4K a través de Plex Watchlist.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Solicitar Películas automáticamente\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} Duración en minutos\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Conceder permiso para ver las listas de seguimiento de Plex de otros usuarios.\",\n  \"components.RequestBlock.decline\": \"Rechazar solicitud\",\n  \"components.RequestBlock.lastmodifiedby\": \"Última Modificación Por\",\n  \"components.RequestBlock.requestdate\": \"Fecha de Solicitud\",\n  \"components.RequestCard.declinerequest\": \"Rechazar Solicitud\",\n  \"components.RequestCard.tvdbid\": \"Identificador de TheTVDB\",\n  \"components.RequestModal.requestseries4ktitle\": \"Solicitar Serie en 4K\",\n  \"components.RequestModal.requestseasons4k\": \"Solicitar {seasonCount} {seasonCount, plural, one {Season} other {Seasons}} en 4K\",\n  \"components.RequestModal.selectmovies\": \"Seleccionar Película(s)\",\n  \"components.Selector.showmore\": \"Mostrar más\",\n  \"components.Selector.searchStudios\": \"Buscar estudios…\",\n  \"components.Selector.nooptions\": \"Sin resultados.\",\n  \"components.Selector.searchKeywords\": \"Buscar palabras clave…\",\n  \"components.Selector.showless\": \"Ver menos\",\n  \"components.Selector.searchGenres\": \"Seleccionar géneros…\",\n  \"components.Selector.starttyping\": \"Escriba para buscar.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"La URL no debe terminar con una barra al final\",\n  \"components.Settings.Notifications.enableMentions\": \"Activar menciones\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Frecuencia actual\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Tamaño total de la caché\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Imágenes en caché\",\n  \"components.Settings.SettingsMain.general\": \"General\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Configuración general\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Ocultar Contenido disponible\",\n  \"components.StatusBadge.managemedia\": \"Gestionar {mediaType}\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Configure los ajustes globales y por defecto de Jellyseerr.\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Algo ha ido mal al guardar los ajustes.\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Debe proporcionar una URL válida\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Debe proporcionar un título de solicitud\",\n  \"components.Settings.tautulliApiKey\": \"Clave API\",\n  \"components.StatusBadge.openinarr\": \"Abrir en {arr}\",\n  \"components.StatusBadge.playonplex\": \"Ver en Plex\",\n  \"components.StatusChecker.reloadApp\": \"Recargar {applicationTitle}\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} No Encontrado\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Algo ha ido mal al obtener los datos de la temporada.\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Episodio} other {# Episodios}}\",\n  \"components.TvDetails.rtaudiencescore\": \"Puntuación audiencia de Rotten Tomatoes\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"El <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> asociado a su cuenta de usuario de Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Solicitar Películas automáticamente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Solicite películas automáticamente en su <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Solicite series automáticamente series en su <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.emptywatchlist\": \"Los medios añadidos a su <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> aparecerán aquí.\",\n  \"components.UserProfile.plexwatchlist\": \"Lista de seguimiento Plex\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Filtro Activo} other {# Filtros Activos}}\",\n  \"components.MovieDetails.productioncountries\": \"Producción {countryCount, plural, one {País} other {Países}}\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Cuando está habilitado en la configuración, Jellyseerr obtendrá y almacenará en caché imágenes de fuentes externas preconfiguradas. Las imágenes almacenadas en caché se guardan en la carpeta de configuración. Puede encontrar los archivos en <code>{appDataPath}/cache/images</code>.\",\n  \"components.PermissionEdit.autorequest\": \"Auto solicitar\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Conceder permiso para enviar solicitudes de películas que no sean 4K a través de Plex Watchlist.\",\n  \"components.RequestBlock.approve\": \"Aprobar solicitud\",\n  \"components.RequestCard.approverequest\": \"Aprobar Solicitud\",\n  \"components.RequestCard.cancelrequest\": \"Cancelar Solicitud\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Conceder permiso para enviar solicitudes de series que no sean 4K a través de Plex Watchlist.\",\n  \"components.RequestCard.editrequest\": \"Editar Solicitud\",\n  \"components.RequestBlock.delete\": \"Eliminar solicitud\",\n  \"components.RequestBlock.edit\": \"Editar solicitud\",\n  \"components.RequestBlock.requestedby\": \"Solicitado Por\",\n  \"components.RequestCard.unknowntitle\": \"Título Desconocido\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Título Desconocido\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"No se ha podido encontrar ninguna coincidencia para esta serie.\",\n  \"components.RequestModal.requestseriestitle\": \"Solicitar Serie\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Solicitar Película en 4K\",\n  \"components.RequestModal.approve\": \"Aprobar Solicitud\",\n  \"components.RequestModal.requestApproved\": \"¡Solicitud de <strong>{title}</strong> aprobada!\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Solicitar Colección en 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Solicitar Colección\",\n  \"components.RequestModal.requestmovietitle\": \"Solicitar Película\",\n  \"components.Settings.urlBase\": \"Base URL\",\n  \"components.Settings.validationUrl\": \"Debe proporcionar una URL válida\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Haga clic en el botón de abajo para recargar la aplicación.\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Reinicie el servidor para aplicar la configuración actualizada.\",\n  \"components.TitleCard.cleardata\": \"Limpiar Datos\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID de usuario de Discord\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"No se ha podido enviar la notificación de prueba de Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Enviando notificación de prueba de Gotify…\",\n  \"components.StatusChecker.restartRequired\": \"Es necesario reiniciar el servidor\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"¡La configuración de notificaciones de Gotify se ha guardado correctamente!\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL del servidor\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Debe proporcionar un token de aplicación\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Debe proporcionar una URL válida\",\n  \"components.Settings.RadarrModal.released\": \"Publicado\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Concede permiso para ver la lista de contenidos añadidos recientemente.\",\n  \"components.PermissionEdit.viewrecent\": \"Ver recientemente añadido\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Algo salió mal al guardar la configuración de Tautulli.\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"La base de la URL debe tener una barra al principio\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Actualizado\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Ver detalles\",\n  \"components.Settings.SettingsMain.apikey\": \"Clave API\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL de la aplicación\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Activar el caché de imágenes\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Idioma en Descubre\",\n  \"components.Settings.SettingsMain.locale\": \"Idioma de visualización\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrar contenidos por idioma original\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Permitir Solicitudes Parciales de Series\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Algo ha ido mal al generar una nueva clave API.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"¡Nueva clave API generada con éxito!\",\n  \"components.Settings.advancedTooltip\": \"Una configuración incorrecta de este parámetro puede afectar a la funcionalidad\",\n  \"components.Settings.restartrequiredTooltip\": \"Jellyseerr debe reiniciarse para que los cambios en esta configuración surtan efecto\",\n  \"components.TvDetails.seasonnumber\": \"Temporada {seasonNumber}\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.UserList.newplexsigninenabled\": \"El ajuste <strong>Enable New Plex Sign-In</strong> está actualmente activado. Los usuarios de Plex con acceso a la biblioteca no necesitan ser importados para abrir sesión.\",\n  \"components.ManageSlideOver.alltime\": \"Tiempo total\",\n  \"components.RequestModal.requestmovies\": \"Solicitar {count} {count, plugarl, one {Película} other {Películas}}\",\n  \"components.Settings.tautulliSettings\": \"Configuración de Tautulli\",\n  \"components.Settings.validationUrlTrailingSlash\": \"La URL no debe terminar con una barra al final\",\n  \"components.PermissionEdit.autorequestSeries\": \"Solicitar series automáticamente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Solicitar series automáticamente\",\n  \"components.PermissionEdit.viewwatchlists\": \"Ver listas de seguimiento de Plex\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Etiqueta de canal\",\n  \"components.RequestBlock.languageprofile\": \"Perfil lingüístico\",\n  \"components.RequestModal.requestmovies4k\": \"Solicitar {count} {count, plugarl, one {Película} other {Películas}} en 4K\",\n  \"components.Settings.RadarrModal.inCinemas\": \"En Cines\",\n  \"components.UserProfile.recentlywatched\": \"Vistos recientemente\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Habilitar agente\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"No se han guardado los ajustes de notificación de Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"¡Notificación de prueba de Gotify enviada!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token de aplicación\",\n  \"components.TvDetails.manageseries\": \"Gestionar Series\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Directorio de datos\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Filtro Activo} other {# Filtros Activos}}\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Filtro Activo} other {# Filtros Activos}}\",\n  \"components.Discover.FilterSlideover.runtime\": \"Duración\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {reproducir} other {reproducir}}\",\n  \"components.Settings.RadarrModal.announced\": \"Anunciado\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Sincronización de la lista de seguimiento de Plex\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Titulo de la aplicación\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Almacenamiento en caché de imágenes de origen externo (requiere una cantidad significativa de espacio en disco)\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"¡Ajustes guardados correctamente!\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"La URL no debe terminar con una barra al final\",\n  \"components.Settings.tautulliSettingsDescription\": \"Opcionalmente configure los ajustes para su servidor Tautulli. Jellyseerr obtiene de Tautulli los datos del historial de visionado de los medios de Plex.\",\n  \"components.TitleCard.tvdbid\": \"Identificador de TheTVDB\",\n  \"components.TvDetails.Season.noepisodes\": \"Lista de episodios no disponible.\",\n  \"components.TvDetails.productioncountries\": \"Producción {countryCount, plural, one {País} other {Países}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Debe proporcionar un ID de Discord válido\",\n  \"i18n.restartRequired\": \"Reinicio necesario\",\n  \"components.Settings.deleteServer\": \"Eliminar servidor {serverType}\",\n  \"components.Settings.experimentalTooltip\": \"Activar esta opción puede provocar un comportamiento inesperado de la aplicación\",\n  \"components.Settings.externalUrl\": \"URL externa\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"¡Configuración de Tautulli guardada con éxito!\",\n  \"components.Settings.validationApiKey\": \"Debe proporcionar una clave API\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"La base de la URL no debe terminar en una barra al final\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"Identificador de TheTVDB\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Limpieza de la caché de imágenes\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Caché de imágenes\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Cada {jobScheduleSeconds, plural, one {segundo} other {{jobScheduleSeconds} segundos}}\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Sincronización de la disponibilidad de medios\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Servicios de streaming de películas TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Servicios de TV en streaming TMDB\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Recuento de votos de los usuarios de TMDB\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Número de votos entre {minValue} y {maxValue}\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Solicitudes de etiquetas\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Solicitudes de etiquetas\",\n  \"i18n.collection\": \"Colección\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.imdbuserscore\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.issueresolved\": \"\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"\",\n  \"components.PermissionEdit.createissues\": \"\",\n  \"components.PermissionEdit.createissuesDescription\": \"\",\n  \"components.PermissionEdit.manageissues\": \"\",\n  \"components.PermissionEdit.manageissuesDescription\": \"\",\n  \"components.PermissionEdit.viewissues\": \"\",\n  \"components.PermissionEdit.viewissuesDescription\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.open\": \"\",\n  \"i18n.resolved\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/et.json",
    "content": "{\n  \"component.BlocklistBlock.blocklistdate\": \"Musta nimekirja lisamise kuupäev\",\n  \"component.BlocklistBlock.blocklistedby\": \"Lisaja\",\n  \"component.BlocklistModal.blocklisting\": \"Musta nimekirja lisamine\",\n  \"components.AirDateBadge.airedrelative\": \"Eetris olnud {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Eetris {relativeTime}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code> andmekogu (volume mount) ei ole korrektselt seadistatud. Kõik andmed kustutatakse, kui konteiner peatatakse või taaskäivitatakse.\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> ei ole mustas nimekirjas.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Halda mustas nimekirjas olevat meediat.\",\n  \"components.Blocklist.blocklistdate\": \"kuupäev\",\n  \"components.Blocklist.blocklistedby\": \"{date}, lisas {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Musta nimekirja seaded\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Blokeeritud sildid\",\n  \"components.Blocklist.filterManual\": \"Käsitsi\",\n  \"components.Blocklist.mediaName\": \"Nimi\",\n  \"components.Blocklist.mediaTmdbId\": \"tmbd Id\",\n  \"components.Blocklist.mediaType\": \"Tüüp\",\n  \"components.Blocklist.showAllBlocklisted\": \"Näita kogu blokeeritud meediat\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} filmi\",\n  \"components.CollectionDetails.overview\": \"Ülevaade\",\n  \"components.CollectionDetails.requestcollection\": \"Taotle kogumikku\",\n  \"components.CollectionDetails.requestcollection4k\": \"Taotle kogumikku 4K-s\",\n  \"components.Discover.CreateSlider.addSlider\": \"Lisa liugur\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Loo kohandatud liugur\",\n  \"components.Discover.CreateSlider.addfail\": \"Uue liuguri loomine ebaõnnestus.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Uus liugur on loodud ja avastamise seaded salvestatud.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Muuda liugurit\",\n  \"components.Discover.CreateSlider.editfail\": \"Liuguri muutmine ebaõnnestus.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Liugur on muudetud ja avastamise seaded salvestatud.\",\n  \"components.Discover.CreateSlider.needresults\": \"Vaja on vähemalt ühte tulemust.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Tulemusi pole.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Sisesta TMDB žanri ID\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Sisesta TMDB märksõna ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Sisesta TMDB võrgustiku ID\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Sisesta otsingupäring\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Sisesta TMDB stuudio ID\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Otsi žanre…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Otsi märksõnu…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Otsi stuudioid…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Liuguri nimi\",\n  \"components.Discover.CreateSlider.starttyping\": \"Alusta kirjutamist, et otsida.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Andmeväärtus on kohustuslik.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Pealkiri on kohustuslik.\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} Filmid\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Filmid\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Filmid\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Aktiivne Filter} other {# Aktiivset Filtrit}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmid\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Populaarsus kasvavalt\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Populaarsus kahanevalt\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Väljalaskekuupäev kasvavalt\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Väljalaskekuupäev kahanevalt\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Pealkiri (A–Z)\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Pealkiri (Z–A)\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB hinne kasvavalt\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB hinne kahanevalt\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} Sarjad\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Liuguri kustutamine ebaõnnestus.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Liugur on edukalt kustutatud.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Lülita nähtavust\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Eemalda\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} Filmid\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Aktiivne Filter} other {# Aktiivset Filtrit}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Sarjad\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Esmaeetrisse minek kasvavalt\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Esmaeetrisse minek kahanevalt\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Populaarsus kasvavalt\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Populaarsus kahanevalt\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Pealkiri (A–Z)\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Pealkiri (Z–A)\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB hinne kasvavalt\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB hinne kahanevalt\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Sarjad\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Sarjad\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Sarjad\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Sinu soovinimekiri\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plexi soovinimekiri\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Aktiivne Filter} other {# Aktiivset Filtrit}}\",\n  \"components.Discover.FilterSlideover.certification\": \"Vanusepiirang\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Tühjenda filtrid\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Välista märksõnad\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtrid\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Esmaeeter\",\n  \"components.Discover.FilterSlideover.from\": \"Alates\",\n  \"components.Discover.FilterSlideover.genres\": \"Žanrid\",\n  \"components.Discover.FilterSlideover.keywords\": \"Märksõnad\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Originaalkeel\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Hinnang vahemikus {minValue} kuni {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Väljalaskekuupäev\",\n  \"components.Discover.FilterSlideover.runtime\": \"Kestus\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"Kestus {minValue}–{maxValue} minutit\",\n  \"components.Discover.FilterSlideover.status\": \"Staatus\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Striimimisteenused\",\n  \"components.Discover.FilterSlideover.studio\": \"Stuudio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB kasutajate hinne\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB häälte arv\",\n  \"components.Discover.FilterSlideover.to\": \"Kuni\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Häälte arv vahemikus {minValue} kuni {maxValue}\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Filmide žanrid\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Filmide žanrid\",\n  \"components.Discover.NetworkSlider.networks\": \"Võrgustikud\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Sinu <PlexWatchlistSupportLink>Plexi soovinimekirja</PlexWatchlistSupportLink> lisatud meedia ilmub siia.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Sinu soovinimekiri\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Viimati lisatud\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Ühenduse loomine teenusega {services} ebaõnnestus. Osa infot võib olla puudu.\",\n  \"components.Discover.StudioSlider.studios\": \"Stuudiod\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Sarjade žanrid\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Sarjade žanrid\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Tulevased sarjad\",\n  \"components.Discover.createnewslider\": \"Loo uus liugur\",\n  \"components.Discover.customizediscover\": \"Kohanda avastamist\",\n  \"components.Discover.discover\": \"Avasta\",\n  \"components.Discover.emptywatchlist\": \"Sinu <PlexWatchlistSupportLink>Plexi soovinimekirja</PlexWatchlistSupportLink> lisatud meedia ilmub siia.\",\n  \"components.Discover.moviegenres\": \"Filmide žanrid\",\n  \"components.Discover.networks\": \"Võrgustikud\",\n  \"components.Discover.plexwatchlist\": \"Sinu soovinimekiri\",\n  \"components.Discover.popularmovies\": \"Populaarsed filmid\",\n  \"components.Discover.populartv\": \"Populaarsed sarjad\",\n  \"components.Discover.recentlyAdded\": \"Viimati lisatud\",\n  \"components.Discover.recentrequests\": \"Viimased taotlused\",\n  \"components.Discover.resetfailed\": \"Avastamise seadete lähtestamisel tekkis viga.\",\n  \"components.Discover.resetsuccess\": \"Avastamise seaded on edukalt lähtestatud.\",\n  \"components.Discover.resettodefault\": \"Lähtesta vaikeseaded\",\n  \"components.Discover.resetwarning\": \"See lähtestab kõik liugurid ja kustutab ka kohandatud liugurid!\",\n  \"components.Discover.stopediting\": \"Lõpeta muutmine\",\n  \"components.Discover.studios\": \"Stuudiod\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB filmi žanr\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB filmi märksõna\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB filmi striimimisteenused\",\n  \"components.Discover.tmdbnetwork\": \"TMDB võrgustik\",\n  \"components.Discover.tmdbsearch\": \"TMDB otsing\",\n  \"components.Discover.tmdbstudio\": \"TMDB stuudio\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB sarja žanr\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB sarja märksõna\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB sarja striimimisteenused\",\n  \"components.Discover.trending\": \"Trendikas\",\n  \"components.Discover.tvgenres\": \"Sarjade žanrid\",\n  \"components.Discover.upcoming\": \"Tulevased filmid\",\n  \"components.Discover.upcomingmovies\": \"Tulevased filmid\",\n  \"components.Discover.upcomingtv\": \"Tulevased sarjad\",\n  \"components.Discover.updatefailed\": \"Avastamise seadete uuendamisel tekkis viga.\",\n  \"components.Discover.updatesuccess\": \"Avastamise seaded on uuendatud.\",\n  \"components.DownloadBlock.estimatedtime\": \"Hinnanguline aeg: {time}\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: {seasonNumber}. hooaeg, {episodeNumber}. osa\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Kas oled kindel, et soovid selle kommentaari kustutada?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Kustuta kommentaar\",\n  \"components.IssueDetails.IssueComment.edit\": \"Muuda kommentaari\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Postitas {relativeTime} {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Postitas {relativeTime} {username} (muudetud)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Sõnum on kohustuslik\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Kustuta probleem\",\n  \"components.IssueDetails.IssueDescription.description\": \"Kirjeldus\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Muuda kirjeldust\",\n  \"components.IssueDetails.allepisodes\": \"Kõik osad\",\n  \"components.IssueDetails.allseasons\": \"Kõik hooajad\",\n  \"components.IssueDetails.closeissue\": \"Sulge probleem\",\n  \"components.IssueDetails.closeissueandcomment\": \"Sulge koos kommentaariga\",\n  \"components.IssueDetails.commentplaceholder\": \"Lisa kommentaar…\",\n  \"components.IssueDetails.comments\": \"Kommentaarid\",\n  \"components.IssueDetails.deleteissue\": \"Kustuta probleem\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Kas oled kindel, et soovid selle probleemi kustutada?\",\n  \"components.IssueDetails.episode\": \"Osa {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Probleem\",\n  \"components.IssueDetails.issuetype\": \"Tüüp\",\n  \"components.IssueDetails.lastupdated\": \"Viimati uuendatud\",\n  \"components.IssueDetails.leavecomment\": \"Kommenteeri\",\n  \"components.IssueDetails.nocomments\": \"Kommentaare pole.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} avas {relativeTime} {username}\",\n  \"components.IssueDetails.openin4karr\": \"Ava 4K {arr}-is\",\n  \"components.IssueDetails.openinarr\": \"Ava {arr}-is\",\n  \"components.IssueDetails.play4konplex\": \"Mängi 4K s serveris {mediaServerName}\",\n  \"components.IssueDetails.playonplex\": \"Mängi serveris {mediaServerName}\",\n  \"components.IssueDetails.problemepisode\": \"Mõjutatud osa\",\n  \"components.IssueDetails.problemseason\": \"Mõjutatud hooaeg\",\n  \"components.IssueDetails.reopenissue\": \"Ava probleem uuesti\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Ava uuesti koos kommentaariga\",\n  \"components.IssueDetails.season\": \"Hooaeg {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Probleemi kirjelduse muutmisel tekkis viga.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Probleemi kirjeldus on edukalt muudetud!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Probleem on edukalt kustutatud!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Probleemi kustutamisel tekkis viga.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Probleemi staatus on edukalt uuendatud!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Probleemi staatuse uuendamisel tekkis viga.\",\n  \"components.IssueDetails.unknownissuetype\": \"Tundmatu\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Probleemi kirjeldus\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Episood} other {Episoodi}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Staatus\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tüüp\",\n  \"components.IssueList.IssueItem.opened\": \"Avatud\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date}, avas {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Mõjutatud osa\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Hooaeg} other {Hooaega}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Tundmatu\",\n  \"components.IssueList.IssueItem.viewissue\": \"Vaata probleemi\",\n  \"components.IssueList.issues\": \"Probleemid\",\n  \"components.IssueList.showallissues\": \"Näita kõiki probleeme\",\n  \"components.IssueList.sortAdded\": \"Uusimad ees\",\n  \"components.IssueList.sortModified\": \"Viimati muudetud\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Kõik osad\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Kõik hooajad\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Osa {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Lisad\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Mõjutatud osa\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Mõjutatud hooaeg\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Palun kirjeldage üksikasjalikult esinenud probleemi.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Teata probleemist\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Hooaeg {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Esita probleem\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Probleemi esitamisel tekkis viga.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"<strong>{title}</strong> probleemiaruanne on edukalt esitatud!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Vaata probleemi\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Kirjeldus on kohustuslik\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Mis on valesti?\",\n  \"components.IssueModal.issueAudio\": \"Heli\",\n  \"components.IssueModal.issueOther\": \"Muu\",\n  \"components.IssueModal.issueSubtitles\": \"Subtiitrid\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.LanguageSelector.languageServerDefault\": \"Vaikimisi ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Kõik keeled\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Kasutajaliidese keel\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Otsi filme ja sarju\",\n  \"components.Layout.Sidebar.blocklist\": \"Must nimekiri\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmid\",\n  \"components.Layout.Sidebar.browsetv\": \"Sarjad\",\n  \"components.Layout.Sidebar.dashboard\": \"Avasta\",\n  \"components.Layout.Sidebar.issues\": \"Probleemid\",\n  \"components.Layout.Sidebar.requests\": \"Taotlused\",\n  \"components.Layout.Sidebar.settings\": \"Seaded\",\n  \"components.Layout.Sidebar.users\": \"Kasutajad\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Filmi taotlused\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Sarja taotlused\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profiil\",\n  \"components.Layout.UserDropdown.requests\": \"Taotlused\",\n  \"components.Layout.UserDropdown.settings\": \"Seaded\",\n  \"components.Layout.UserDropdown.signout\": \"Logi välja\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"E-posti aadress on vigane.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"E-posti aadress on kohustuslik.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Parool on kohustuslik.\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {muudatus} other {muudatust}} maas\",\n  \"components.Layout.VersionStatus.outofdate\": \"Aegunud\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr arendusversioon\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr stabiilne\",\n  \"components.Login.adminerror\": \"Sisselogimiseks peate kasutama administraatori kontot.\",\n  \"components.Login.back\": \"Mine tagasi\",\n  \"components.Login.credentialerror\": \"Kasutajanimi või parool on vale.\",\n  \"components.Login.description\": \"Kuna see on teie esimene sisselogimine rakendusse {applicationName}, peate lisama kehtiva e-posti aadressi.\",\n  \"components.Login.email\": \"E-posti aadress\",\n  \"components.Login.emailtooltip\": \"Aadress ei pea olema seotud teie {mediaServerName} serveriga.\",\n  \"components.Login.enablessl\": \"Kasuta SSL-i\",\n  \"components.Login.forgotpassword\": \"Unustasid parooli?\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.initialsignin\": \"Ühenda\",\n  \"components.Login.initialsigningin\": \"\\\"Ühendamine…\",\n  \"components.Login.invalidurlerror\": \"Ühenduse loomine {mediaServerName} serveriga ebaõnnestus.\",\n  \"components.Login.loginerror\": \"Sisselogimisel tekkis viga.\",\n  \"components.Login.loginwithapp\": \"Logi sisse teenusega {appName}\",\n  \"components.Login.noadminerror\": \"Serverist ei leitud ühtegi administraatorit.\",\n  \"components.Login.orsigninwith\": \"Või logi sisse järgnevaga\",\n  \"components.Login.password\": \"Parool\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.save\": \"Lisa\",\n  \"components.Login.saving\": \"Lisamine…\",\n  \"components.Login.servertype\": \"Serveri tüüp\",\n  \"components.Login.signin\": \"Logi sisse\",\n  \"components.Login.signingin\": \"Sisselogimine…\",\n  \"components.Login.signinheader\": \"Jätkamiseks logi sisse\",\n  \"components.Login.signinwithjellyfin\": \"Kasuta oma {mediaServerName} kontot\",\n  \"components.Login.signinwithoverseerr\": \"Kasuta oma {applicationTitle} kontot\",\n  \"components.Login.signinwithplex\": \"Kasuta oma Plexi kontot\",\n  \"components.Login.title\": \"Lisa e-post\",\n  \"components.Login.urlBase\": \"URL-i baas\",\n  \"components.Login.username\": \"Kasutajanimi\",\n  \"components.Login.validationEmailFormat\": \"Vigane e-post\",\n  \"components.Login.validationEmailRequired\": \"E-post on kohustuslik\",\n  \"components.Login.validationPortRequired\": \"Sisesta kehtiv pordi number\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"URL-i baas peab algama kaldkriipsuga\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"…URL-i baas ei tohi lõppeda kaldkriipsuga\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL ei tohi lõppeda kaldkriipsuga\",\n  \"components.Login.validationemailformat\": \"Vajalik on kehtiv e-post\",\n  \"components.Login.validationemailrequired\": \"Sisesta kehtiv e-posti aadress\",\n  \"components.Login.validationhostformat\": \"Vajalik on kehtiv URL\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL on kohustuslik\",\n  \"components.Login.validationpasswordrequired\": \"Parool on kohustuslik\",\n  \"components.Login.validationservertyperequired\": \"Vali serveri tüüp\",\n  \"components.Login.validationusernamerequired\": \"Kasutajanimi on kohustuslik\",\n  \"components.ManageSlideOver.alltime\": \"Kogu aeg\",\n  \"components.ManageSlideOver.downloadstatus\": \"Allalaadimised\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Täpsem\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Tühjenda andmed\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"See eemaldab pöördumatult kõik selle {mediaType} andmed, sealhulgas taotlused. Kui see element on teie {mediaServerName} raamatukogus olemas, taastatakse meediainfo järgmise skaneerimise ajal.\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Avatud probleemid\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Meedia\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K meedia\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Taotlusi pole.\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* See eemaldab selle {mediaType} ja kõik sellega seotud failid jäädavalt {arr}-ist.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Taotlused\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Halda: {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Märgi 4K-s saadavaks\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Märgi kõik hooajad 4K-s saadavaks\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Märgi kõik hooajad saadavaks\",\n  \"components.ManageSlideOver.markavailable\": \"Märgi saadavaks\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.ManageSlideOver.openarr\": \"Ava {arr}-is\",\n  \"components.ManageSlideOver.openarr4k\": \"Ava 4K {arr}-is\",\n  \"components.ManageSlideOver.opentautulli\": \"Ava Tautullis\",\n  \"components.ManageSlideOver.pastdays\": \"Viimased {days, number} päeva\",\n  \"components.ManageSlideOver.playedby\": \"Mänginud\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {vaatamine} other {vaatamist}}\",\n  \"components.ManageSlideOver.removearr\": \"Eemalda {arr}-ist\",\n  \"components.ManageSlideOver.removearr4k\": \"Eemalda 4K {arr}-ist\",\n  \"components.ManageSlideOver.tvshow\": \"sari\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Vaata rohkem\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Vali metaandmete pakkuja\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Kogu näitlejaskond\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Kogu meeskond\",\n  \"components.MovieDetails.addtowatchlist\": \"Lisa soovinimekirja\",\n  \"components.MovieDetails.budget\": \"Eelarve\",\n  \"components.MovieDetails.cast\": \"Näitlejad\",\n  \"components.MovieDetails.digitalrelease\": \"Digitaalne väljalase\",\n  \"components.MovieDetails.downloadstatus\": \"Allalaadimise staatus\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB kasutajate hinne – hääli: {formattedCount}\",\n  \"components.MovieDetails.managemovie\": \"Halda filmi\",\n  \"components.MovieDetails.mark4kavailable\": \"Märgi 4K-s saadavaks\",\n  \"components.MovieDetails.markavailable\": \"Märgi saadavaks\",\n  \"components.MovieDetails.openradarr\": \"Ava film Radarris\",\n  \"components.MovieDetails.openradarr4k\": \"Ava film 4K Radarris\",\n  \"components.MovieDetails.originallanguage\": \"Originaalkeel\",\n  \"components.MovieDetails.originaltitle\": \"Originaalpealkiri\",\n  \"components.MovieDetails.overview\": \"Ülevaade\",\n  \"components.MovieDetails.overviewunavailable\": \"Ülevaade puudub.\",\n  \"components.MovieDetails.physicalrelease\": \"Füüsiline väljalase\",\n  \"components.MovieDetails.play\": \"Mängi serveris {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Mängi 4K-s serveris {mediaServerName}\",\n  \"components.MovieDetails.productioncountries\": \"Tootja {countryCount, plural, one {riik} other {riiki}}\",\n  \"components.MovieDetails.recommendations\": \"Soovitused\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Väljalaskekuupäev} other {Väljalaskekuupäevad}}\",\n  \"components.MovieDetails.removefromwatchlist\": \"Eemalda soovinimekirjast\",\n  \"components.MovieDetails.reportissue\": \"Teata probleemist\",\n  \"components.MovieDetails.revenue\": \"Tulu\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes publiku hinne\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes kriitikute hinne\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutit\",\n  \"components.MovieDetails.showless\": \"Näita vähem\",\n  \"components.MovieDetails.showmore\": \"Näita rohkem\",\n  \"components.MovieDetails.similar\": \"Sarnased pealkirjad\",\n  \"components.MovieDetails.streamingproviders\": \"Hetkel voogedastuses\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Stuudio} other {Stuudiot}}\",\n  \"components.MovieDetails.theatricalrelease\": \"Kinolinastus\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB kasutajate hinne\",\n  \"components.MovieDetails.viewfullcrew\": \"Vaata kogu meeskonda\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> eemaldati edukalt soovinimekirjast!\",\n  \"components.MovieDetails.watchlistError\": \"Midagi läks valesti. Palun proovi uuesti.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> lisati edukalt soovinimekirja!\",\n  \"components.MovieDetails.watchtrailer\": \"Vaata treilerit\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Saa teavitus, kui teised kasutajad kommenteerivad probleeme.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Saa teavitus, kui teised kasutajad avavad probleeme uuesti.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Saa teavitus, kui teised kasutajad lahendavad probleeme.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Probleemi kommentaar\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Saada teavitusi, kui probleemidele lisatakse uusi kommentaare.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Probleemist teatatud\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Saada teavitusi, kui teatatakse uutest probleemidest.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Probleem uuesti avatud\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Saada teavitusi, kui probleeme avatakse uuesti.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Probleem lahendatud\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Saada teavitusi, kui probleemid lahendatakse.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Taotlus automaatselt heaks kiidetud\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Saada teavitusi, kui kasutajate uued meediataotlused kiidetakse automaatselt heaks.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Taotlus heaks kiidetud\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Saada teavitusi, kui meediataotlused kiidetakse käsitsi heaks.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Taotlus automaatselt esitatud\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Saa teavitus, kui sinu soovinimekirjas olevate asjade kohta esitatakse automaatselt taotlus.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Taotlus saadaval\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Saada teavitusi, kui taotletud meedia saabub serverisse.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Taotlus tagasi lükatud\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Saada teavitusi, kui meediataotlused lükatakse tagasi.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Taotluse töötlemine ebaõnnestus\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Saada teavitusi, kui meediataotluse lisamine Radarrisse või Sonarrisse ebaõnnestub.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Taotlus ootab heakskiitu\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Saada teavitusi, kui kasutajad esitavad uusi taotlusi, mis vajavad heakskiitu.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Teavituste tüübid\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Saa teavitus, kui sinu teatatud probleemidele lisatakse kommentaare.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Saa teavitus, kui teised kasutajad teatavad probleemidest.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Saa teavitus, kui sinu teatatud probleemid avatakse uuesti.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Saa teavitus, kui sinu teatatud probleemid lahendatakse.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Saa teavitus, kui teised kasutajad esitavad taotlusi, mis kiidetakse automaatselt heaks.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Saa teavitus, kui sinu meediataotlused kiidetakse heaks.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Saa teavitus, kui sinu meediataotlused on vaatamiseks saadaval.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Saa teavitus, kui sinu meediataotlused lükatakse tagasi.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Saa teavitus, kui sinu meediataotluse lisamine Radarrisse või Sonarrisse ebaõnnestub.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Saa teavitus, kui teised kasutajad esitavad taotlusi, mis vajavad heakskiitu.\",\n  \"components.PermissionEdit.admin\": \"Administraator\",\n  \"components.PermissionEdit.adminDescription\": \"Täielik administraatori ligipääs. Ignoreerib kõiki teisi õiguste kontrolle.\",\n  \"components.PermissionEdit.advancedrequest\": \"Täpsemad taotlused\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Annab õiguse muuta taotluste täpsemaid seadeid.\",\n  \"components.PermissionEdit.autoapprove\": \"Automaatne heakskiit\",\n  \"components.PermissionEdit.autoapprove4k\": \"Automaatne 4K heakskiit\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Annab automaatse heakskiidu kõikidele 4K meediataotlustele.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Automaatne 4K filmide heakskiit\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Annab automaatse heakskiidu 4K filmide taotlustele.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Automaatne 4K sarjade heakskiit\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Annab automaatse heakskiidu 4K sarjade taotlustele.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Annab automaatse heakskiidu kõikidele mitte-4K meediataotlustele.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Automaatne filmide heakskiit\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Annab automaatse heakskiidu mitte-4K filmide taotlustele.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Automaatne sarjade heakskiit\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Annab automaatse heakskiidu mitte-4K sarjade taotlustele.\",\n  \"components.PermissionEdit.autorequest\": \"Automaatne taotlus\",\n  \"components.PermissionEdit.autorequestDescription\": \"Annab õiguse esitada automaatselt mitte-4K taotlusi Plexi soovinimekirja kaudu.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Automaatne filmide taotlus\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Annab õiguse esitada automaatselt mitte-4K filmide taotlusi Plexi soovinimekirja kaudu.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Automaatne sarjade taotlus\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Annab õiguse esitada automaatselt mitte-4K sarjade taotlusi Plexi soovinimekirja kaudu.\",\n  \"components.PermissionEdit.blocklistedItems\": \"Meedia blokeerimine.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Annab õiguse lisada meediat musta nimekirja.\",\n  \"components.PermissionEdit.createissues\": \"Probleemidest teatamine\",\n  \"components.PermissionEdit.createissuesDescription\": \"Annab õiguse teatada meediaga seotud probleemidest.\",\n  \"components.PermissionEdit.manageblocklist\": \"Musta nimekirja haldamine\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Annab õiguse hallata mustas nimekirjas olevat meediat.\",\n  \"components.PermissionEdit.manageissues\": \"Probleemide haldamine\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Annab õiguse hallata meediaga seotud probleeme.\",\n  \"components.PermissionEdit.managerequests\": \"Taotluste haldamine\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Annab õiguse hallata meediataotlusi. Selle õigusega kasutaja taotlused kiidetakse alati automaatselt heaks.\",\n  \"components.PermissionEdit.request\": \"Taotlemine\",\n  \"components.PermissionEdit.request4k\": \"4K taotlemine\",\n  \"components.PermissionEdit.request4kDescription\": \"Annab õiguse taotleda 4K meediat.\",\n  \"components.PermissionEdit.request4kMovies\": \"4K filmide taotlemine\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Annab õiguse taotleda 4K filme.\",\n  \"components.PermissionEdit.request4kTv\": \"4K sarjade taotlemine\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Annab õiguse taotleda 4K sarju.\",\n  \"components.PermissionEdit.requestDescription\": \"Annab õiguse taotleda mitte-4K meediat.\",\n  \"components.PermissionEdit.requestMovies\": \"Filmide taotlemine\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Annab õiguse taotleda mitte-4K filme.\",\n  \"components.PermissionEdit.requestTv\": \"Sarjade taotlemine\",\n  \"components.PermissionEdit.requestTvDescription\": \"Annab õiguse taotleda mitte-4K sarju.\",\n  \"components.PermissionEdit.users\": \"Kasutajate haldamine\",\n  \"components.PermissionEdit.usersDescription\": \"Annab õiguse hallata kasutajaid. Selle õigusega kasutajad ei saa muuta administraatoreid ega anda administraatori õigusi.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Blokeeritud meedia vaatamine.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Annab õiguse vaadata mustas nimekirjas olevat meediat.\",\n  \"components.PermissionEdit.viewissues\": \"Probleemide vaatamine\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Annab õiguse vaadata teiste kasutajate teatatud probleeme.\",\n  \"components.PermissionEdit.viewrecent\": \"Viimati lisatute vaatamine\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Annab õiguse vaadata viimati lisatud meedia nimekirja.\",\n  \"components.PermissionEdit.viewrequests\": \"Taotluste vaatamine\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Annab õiguse vaadata teiste kasutajate esitatud taotlusi.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Vaata {mediaServerName} soovinimekirju\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Annab õiguse vaadata teiste kasutajate {mediaServerName} soovinimekirju.\",\n  \"components.PersonDetails.alsoknownas\": \"Tuntud ka kui: {names}\",\n  \"components.PersonDetails.appearsin\": \"Osalemised\",\n  \"components.PersonDetails.ascharacter\": \"rollis {character}\",\n  \"components.PersonDetails.birthdate\": \"Sündinud {birthdate}\",\n  \"components.PersonDetails.crewmember\": \"Meeskond\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {päev} other {päeva}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} {quotaDays} {days} jooksul</quotaUnits>\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {filmi}}\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {hooaeg} other {hooaega}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} {quotaDays} {days} jooksul</quotaUnits>\",\n  \"components.QuotaSelector.unlimited\": \"Piiramatu\",\n  \"components.RegionSelector.regionDefault\": \"Kõik regioonid\",\n  \"components.RegionSelector.regionServerDefault\": \"Vaikimisi ({region})\",\n  \"components.RequestBlock.approve\": \"Kiida taotlus heaks\",\n  \"components.RequestBlock.decline\": \"Lükka taotlus tagasi\",\n  \"components.RequestBlock.delete\": \"Kustuta taotlus\",\n  \"components.RequestBlock.edit\": \"Muuda taotlust\",\n  \"components.RequestBlock.languageprofile\": \"Keeleprofiil\",\n  \"components.RequestBlock.lastmodifiedby\": \"Viimati muutis\",\n  \"components.RequestBlock.profilechanged\": \"Kvaliteediprofiil\",\n  \"components.RequestBlock.requestdate\": \"Taotluse kuupäev\",\n  \"components.RequestBlock.requestedby\": \"Taotleja\",\n  \"components.RequestBlock.requestoverrides\": \"Taotluse ülekirjutamised\",\n  \"components.RequestBlock.rootfolder\": \"Juurkaust\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Hooaeg} other {Hooaega}}\",\n  \"components.RequestBlock.server\": \"Sihtserver\",\n  \"components.RequestButton.approve4krequests\": \"Kiida heaks {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.approverequest\": \"Kiida taotlus heaks\",\n  \"components.RequestButton.approverequest4k\": \"Kiida 4K taotlus heaks\",\n  \"components.RequestButton.approverequests\": \"Kiida heaks {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.decline4krequests\": \"Lükka tagasi {requestCount, plural, one {4K taotlus} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.declinerequest\": \"Lükka taotlus tagasi\",\n  \"components.RequestButton.declinerequest4k\": \"Lükka 4K taotlus tagasi\",\n  \"components.RequestButton.declinerequests\": \"Lükka tagasi {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.requestmore\": \"Taotle rohkem\",\n  \"components.RequestButton.requestmore4k\": \"Taotle rohkem 4K-s\",\n  \"components.RequestButton.viewrequest\": \"Vaata taotlust\",\n  \"components.RequestButton.viewrequest4k\": \"Vaata 4K taotlust\",\n  \"components.RequestCard.approverequest\": \"Kiida taotlus heaks\",\n  \"components.RequestCard.cancelrequest\": \"Tühista taotlus\",\n  \"components.RequestCard.declinerequest\": \"Lükka taotlus tagasi\",\n  \"components.RequestCard.deleterequest\": \"Kustuta taotlus\",\n  \"components.RequestCard.editrequest\": \"Muuda taotlust\",\n  \"components.RequestCard.failedretry\": \"Taotluse uuesti proovimisel tekkis viga.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} ei leitud\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Hooaeg} other {Hooaega}}\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestCard.unknowntitle\": \"Tundmatu pealkiri\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Tühista taotlus\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Kustuta taotlus\",\n  \"components.RequestList.RequestItem.editrequest\": \"Muuda taotlust\",\n  \"components.RequestList.RequestItem.failedretry\": \"Taotluse uuesti proovimisel tekkis viga.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} ei leitud\",\n  \"components.RequestList.RequestItem.modified\": \"Muudetud\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date}, muutis {user}\",\n  \"components.RequestList.RequestItem.profileName\": \"Profiil\",\n  \"components.RequestList.RequestItem.removearr\": \"Eemalda {arr}-ist\",\n  \"components.RequestList.RequestItem.requested\": \"Taotletud\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Taotletud\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Hooaeg} other {Hooaega}}\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Tundmatu pealkiri\",\n  \"components.RequestList.requests\": \"Taotlused\",\n  \"components.RequestList.showallrequests\": \"Näita kõiki taotlusi\",\n  \"components.RequestList.sortAdded\": \"Uusimad ees\",\n  \"components.RequestList.sortDirection\": \"Vaheta sorteerimise suunda\",\n  \"components.RequestList.sortModified\": \"Viimati muudetud\",\n  \"components.RequestList.unableToConnect\": \"Ühenduse loomine teenusega {services} ebaõnnestus. Osa infot võib olla puudu.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Täpsem\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* See sari on anime.\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Vaikimisi)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Sihtserver\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Keeleprofiil\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Silte pole.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Kvaliteediprofiil\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Taotle kui\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Juurkaust\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Vali sildid\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Sildid\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Sul on lubatud taotleda <strong>{limit}</strong> {type} iga <strong>{days}</strong> päeva tagant.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Sellel kasutajal on lubatud taotleda <strong>{limit}</strong> {type} iga <strong>{days}</strong> päeva tagant.\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"filmi\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {filmi}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Hooaja taotlusi pole piisavalt järel\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Saad vaadata oma taotluspiirangute kokkuvõtet oma <ProfileLink>profiili lehelt</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Saad vaadata selle kasutaja taotluspiirangute kokkuvõtet tema <ProfileLink>profiili lehelt</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Ühtegi} other {<strong>#</strong>}} {type} {remaining, plural, one {taotlust} other {taotlusi}} järel\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Sul peab olema vähemalt <strong>{seasons}</strong> {hooaega, plural, one {vaba hooaja taotlus} other {vaba hooaja taotlust}}, et seda sarja taotleda.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Sellel kasutajal peab olema vähemalt <strong>{seasons}</strong> {seasons, plural, one {vaba hooaja taotlus} other {vaba hooaja taotlust}}, et seda sarja taotleda.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"hooaeg\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {hooaeg} other {hooaega}}\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Me ei leidnud sellele sarjale vastet.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Me ei saanud seda sarja automaatselt tuvastada. Palun vali allpool õige vaste.\",\n  \"components.RequestModal.alreadyrequested\": \"Juba taotletud\",\n  \"components.RequestModal.approve\": \"Kiida taotlus heaks\",\n  \"components.RequestModal.autoapproval\": \"Automaatne heakskiit\",\n  \"components.RequestModal.cancel\": \"Tühista taotlus\",\n  \"components.RequestModal.edit\": \"Muuda taotlust\",\n  \"components.RequestModal.errorediting\": \"Taotluse muutmisel tekkis viga.\",\n  \"components.RequestModal.numberofepisodes\": \"# Osade arv\",\n  \"components.RequestModal.pending4krequest\": \"Ootel 4K taotlus\",\n  \"components.RequestModal.pendingapproval\": \"Sinu taotlus ootab heakskiitu.\",\n  \"components.RequestModal.pendingrequest\": \"Ootel taotlus\",\n  \"components.RequestModal.requestApproved\": \"<strong>{title}</strong> taotlus on heaks kiidetud!\",\n  \"components.RequestModal.requestCancel\": \"<strong>{title}</strong> taotlus on tühistatud.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> taotlemine õnnestus!\",\n  \"components.RequestModal.requestadmin\": \"See taotlus kiidetakse heaks automaatselt.\",\n  \"components.RequestModal.requestcancelled\": \"<strong>{title}</strong> taotlus on tühistatud.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Taotle kogumikku 4K-s\",\n  \"components.RequestModal.requestcollectiontitle\": \"Taotle kogumikku\",\n  \"components.RequestModal.requestedited\": \"<strong>{title}</strong> taotlus on edukalt muudetud!\",\n  \"components.RequestModal.requesterror\": \"Taotluse esitamisel tekkis viga.\",\n  \"components.RequestModal.requestfrom\": \"{username} taotlus ootab heakskiitu.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Taotle filmi 4K-s\",\n  \"components.RequestModal.requestmovies\": \"Taotle {count} {count, plural, one {film} other {filmi}}\",\n  \"components.RequestModal.requestmovies4k\": \"Taotle {count} {count, plural, one {film} other {filmi}} 4K-s\",\n  \"components.RequestModal.requestmovietitle\": \"Taotle filmi\",\n  \"components.RequestModal.requestseasons\": \"Taotle {seasonCount} {seasonCount, plural, one {hooaeg} other {hooaega}}\",\n  \"components.RequestModal.requestseasons4k\": \"Taotle {seasonCount} {seasonCount, plural, one {hooaeg} other {hooaega}} 4K-s\",\n  \"components.RequestModal.requestseries4ktitle\": \"Taotle sarja 4K-s\",\n  \"components.RequestModal.requestseriestitle\": \"Taotle sarja\",\n  \"components.RequestModal.season\": \"Hooaeg\",\n  \"components.RequestModal.seasonnumber\": \"{number}. hooaeg\",\n  \"components.RequestModal.selectmovies\": \"Vali film(id)\",\n  \"components.RequestModal.selectseason\": \"Vali hooaeg (hooajad)\",\n  \"components.ResetPassword.confirmpassword\": \"Kinnita parool\",\n  \"components.ResetPassword.email\": \"E-posti aadress\",\n  \"components.ResetPassword.emailresetlink\": \"Saada taastamislink\",\n  \"components.ResetPassword.gobacklogin\": \"Tagasi sisselogimislehele\",\n  \"components.ResetPassword.password\": \"Parool\",\n  \"components.ResetPassword.passwordreset\": \"Parooli lähtestamine\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Parooli lähtestamise link saadetakse sisestatud e-posti aadressile, kui see on seotud kehtiva kasutajaga.\",\n  \"components.ResetPassword.resetpassword\": \"Lähtesta oma parool\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Parool on edukalt lähtestatud!\",\n  \"components.ResetPassword.validationemailrequired\": \"Sisesta kehtiv e-posti aadress\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Paroolid peavad ühtima\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Parool on liiga lühike; see peab olema vähemalt 8 märki\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Parool on kohustuslik\",\n  \"components.Search.search\": \"Otsi\",\n  \"components.Search.searchresults\": \"Otsingutulemused\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Vanusepiirangute laadimine ebaõnnestus\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Maksimaalne reiting\",\n  \"components.Selector.CertificationSelector.minRating\": \"Minimaalne reiting\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Valikud puuduvad\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Vali vanusepiirang\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Vali riik\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Alusta kirjutamist, et otsida.\",\n  \"components.Selector.canceled\": \"Tühistatud\",\n  \"components.Selector.ended\": \"Lõppenud\",\n  \"components.Selector.inProduction\": \"Tootmises\",\n  \"components.Selector.nooptions\": \"Tulemusi pole.\",\n  \"components.Selector.pilot\": \"Pilootosa\",\n  \"components.Selector.planned\": \"Planeeritud\",\n  \"components.Selector.returningSeries\": \"Jätkuv sari\",\n  \"components.Selector.searchGenres\": \"Vali žanrid…\",\n  \"components.Selector.searchKeywords\": \"Otsi märksõnu…\",\n  \"components.Selector.searchStatus\": \"Vali staatus...\",\n  \"components.Selector.searchStudios\": \"Otsi stuudioid…\",\n  \"components.Selector.searchUsers\": \"Vali kasutajad…\",\n  \"components.Selector.showless\": \"Näita vähem\",\n  \"components.Selector.showmore\": \"Näita rohkem\",\n  \"components.Selector.starttyping\": \"Alusta kirjutamist, et otsida.\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Luba agent\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify teavituste seaded on salvestatud!\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Prioriteet\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify testteavituse saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Gotify testteavituse saatmine…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify testteavitus on saadetud!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Rakenduse pääsutõend (token)\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Serveri URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Määra prioriteedi number\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Rakenduse pääsutõend (token) on kohustuslik\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Vali vähemalt üks teavituse tüüp\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Kehtiv URL on kohustuslik\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL ei tohi lõppeda kaldkriipsuga\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Luba agent\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Lisa plakat\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Ntfy teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Ntfy teavituste seaded on salvestatud!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Parool\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Priooriteet\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Ntfy testteavituse saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Ntfy testteavituse saatmine…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Ntfy testteavitus on saadetud!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Pääsutõend (token)\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Pääsutõendiga (token) autentimine\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Teema\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Serveri juur-URL\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Kasutajanimi\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Kasutajanimi + parool autentimine\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Teema on kohustuslik\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Kehtiv URL on kohustuslik\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"Peate määrama prioriteedi vahemikus 1 kuni 5.\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Vali vähemalt üks teavituse tüüp\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Pääsutõend (token)\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Loo pääsutõend (token) oma <PushbulletSettingsLink>konto seadetes</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Luba agent\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Kanali silt\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbulleti teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbulleti teavituste seaded on salvestatud!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbulleti testteavituse saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Pushbulleti testteavituse saatmine…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbulleti testteavitus on saadetud!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Pääsutõend (token) on kohustuslik\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Vali vähemalt üks teavituse tüüp\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Rakenduse API pääsutõend\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registreeri rakendus</ApplicationRegistrationLink>, et seda Seerriga kasutada\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Luba agent\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Seadme vaikeväärtus\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Lisa plakat\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushoveri teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushoveri teavituste seaded on salvestatud!\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Teavituse heli\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushoveri testteavituse saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Pushoveri testteavituse saatmine…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushoveri testteavitus on saadetud!\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Kasutaja või grupi võti\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Sinu 30-kohaline <UsersGroupsLink>kasutaja või grupi tunnus</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Kehtiv rakenduse pääsutõend (token) on kohustuslik\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Vali vähemalt üks teavituse tüüp\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Kehtiv kasutaja või grupi võti on kohustuslik\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Luba agent\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Lisa plakat\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Slacki teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slacki teavituste seaded on salvestatud!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slacki testteavituse saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Slacki testteavituse saatmine…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slacki testteavitus on saadetud!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Vali vähemalt üks teavituse tüüp\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Kehtiv URL on kohustuslik\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhooki URL\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Loo <WebhookLink>Sissetulev Webhook</WebhookLink> integratsioon\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Luba agent\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Autoriseerimise päis (Authorization Header)\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Kohandatud päised\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Lisa päis\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Ei saa kasutada korraga standardset Authorization-päist ja kohandatud Authorization-päist. Palun eemalda üks neist.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Kõikidel päistel peab olema täidetud nii nimi kui ka väärtus\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Päise nimi\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Eemalda\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Lisa kohandatud HTTP-päised, mis saadetakse koos veebihaagi (webhook) päringutega\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Päise väärtus\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON-andmekogu (Payload)\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Taasta vaikimisi seaded\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON-andmekogu on edukalt lähtestatud!\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Toeta URL-i muutujaid\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Saadaolevad muutujad on kirjeldatud veebihaagi malli muutujate jaotises\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Malli muutujate abi\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Veebihaagi testteavituse saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Veebihaagi testteavituse saatmine…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Veebihaagi testteavitus on saadetud!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Pead sisestama korrektse JSON-andmekogu\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Pead valima vähemalt ühe teavitustüübi\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Pead sisestama kehtiva URL-i\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Veebihaagi URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"Testteavituse URL-iks on määratud {testUrl} tegeliku veebihaagi URL-i asemel.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Veebihaagi teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Veebihaagi teavituste seaded on edukalt salvestatud!\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Luba agent\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Lisa poster\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Veebitõuketeavituste saamiseks peab Seerr kasutama HTTPS-ühendust.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Veebitõuketeavituse testteate saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Veebitõuketeavituse testteate saatmine…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Veebitõuketeavituse testteade on saadetud!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Veebitõuketeavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Veebitõuketeavituste seaded on edukalt salvestatud!\",\n  \"components.Settings.Notifications.agentenabled\": \"Luba agent\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Luba iseallkirjastatud sertifikaadid\",\n  \"components.Settings.Notifications.authPass\": \"SMTP parool\",\n  \"components.Settings.Notifications.authUser\": \"SMTP kasutajanimi\",\n  \"components.Settings.Notifications.botAPI\": \"Boti autoriseerimistõend (token)\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Loo bot</CreateBotLink> Seerris kasutamiseks\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Boti avatari URL\",\n  \"components.Settings.Notifications.botUsername\": \"Boti kasutajanimi\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Võimalda kasutajatel samuti botiga vestlust alustada ja oma teavitusi seadistada\",\n  \"components.Settings.Notifications.chatId\": \"Vestluse ID (Chat ID)\",\n  \"components.Settings.Notifications.chatIdTip\": \"Alusta botiga vestlust, lisa <GetIdBotLink>@get_id_bot</GetIdBotLink> ja sisesta käsk <code>/my_id</code>\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discordi teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discordi teavituste seaded on edukalt salvestatud!\",\n  \"components.Settings.Notifications.emailsender\": \"Saatja aadress\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"E-posti teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"E-posti teavituste seaded on edukalt salvestatud!\",\n  \"components.Settings.Notifications.embedPoster\": \"Lisa poster\",\n  \"components.Settings.Notifications.enableMentions\": \"Luba mainimised\",\n  \"components.Settings.Notifications.encryption\": \"Krüpteerimismeetod\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Kasuta STARTTLS-i, kui see on saadaval\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Kasuta implitsiitset TLS-i (Implicit TLS)\",\n  \"components.Settings.Notifications.encryptionNone\": \"Puudub\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Kasuta alati STARTTLS-i\",\n  \"components.Settings.Notifications.encryptionTip\": \"Enamasti kasutab implitsiitne TLS porti 465 ja STARTTLS porti 587\",\n  \"components.Settings.Notifications.messageThreadId\": \"Lõime/teema ID\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Kui sinu grupivestluses on teemad lubatud, saad siin määrata lõime või teema ID\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP parool\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Allkirjasta krüpteeritud e-kirjad, kasutades <OpenPgpLink>OpenPGP</OpenPgpLink>-d\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP privaatvõti\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Allkirjasta krüpteeritud e-kirjad, kasutades <OpenPgpLink>OpenPGP</OpenPgpLink>-d\",\n  \"components.Settings.Notifications.sendSilently\": \"Saada hääletult\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Saada teavitused ilma helita\",\n  \"components.Settings.Notifications.senderName\": \"Saatja nimi\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP host (või SMTP server)\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP port\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegrami teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegrami teavituste seaded on edukalt salvestatud!\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discordi testteavituse saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Discordi testteavituse saatmine…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discordi testteavitus on saadetud!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"E-posti testteavituse saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"E-posti testteavituse saatmine…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"E-posti testteavitus on saadetud!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegrami testteavituse saatmine ebaõnnestus.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Telegrami testteavituse saatmine…\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegrami testteavitus on saadetud!\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Nõua kasutaja e-posti aadressi\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Pead sisestama boti autoriseerimistõendi (token)\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Pead sisestama kehtiva vestluse ID\",\n  \"components.Settings.Notifications.validationEmail\": \"Pead sisestama kehtiva e-posti aadressi\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"Lõime/teema ID peab olema positiivne täisarv\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Pead sisestama PGP parooli\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Pead sisestama kehtiva PGP privaatvõtme\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Pead sisestama kehtiva hostinime või IP-aadressi\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Pead sisestama kehtiva pordinumbri\",\n  \"components.Settings.Notifications.validationTypes\": \"Pead valima vähemalt ühe teavitustüübi\",\n  \"components.Settings.Notifications.validationUrl\": \"Pead sisestama kehtiva URL-i\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Pead sisestama kehtiva Discordi rolli ID\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Teavituse rolli ID\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"Rolli ID, mida veebihaagi (webhook) sõnumis mainida. Mainimiste keelamiseks jäta tühjaks\",\n  \"components.Settings.Notifications.webhookUrl\": \"Veebihaagi URL\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Loo oma serveris <DiscordWebhookLink>veebihaagi integratsioon</DiscordWebhookLink>\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Tingimused\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Määrab tingimused, mis peavad olema täidetud enne parameetrite muutmist. Reeglite rakendamiseks peavad kõik väljad olema kinnitatud (AND-tehe). Väli loetakse kinnitatuks, kui vähemalt üks selle omadustest ühtib (OR-tehe).\",\n  \"components.Settings.OverrideRuleModal.create\": \"Loo reegel\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Uus ülekirjutamise reegel\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Muuda ülekirjutamise reeglit\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Žanrid\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Märksõnad\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Keeled\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Silte pole.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Kvaliteediprofiil\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Juurkaust\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Ülekirjutamise reegel on edukalt loodud!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Ülekirjutamise reegel on edukalt värskendatud!\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Vali kvaliteediprofiil\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Vali juurkaust\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Vali teenus\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Vali sildid\",\n  \"components.Settings.OverrideRuleModal.service\": \"Teenus\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Rakenda see reegel valitud teenusele.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Seaded\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Määrab, milliseid seadeid muudetakse, kui ülaltoodud tingimused on täidetud.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Sildid\",\n  \"components.Settings.OverrideRuleModal.users\": \"Kasutajad\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Tingimused\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Žanr\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Märksõnad\",\n  \"components.Settings.OverrideRuleTile.language\": \"Keel\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Kvaliteediprofiil\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Juurkaust\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Seaded\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Sildid\",\n  \"components.Settings.OverrideRuleTile.users\": \"Kasutajad\",\n  \"components.Settings.RadarrModal.add\": \"Lisa server\",\n  \"components.Settings.RadarrModal.announced\": \"Kuulutatud\",\n  \"components.Settings.RadarrModal.apiKey\": \"API võti\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL-i baas (URL Base)\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Lisa uus 4K Radarr-i server\",\n  \"components.Settings.RadarrModal.createradarr\": \"Lisa uus Radarr-i server\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Vaikimisi 4K server\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Vaikimisi server\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Muuda 4K Radarr-i serverit\",\n  \"components.Settings.RadarrModal.editradarr\": \"Muuda Radarr-i serverit\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Luba automaatne otsing\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Väline URL\",\n  \"components.Settings.RadarrModal.hostname\": \"Hostinimi või IP-aadress\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Kinodes\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Siltide laadimine…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Kvaliteediprofiilide laadimine…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Juurkaustade laadimine…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimaalne saadavus\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Silte pole.\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Kvaliteediprofiil\",\n  \"components.Settings.RadarrModal.released\": \"Välja antud\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Juurkaust\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Vali minimaalne saadavus\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Vali kvaliteediprofiil\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Vali juurkaust\",\n  \"components.Settings.RadarrModal.selecttags\": \"Vali sildid\",\n  \"components.Settings.RadarrModal.server4k\": \"4K server\",\n  \"components.Settings.RadarrModal.servername\": \"Serveri nimi\",\n  \"components.Settings.RadarrModal.ssl\": \"Kasuta SSL-i\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Luba skannimine\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Sildista taotlused\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Lisa automaatselt täiendav silt taotleja kasutaja-ID ja kuvatava nimega\",\n  \"components.Settings.RadarrModal.tags\": \"Sildid\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Kvaliteediprofiilide laadimiseks testi esmalt ühendust\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Juurkaustade laadimiseks testi esmalt ühendust\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Siltide laadimiseks testi esmalt ühendust\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Radarriga ühenduse loomine ebaõnnestus.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Ühendus Radarriga on edukalt loodud!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Pead sisestama API võtme\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Pead sisestama kehtiva URL-i\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL ei tohi lõppeda kaldkriipsuga\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL-i baas peab algama kaldkriipsuga ( / )\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL-i baas ei tohi lõppeda kaldkriipsuga\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Pead sisestama kehtiva hostinime või IP-aadressi\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Pead valima minimaalse saadavuse\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Pead sisestama serveri nime\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Pead sisestama kehtiva pordinumbri\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Pead valima kvaliteediprofiili\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Pead valima juurkausta\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Praegune\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Uusim\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Väljalaskeandmed pole hetkel saadaval.\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Väljalasked\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} muudatuste logi\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Vaata muudatuste logi\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Vaata GitHubis\",\n  \"components.Settings.SettingsAbout.about\": \"Teave\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Lähemalt Seerrist\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Andmete kataloog\",\n  \"components.Settings.SettingsAbout.contribute\": \"Panusta arendusse\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentatsioon\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Abi saamine\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHubi arutelud\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Vananenud\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Kasutate Seerri <code>develop</code> haru, mis on soovitatav ainult arendajatele või neile, kes aitavad katsetada kõige värskemaid (bleeding-edge) muudatusi.\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Toeta Seerri\",\n  \"components.Settings.SettingsAbout.timezone\": \"Ajavöönd\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Meediat kokku\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Taotlusi kokku\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Ajakohane\",\n  \"components.Settings.SettingsAbout.version\": \"Versioon\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Meedia saadavuse sünkroonimine\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Puhver\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr puhverdab väliseid API-päringuid, et optimeerida jõudlust ja vältida asjatuid päringuid.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} puhver tühjendati.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Tabamused\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Võtmeid kokku\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Võtme suurus\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Möödalasud\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Puhvri nimi\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Väärtuse suurus\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Tühista töö\",\n  \"components.Settings.SettingsJobsCache.command\": \"Käsk\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNS-puhver\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr puhverdab DNS-päringuid, et optimeerida jõudlust ja vältida asjatuid API-päringuid.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"DNS-puhvri koondstatistika\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"See statistika on summeeritud kõigi DNS-puhvri kirjete peale.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Ühtegi DNS-päringut pole veel puhverdatud.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Aktiivne aadress\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Vanus\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"{hostname} DNS-puhver on tühjendatud.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Tabamused\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Möödalasud\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Hostinimi\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Allalaadimiste sünkroonimine\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Allalaadimiste sünkroonimise lähtestamine\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Muuda töö ajakava\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Praegune sagedus\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Uus sagedus\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Iga {jobScheduleDays, plural, one {päeva} other {{jobScheduleDays} days}} järel\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Iga {jobScheduleHours, plural, one {tunni} other {{jobScheduleHours} hours}} järel\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Iga {jobScheduleMinutes, plural, one {minuti} other {{jobScheduleMinutes} minutes}} järel\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Iga {jobScheduleSeconds, plural, one {sekundi} other {{jobScheduleSeconds} seconds}} järel\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Ebaõnnestumised\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Tühjenda puhver\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Tühjenda DNS-puhver\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Tabamuste määr\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Tabamused\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Pildipuhvri puhastus\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Pildipuhver\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Kui seadetes lubatud, vahendab (proxy) ja puhverdab Seerr pilte eelseadistatud välistest allikatest. Puhverdatud pildid salvestatakse sinu seadistuste kausta. Failid leiad asukohast <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Puhverdatud pilte\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Puhvri kogumaht\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4-varulahendused\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Jellyfini täielik raamatukogu skannimine\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Jellyfini viimati lisatud sisu skannimine\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Töö salvestamisel läks midagi valesti.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Töö on edukalt muudetud!\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} tühistati.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Töö nimi\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Tööd\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr viib regulaarselt läbi hooldustöid, kuid neid saab ka allpool käsitsi käivitada. Töö käsitsi käivitamine ei muuda selle ajakava.\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Tööd ja puhver\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} käivitati.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tüüp\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Möödalasud\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Järgmine käivitamine\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plexi täielik raamatukogu skannimine\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plexi viimati lisatud sisu skannimine\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plexi värskendustõend (token)\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plexi sooviloendi sünkroonimine\",\n  \"components.Settings.SettingsJobsCache.process\": \"Protsess\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Töötle mustas nimekirjas olevaid silte\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarri skannimine\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Käivita kohe\",\n  \"components.Settings.SettingsJobsCache.size\": \"Suurus\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarri skannimine\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Tundmatu töö\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Kasutajate avatarid\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Logiteade on kopeeritud lõikelauale.\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Kopeeri lõikelauale\",\n  \"components.Settings.SettingsLogs.extraData\": \"Lisaandmed\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Silumine (Debug)\",\n  \"components.Settings.SettingsLogs.filterError\": \"Viga\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Hoiatus\",\n  \"components.Settings.SettingsLogs.label\": \"Silt\",\n  \"components.Settings.SettingsLogs.level\": \"Raskusaste\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Logi üksikasjad\",\n  \"components.Settings.SettingsLogs.logs\": \"Logid\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Neid logisid saab vaadata ka otse <code>stdout</code>kaudu või <code>failist {appDataPath}/logs/seerr.log.</code>.\",\n  \"components.Settings.SettingsLogs.message\": \"Sõnum\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Paus\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Jätka\",\n  \"components.Settings.SettingsLogs.showall\": \"Näita kõiki logisid\",\n  \"components.Settings.SettingsLogs.time\": \"Ajamärgis\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Vaata üksikasju\",\n  \"components.Settings.SettingsMain.apikey\": \"API võti\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"API võti kopeeriti lõikelauale.\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Rakenduse pealkiri\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Rakenduse URL\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Lisa siltidega sisu musta nimekirja\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Musta nimekirja lisatava sisu piirang sildi kohta\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"Töö „Töötle mustas nimekirjas olevaid silte“ lisab musta nimekirja märgitud arvu lehekülgi iga sorteerimisviisi kohta. Suurem arv loob täpsema nimekirja, kuid kulutab rohkem ruumi.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Lisa siltidega sisu automaatselt musta nimekirja, kasutades tööd „Töötle mustas nimekirjas olevaid silte“\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Luba piltide puhverdamine\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Puhverda välisallikatest pärit pilte (nõuab märkimisväärset kettaruumi)\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Avastamispiirkond\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filtreeri sisu piirkondliku saadavuse järgi\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Luba eriepisoodide taotlemine\",\n  \"components.Settings.SettingsMain.general\": \"Üldine\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Üldseaded\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Seadista Seerri globaalsed ja vaikeseaded.\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Peida olemasolev meedia\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Peida juba olemasolev meedia avastamislehtedelt, kuid mitte otsingutulemustest\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Peida mustas nimekirjas olevad üksused\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Peida musta nimekirja lisatud üksused avastamislehtedelt kõigi kasutajate jaoks, kellel on õigus „Halda musta nimekirja“\",\n  \"components.Settings.SettingsMain.locale\": \"Kuvamise keel\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Avastamise keel\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtreeri sisu originaalkeele järgi\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Luba sarjade osaline taotlemine\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Voogedastuse piirkond\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Näita voogedastusplatvorme piirkondliku saadavuse järgi\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Uue API-võtme genereerimisel läks midagi valesti.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Uus API-võti on edukalt genereeritud!\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Seadete salvestamisel läks midagi valesti.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Seaded on edukalt salvestatud!\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Pead sisestama rakenduse pealkirja\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Pead sisestama kehtiva URL-i\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL ei tohi lõppeda kaldkriipsuga\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Pead sisestama kehtiva URL-i\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URL ei tohi lõppeda kaldkriipsuga\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube'i URL\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"YouTube'i videote baas-URL, kui kasutatakse ise hostitud (self-hosted) YouTube'i rakendust.\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"API-päringu aegumine\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Maksimaalne aeg (sekundites), mida oodatakse välistelt teenustelt (nt Radarr/Sonarr) vastuse saamiseks. Määra 0, kui soovid aegumise keelata.\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Luba CSRF-kaitse\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"ÄRA luba seda seadet, kui sa ei tea täpselt, mida sa teed!\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Määra väline API-juurdepääs ainult lugemiseks (nõuab HTTPS-ühendust)\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNS-puhver\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"DNS-puhvri maksimaalne TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"DNS-puhvri minimaalne TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"ÄRA luba seda, kui sul on probleeme DNS-päringutega\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Luba DNS-päringute puhverdamine, et optimeerida jõudlust ja vältida asjatuid API-päringuid\",\n  \"components.Settings.SettingsNetwork.docs\": \"dokumentatsioon\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Eelista IPv4 lahendamist\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Sunni Seerr lahendama esmalt IPv4-aadresse IPv6-aadresside asemel\",\n  \"components.Settings.SettingsNetwork.network\": \"Võrk\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Nende seadete asemel tuleks eelistada konteineri või operatsioonisüsteemi võrguparameetreid. Vaata lisateavet {docs} alt.\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Võrguseaded\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Seadista oma Seerri eksemplari võrguseadeid.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Proksi eiratavad aadressid\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Kasuta eraldajana koma (,) ning alamdomeenide tähistamiseks metamärki (*.)\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Ära kasuta proksit kohalike aadresside puhul\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S)-proksi\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Saada KÕIK väljuvad HTTP/HTTPS päringud läbi proksiserveri (host/port). See EI lülita sisse HTTPS-i, SSL-i ega sertifikaatide seadistust.\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Proksi hostinimi\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Proksi parool\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Proksi port\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Kasuta proksi jaoks SSL-i\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Proksi kasutajanimi\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Seadete salvestamisel läks midagi valesti.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Seaded on edukalt salvestatud!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Luba proksi tugi\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Võimaldab Seerril tuvastada kliendi korrektse IP-aadressi, kui süsteem asub proksi taga\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Pead sisestama kehtiva aegumise väärtuse\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Pead sisestama kehtiva maksimaalse TTL-i\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Pead sisestama kehtiva minimaalse TTL-i\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Pead sisestama kehtiva pordinumbri\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Valitud peab olema vähemalt üks autentimismeetod.\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Vaikimisi õigused\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Uutele kasutajatele määratavad esmased õigused\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Luba kohalik sisselogimine\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Luba kasutajatel sisse logida oma e-posti aadressi ja parooliga\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Sisselogimismeetodid\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Seadista kasutajate sisselogimismeetodid.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Luba {mediaServerName} sisselogimine\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Luba kasutajatel sisse logida oma {mediaServerName} kontoga\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Globaalne filmide taotlemise piirang\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Luba uus {mediaServerName} sisselogimine\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Luba {mediaServerName} kasutajatel sisse logida ilma neid eelnevalt importimata\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Seadete salvestamisel läks midagi valesti.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Kasutajaseaded on edukalt salvestatud!\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Globaalne sarjade taotlemise piirang\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Kasutajaseaded\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Seadista kasutajate globaalsed ja vaikeseaded.\",\n  \"components.Settings.SettingsUsers.users\": \"Kasutajad\",\n  \"components.Settings.SonarrModal.add\": \"Lisa server\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Anime-sarja tüüp\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime sildid\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime keeleprofiil\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime kvaliteediprofiil\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime juurkaust\",\n  \"components.Settings.SonarrModal.apiKey\": \"API võti\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL-i baas (URL Base)\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Lisa uus 4K Sonarri server\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Lisa uus Sonarri server\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Vaikimisi 4K server\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Vaikimisi server\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Muuda 4K Sonarri serverit\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Muuda Sonarri serverit\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Luba automaatne otsing\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Väline URL\",\n  \"components.Settings.SonarrModal.hostname\": \"Hostinimi või IP-aadress\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Keeleprofiil\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Siltide laadimine…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Keeleprofiilide laadimine…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Kvaliteediprofiilide laadimine…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Juurkaustade laadimine…\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Jälgi uusi hooaegu\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Silte pole.\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Kvaliteediprofiil\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Juurkaust\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Hooajakaustad\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Vali keeleprofiil\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Vali kvaliteediprofiil\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Vali juurkaust\",\n  \"components.Settings.SonarrModal.selecttags\": \"Vali sildid\",\n  \"components.Settings.SonarrModal.seriesType\": \"Sarja tüüp\",\n  \"components.Settings.SonarrModal.server4k\": \"4K server\",\n  \"components.Settings.SonarrModal.servername\": \"Serveri nimi\",\n  \"components.Settings.SonarrModal.ssl\": \"Kasuta SSL-i\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Luba skannimine\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Sildista taotlused\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Lisa automaatselt täiendav silt taotleja kasutaja-ID ja kuvatava nimega\",\n  \"components.Settings.SonarrModal.tags\": \"Sildid\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Keeleprofiilide laadimiseks testi esmalt ühendust\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Kvaliteediprofiilide laadimiseks testi esmalt ühendust\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Juurkaustade laadimiseks testi esmalt ühendust\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Siltide laadimiseks testi esmalt ühendust\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Sonarriga ühenduse loomine ebaõnnestus.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Ühendus Sonarriga on edukalt loodud!\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Pead sisestama API võtme\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Pead sisestama kehtiva URL-i\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL ei tohi lõppeda kaldkriipsuga\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"URL-i baas peab algama kaldkriipsuga ( / )\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"URL-i baas ei tohi lõppeda kaldkriipsuga\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Pead sisestama kehtiva hostinime või IP-aadressi\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Pead valima keeleprofiili\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Pead sisestama serveri nime\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Pead sisestama kehtiva pordinumbri\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Pead valima kvaliteediprofiili\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Pead valima juurkausta\",\n  \"components.Settings.activeProfile\": \"Aktiivne profiil\",\n  \"components.Settings.addradarr\": \"Lisa Radarr-i server\",\n  \"components.Settings.address\": \"Aadress\",\n  \"components.Settings.addrule\": \"Uus ülekirjutamise reegel\",\n  \"components.Settings.addsonarr\": \"Lisa Sonarri server\",\n  \"components.Settings.advancedTooltip\": \"Selle seade vale seadistamine võib põhjustada tõrkeid rakenduse töös\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Kõik valitud metaandmete pakkujad on töökorras\",\n  \"components.Settings.animeMetadataProvider\": \"Anime metaandmete pakkuja\",\n  \"components.Settings.apiKey\": \"API-võti\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Kleebi musta nimekirja siltide seadistus allapoole.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Impordi musta nimekirja siltide seadistus\",\n  \"components.Settings.blocklistedTagsText\": \"Mustas nimekirjas olevad sildid\",\n  \"components.Settings.cancelscan\": \"Tühista skannimine\",\n  \"components.Settings.chooseProvider\": \"Vali metaandmete pakkujad erinevatele sisutüüpidele\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Kas oled kindel, et soovid mustas nimekirjas olevad sildid eemaldada?\",\n  \"components.Settings.clickTest\": \"Klõpsa nupule „Test“, et kontrollida ühendust metaandmete pakkujatega\",\n  \"components.Settings.connectionTestFailed\": \"Ühenduse kontroll ebaõnnestus\",\n  \"components.Settings.copyBlocklistedTags\": \"Mustas nimekirjas olevad sildid kopeeriti lõikelauale.\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Pole midagi kopeerida\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Kopeeri musta nimekirja siltide seadistus\",\n  \"components.Settings.currentlibrary\": \"Praegune raamatukogu: {name}\",\n  \"components.Settings.default\": \"Vaikimisi\",\n  \"components.Settings.default4k\": \"Vaikimisi 4K\",\n  \"components.Settings.deleteServer\": \"Kustuta {serverType} server\",\n  \"components.Settings.deleteserverconfirm\": \"Kas oled kindel, et soovid selle serveri kustutada?\",\n  \"components.Settings.email\": \"E-post\",\n  \"components.Settings.enablessl\": \"Kasuta SSL-i\",\n  \"components.Settings.experimentalTooltip\": \"Selle seade lubamine võib põhjustada rakenduse ootamatut käitumist\",\n  \"components.Settings.externalUrl\": \"Väline URL\",\n  \"components.Settings.failed\": \"Ei tööta\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Metaandmete pakkuja seadete salvestamine ebaõnnestus\",\n  \"components.Settings.general\": \"Üldine\",\n  \"components.Settings.hostname\": \"Hostinimi või IP-aadress\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Impordi musta nimekirja siltide seadistus\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} ei ole TMDB märksõna.\",\n  \"components.Settings.invalidurlerror\": \"Ühenduse loomine {mediaServerName} serveriga ebaõnnestus.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Unustatud parooli URL\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName} seaded\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Soovi korral seadistage oma {mediaServerName} serveri sisesed ja välised lõpp-punktid (endpoints). Enamikul juhtudel on väline URL sisemisest erinev. Samuti saab määrata kohandatud parooli lähtestamise URL-i {mediaServerName} sisselogimiseks, juhuks kui soovite suunata kasutaja teisele parooli lähtestamise lehele. Saate muuta ka Jellyfini API-võtit, mis genereeriti varem automaatselt.\",\n  \"components.Settings.jellyfinSettingsFailure\": \"{mediaServerName} seadete salvestamisel läks midagi valesti.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName} seaded on edukalt salvestatud!\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Kohandatud autentimine koos automaatse raamatukogude rühmitamisega ei ole toetatud\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Raamatukogude sünkroonimisel läks midagi valesti\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Ühtegi raamatukogu ei leitud\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName} raamatukogud\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"Raamatukogud, mida {mediaServerName} sisu leidmiseks skannib. Kui nimekirjas pole ühtegi raamatukogu, klõpsake alloleval nupul.\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName} Seaded\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Seadistage oma {mediaServerName} serveri seaded. {mediaServerName} skannib teie {mediaServerName} raamatukogusid, et näha...\",\n  \"components.Settings.librariesRemaining\": \"Raamatukogusid järel: {count}\",\n  \"components.Settings.manualscan\": \"Raamatukogu käsitsi skannimine\",\n  \"components.Settings.manualscanDescription\": \"Tavaliselt käivitatakse seda vaid kord 24 tunni jooksul. Seerr kontrollib sinu Plexi serveri viimati lisatud sisu sagedamini. Kui seadistad Plexi esimest korda, on soovitatav teha ühekordne täielik käsitsi skannimine!\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Tavaliselt käivitatakse seda vaid kord 24 tunni jooksul. Seerr kontrollib sinu {mediaServerName} serveri viimati lisatud sisu sagedamini. Kui seadistad Seerri esimest korda, on soovitatav teha ühekordne täielik käsitsi skannimine!\",\n  \"components.Settings.manualscanJellyfin\": \"Raamatukogu käsitsi skannimine\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.mediaTypeSeries\": \"sari\",\n  \"components.Settings.menuAbout\": \"Teave\",\n  \"components.Settings.menuGeneralSettings\": \"Üldine\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.menuJobs\": \"Tööd ja puhver\",\n  \"components.Settings.menuLogs\": \"Logid\",\n  \"components.Settings.menuMetadataProviders\": \"Metaandmete pakkujad\",\n  \"components.Settings.menuNetwork\": \"Võrk\",\n  \"components.Settings.menuNotifications\": \"Teavitused\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Teenused\",\n  \"components.Settings.menuUsers\": \"Kasutajad\",\n  \"components.Settings.metadataProviderSelection\": \"Metaandmete pakkuja valimine\",\n  \"components.Settings.metadataProviderSettings\": \"Metaandmete pakkujad\",\n  \"components.Settings.metadataSettings\": \"Metaandmete pakkuja seaded\",\n  \"components.Settings.metadataSettingsSaved\": \"Metaandmete pakkuja seaded on salvestatud\",\n  \"components.Settings.no\": \"Ei\",\n  \"components.Settings.noDefault4kServer\": \"Kasutajate 4K {mediaType} taotluste lubamiseks peab üks 4K {serverType} server olema määratud vaikimisi serveriks.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Kui sul on nii tava- kui ka 4K-sisu jaoks vaid üks {serverType} server (või kui laadid alla ainult 4K-sisu), siis <strong>EI TOHIKS</strong> seda {serverType} serverit määrata 4K-serveriks.\",\n  \"components.Settings.noDefaultServer\": \"{mediaType} taotluste töötlemiseks peab vähemalt üks {serverType} server olema määratud vaikimisi serveriks.\",\n  \"components.Settings.noSpecialCharacters\": \"Seadistus peab olema komadega eraldatud TMDB märksõnade ID-de loend ning see ei tohi alata ega lõppeda komaga.\",\n  \"components.Settings.nooptions\": \"Tulemusi pole.\",\n  \"components.Settings.notTested\": \"Kontrollimata\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Seadista ja luba teavitusagendid.\",\n  \"components.Settings.notifications\": \"Teavitused\",\n  \"components.Settings.notificationsettings\": \"Teavituste seaded\",\n  \"components.Settings.notrunning\": \"Ei tööta\",\n  \"components.Settings.operational\": \"Töökorras\",\n  \"components.Settings.overrideRules\": \"Ülekirjutamise reeglid\",\n  \"components.Settings.overrideRulesDescription\": \"Ülekirjutamise reeglid võimaldavad määrata omadusi, mis asendatakse, kui taotlus vastab reeglile.\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.plexlibraries\": \"Plexi raamatukogud\",\n  \"components.Settings.plexlibrariesDescription\": \"Raamatukogud, mida Seerr sisu leidmiseks skannib. Seadista ja salvesta oma Plexi ühenduse seaded, seejärel klõpsa allolevat nuppu, kui loendis pole raamatukogusid.\",\n  \"components.Settings.plexsettings\": \"Plexi seaded\",\n  \"components.Settings.plexsettingsDescription\": \"Seadista oma Plexi serveri seaded. Seerr skannib sinu Plexi raamatukogusid, et tuvastada sisu saadavust.\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.providerStatus\": \"Metaandmete pakkuja olek\",\n  \"components.Settings.radarrsettings\": \"Radarr-i seaded\",\n  \"components.Settings.restartrequiredTooltip\": \"Selle seade muudatuste jõustumiseks tuleb Seerr taaskäivitada\",\n  \"components.Settings.save\": \"Salvesta muudatused\",\n  \"components.Settings.saving\": \"Salvestamine…\",\n  \"components.Settings.scan\": \"Sünkrooni raamatukogud\",\n  \"components.Settings.scanbackground\": \"Skannimine toimub taustal. Vahepeal saad jätkata seadistamist.\",\n  \"components.Settings.scanning\": \"Sünkroonimine…\",\n  \"components.Settings.searchKeywords\": \"Otsi märksõnu…\",\n  \"components.Settings.seriesMetadataProvider\": \"Sarjade metaandmete pakkuja\",\n  \"components.Settings.serverLocal\": \"kohalik\",\n  \"components.Settings.serverRemote\": \"kaugühendus\",\n  \"components.Settings.serverSecure\": \"turvaline\",\n  \"components.Settings.serverpreset\": \"Server\",\n  \"components.Settings.serverpresetLoad\": \"Saadaolevate serverite laadimiseks vajuta nuppu\",\n  \"components.Settings.serverpresetManualMessage\": \"Käsitsi seadistamine\",\n  \"components.Settings.serverpresetRefreshing\": \"Serverite hankimine…\",\n  \"components.Settings.serviceSettingsDescription\": \"Seadista oma {serverType} server(id) allpool. Saad ühendada mitu {serverType} serverit, kuid ainult kaks neist saab märkida vaikimisi serveriteks (üks tava- ja üks 4K-server). Administraatorid saavad enne taotluse kinnitamist muuta serverit, mida kasutatakse sisu töötlemiseks.\",\n  \"components.Settings.services\": \"Teenused\",\n  \"components.Settings.settingUpPlexDescription\": \"Plexi seadistamiseks saad andmed sisestada käsitsi või valida serveri, mis on pärit saidilt <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Saadaolevate serverite loendi hankimiseks vajuta rippmenüüst paremal asuvat nuppu.\",\n  \"components.Settings.settings\": \"Seaded\",\n  \"components.Settings.sonarrsettings\": \"Sonarri seaded\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Alusta skannimist\",\n  \"components.Settings.starttyping\": \"Otsimiseks alusta trükkimist.\",\n  \"components.Settings.syncJellyfin\": \"Sünkrooni raamatukogud\",\n  \"components.Settings.syncing\": \"Sünkroonimine\",\n  \"components.Settings.tautulliApiKey\": \"API-võti\",\n  \"components.Settings.tautulliSettings\": \"Tautulli seaded\",\n  \"components.Settings.tautulliSettingsDescription\": \"Soovi korral seadistage oma Tautulli serveri seaded. Seerr hangib Tautullist teie Plexi meedia vaatamisajaloo andmed.\",\n  \"components.Settings.timeout\": \"Aegumine\",\n  \"components.Settings.tip\": \"Vihje\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"TMDB pakkuja ei tööta, palun valige mõni teine metaandmete pakkuja\",\n  \"components.Settings.toastPlexConnecting\": \"Üritan luua ühendust Plexiga…\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Ühenduse loomine Plexiga ebaõnnestus.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Ühendus Plexiga on edukalt loodud!\",\n  \"components.Settings.toastPlexRefresh\": \"Serverite loendi hankimine Plexist…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Plexi serverite loendi hankimine ebaõnnestus.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Plexi serverite loend on edukalt hangitud!\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Tautulli seadete salvestamisel läks midagi valesti.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli seaded on edukalt salvestatud!\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"TVDB pakkuja ei tööta, palun vali mõni teine metaandmete pakkuja\",\n  \"components.Settings.urlBase\": \"URL-i baas\",\n  \"components.Settings.validationApiKey\": \"Pead sisestama API-võtme\",\n  \"components.Settings.validationHostnameRequired\": \"Pead sisestama kehtiva hostinime või IP-aadressi\",\n  \"components.Settings.validationPortRequired\": \"Pead sisestama kehtiva pordinumbri\",\n  \"components.Settings.validationUrl\": \"Pead sisestama kehtiva URL-i\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL-i baas peab algama kaldkriipsuga\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"URL-i baas ei tohi lõppeda kaldkriipsuga\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL ei tohi lõppeda kaldkriipsuga\",\n  \"components.Settings.valueRequired\": \"Väärtuse sisestamine on kohustuslik.\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Veebirakenduse</WebAppLink> URL\",\n  \"components.Settings.webAppUrlTip\": \"Soovi korral suuna kasutajad oma serveris asuvasse veebirakendusse, mitte „hostitud“ veebirakendusse\",\n  \"components.Settings.webhook\": \"Weebihaage (webhook)\",\n  \"components.Settings.webpush\": \"Veebitõuketeated\",\n  \"components.Settings.yes\": \"Jah\",\n  \"components.Setup.back\": \"Mine tagasi\",\n  \"components.Setup.configemby\": \"Seadista Emby\",\n  \"components.Setup.configjellyfin\": \"Seadista Jellyfin\",\n  \"components.Setup.configplex\": \"Seadista Plex\",\n  \"components.Setup.configuremediaserver\": \"Seadista meediaserver\",\n  \"components.Setup.configureservices\": \"Seadista teenused\",\n  \"components.Setup.continue\": \"Jätka\",\n  \"components.Setup.finish\": \"Lõpeta seadistamine\",\n  \"components.Setup.finishing\": \"Lõpetamine…\",\n  \"components.Setup.librarieserror\": \"Valideerimine ebaõnnestus. Jätkamiseks lülita raamatukogud uuesti sisse/välja.\",\n  \"components.Setup.servertype\": \"Vali serveri tüüp\",\n  \"components.Setup.setup\": \"Seadistamine\",\n  \"components.Setup.signin\": \"Logi sisse\",\n  \"components.Setup.signinMessage\": \"Alustamiseks logi sisse\",\n  \"components.Setup.signinWithEmby\": \"Sisesta oma Emby andmed\",\n  \"components.Setup.signinWithJellyfin\": \"Sisesta oma Jellyfini andmed\",\n  \"components.Setup.signinWithPlex\": \"Sisesta oma Plexi andmed\",\n  \"components.Setup.subtitle\": \"Alustamiseks vali oma meediaserver\",\n  \"components.Setup.welcome\": \"Tere tulemast Seerri\",\n  \"components.StatusBadge.managemedia\": \"Halda: {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Ava rakenduses {arr}\",\n  \"components.StatusBadge.playonplex\": \"Vaata platvormil {mediaServerName}\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} on värskendatud\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Rakenduse uuesti laadimiseks klõpsa allolevat nuppu.\",\n  \"components.StatusChecker.reloadApp\": \"Laadi {applicationTitle} uuesti\",\n  \"components.StatusChecker.restartRequired\": \"Vajalik serveri taaskäivitamine\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Uuendatud seadete rakendamiseks palun taaskäivita server.\",\n  \"components.TitleCard.addToWatchList\": \"Lisa sooviloendisse\",\n  \"components.TitleCard.cleardata\": \"Kustuta andmed\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} ei leitud\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.TitleCard.watchlistCancel\": \"Teose<strong>{title}</strong> lisamine sooviloendisse tühistati.\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> eemaldati edukalt sooviloendist!\",\n  \"components.TitleCard.watchlistError\": \"Midagi läks valesti. Palun proovi uuesti.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> lisati edukalt sooviloendisse!\",\n  \"components.TvDetails.Season.noepisodes\": \"Osade nimekiri pole saadaval.\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Hooaja andmete hankimisel läks midagi valesti.\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Sarja täielik näitlejaskond\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Sarja täielik võttemeeskond\",\n  \"components.TvDetails.addtowatchlist\": \"Lisa sooviloendisse\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.cast\": \"Näitlejad\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Episood} other {# Episoodi}}\",\n  \"components.TvDetails.episodeRuntime\": \"Osa kestus\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutit\",\n  \"components.TvDetails.firstAirDate\": \"Esmakordselt eetris\",\n  \"components.TvDetails.manageseries\": \"Halda sarja\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Telekanal} other {Telekanalit}}\",\n  \"components.TvDetails.nextAirDate\": \"Järgmisena eetris\",\n  \"components.TvDetails.originallanguage\": \"Originaalkeel\",\n  \"components.TvDetails.originaltitle\": \"Originaalpealkiri\",\n  \"components.TvDetails.overview\": \"Ülevaade\",\n  \"components.TvDetails.overviewunavailable\": \"Ülevaade puudub.\",\n  \"components.TvDetails.play\": \"Vaata platvormil {mediaServerName}\",\n  \"components.TvDetails.play4k\": \"Vaata 4K-s platvormil {mediaServerName}\",\n  \"components.TvDetails.productioncountries\": \"Tootja{countryCount, plural, one {riik} other {riigid}}\",\n  \"components.TvDetails.recommendations\": \"Soovitused\",\n  \"components.TvDetails.removefromwatchlist\": \"Eemalda sooviloendist\",\n  \"components.TvDetails.reportissue\": \"Teata veast\",\n  \"components.TvDetails.rtaudiencescore\": \"Rotten Tomatos vaatajate hinne\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes kriitikute hinne\",\n  \"components.TvDetails.seasonnumber\": \"Hooaeg {seasonNumber}\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Hooaeg} other {# Hooaega}}\",\n  \"components.TvDetails.seasonstitle\": \"Hooajad\",\n  \"components.TvDetails.showtype\": \"Sarja tüüp\",\n  \"components.TvDetails.similar\": \"Sarnased sarjad\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.streamingproviders\": \"Praegu voogedastatav\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB kasutajate hinne\",\n  \"components.TvDetails.viewfullcrew\": \"Vaata täielikku võttemeeskonda\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> eemaldati edukalt sooviloendist!\",\n  \"components.TvDetails.watchlistError\": \"Midagi läks valesti. Palun proovi uuesti.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> lisati edukalt sooviloendisse!\",\n  \"components.TvDetails.watchtrailer\": \"Vaata treilerit\",\n  \"components.UserList.accounttype\": \"Tüüp\",\n  \"components.UserList.admin\": \"Admin\",\n  \"components.UserList.autogeneratepassword\": \"Genereeri parool automaatselt\",\n  \"components.UserList.autogeneratepasswordTip\": \"Saada serveri genereeritud parool kasutajale e-postiga\",\n  \"components.UserList.bulkedit\": \"Hulgi-muutmine\",\n  \"components.UserList.create\": \"Loo\",\n  \"components.UserList.created\": \"Liitus\",\n  \"components.UserList.createlocaluser\": \"Loo kohalik kasutaja\",\n  \"components.UserList.creating\": \"Loomine…\",\n  \"components.UserList.deleteconfirm\": \"Kas oled kindel, et soovid selle kasutaja kustutada? Kõik tema taotluste andmed eemaldatakse jäädavalt.\",\n  \"components.UserList.deleteuser\": \"Kustuta kasutaja\",\n  \"components.UserList.edituser\": \"Muuda kasutaja õigusi\",\n  \"components.UserList.email\": \"E-posti aadress\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {kasutaja} other {kasutajat}} imporditi edukalt!\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {kasutaja} teist {kasutajat}} on edukalt imporditud!\",\n  \"components.UserList.importfromJellyfin\": \"Impordi {mediaServerName} kasutajad\",\n  \"components.UserList.importfromJellyfinerror\": \"{mediaServerName} kasutajate importimisel läks midagi valesti.\",\n  \"components.UserList.importfrommediaserver\": \"Impordi {mediaServerName} kasutajad\",\n  \"components.UserList.importfromplex\": \"Impordi Plexi kasutajad\",\n  \"components.UserList.importfromplexerror\": \"Plexi kasutajate importimisel läks midagi valesti.\",\n  \"components.UserList.localLoginDisabled\": \"Säte <strong>Luba kohalik sisselogimine</strong> on hetkel keelatud.\",\n  \"components.UserList.localuser\": \"Kohalik kasutaja\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName} kasutaja\",\n  \"components.UserList.newJellyfinsigninenabled\": \"Säte <strong>Luba uus {mediaServerName} sisselogimine</strong> on hetkel lubatud. {mediaServerName} kasutajaid, kellel on juurdepääs raamatukogule, ei ole sisselogimiseks vaja importida.\",\n  \"components.UserList.newplexsigninenabled\": \"Säte <strong>Luba uus Plexi sisselogimine</strong> on hetkel lubatud. Plexi kasutajaid, kellel on juurdepääs raamatukogule, ei ole sisselogimiseks vaja importida.\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Imporditavaid {mediaServerName} kasutajaid ei ole.\",\n  \"components.UserList.nouserstoimport\": \"Imporditavaid Plexi kasutajaid ei ole.\",\n  \"components.UserList.owner\": \"Omanik\",\n  \"components.UserList.password\": \"Parool\",\n  \"components.UserList.passwordinfodescription\": \"Automaatse parooligenerimise lubamiseks seadistage rakenduse URL ja lubage e-posti teavitused.\",\n  \"components.UserList.plexuser\": \"Plexi kasutaja\",\n  \"components.UserList.role\": \"Roll\",\n  \"components.UserList.sortCreated\": \"Liitumiskuupäev\",\n  \"components.UserList.sortDisplayName\": \"Kuvatav nimi\",\n  \"components.UserList.sortRequests\": \"Taotluste arv\",\n  \"components.UserList.totalrequests\": \"Taotlused\",\n  \"components.UserList.user\": \"Kasutaja\",\n  \"components.UserList.usercreatedfailed\": \"Kasutaja loomisel läks midagi valesti.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Sisestatud e-posti aadress on juba teise kasutaja poolt kasutusel.\",\n  \"components.UserList.usercreatedsuccess\": \"Kasutaja on edukalt loodud!\",\n  \"components.UserList.userdeleted\": \"Kasutaja on edukalt kustutatud!\",\n  \"components.UserList.userdeleteerror\": \"Kasutaja kustutamisel läks midagi valesti.\",\n  \"components.UserList.userfail\": \"Kasutaja õiguste salvestamisel läks midagi valesti.\",\n  \"components.UserList.userlist\": \"Kasutajate nimekiri\",\n  \"components.UserList.username\": \"Kasutajanimi\",\n  \"components.UserList.users\": \"Kasutajad\",\n  \"components.UserList.userssaved\": \"Kasutaja õigused on edukalt salvestatud!\",\n  \"components.UserList.validationEmail\": \"E-posti aadress on nõutav\",\n  \"components.UserList.validationUsername\": \"Pead sisestama kasutajanime\",\n  \"components.UserList.validationpasswordminchars\": \"Parool on liiga lühike; see peab olema vähemalt 8 märki pikk\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Liitus: {joindate}\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Vaata profiili\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Muuda seadeid\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Kasutaja ID: {userid}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Sisesta oma {mediaServerName} andmed, et linkida oma konto rakendusega {applicationName}.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"See konto on juba lingitud rakenduse {applicationName} kasutajaga\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Sinu andmetega ei õnnestunud luua ühendust serveriga {mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Ilmnes tundmatu viga\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Parool\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Pead sisestama parooli\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Lingi\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Lisamine…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Lingi {mediaServerName} konto\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Kasutajanimi\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Pead sisestama kasutajanime\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Konto tüüp\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administraator\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Kuvakeel\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discordi kasutaja ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Sinu Discordi kasutajakontoga seotud <FindDiscordIdLink>mitmekohaline ID-number</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Avastamise piirkond\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Filtreeri sisu piirkondliku kättesaadavuse järgi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Kuvatav nimi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-post\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Kirjuta globaalne piirang üle\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Üldine\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Üldised seaded\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Vaikimisi ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Kohalik kasutaja\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName} kasutaja\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Filmitaotluste piirang\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Avastamise keel\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtreeri sisu originaalkeele järgi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Omanik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plexi kasutaja\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Taotle filme automaatselt\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Taotle automaatselt filme, mis on lisatud sinu <PlexWatchlistSupportLink>Plexi sooviloendisse</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Taotle sarju automaatselt\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Taotle automaatselt sarju, mis on lisatud sinu <PlexWatchlistSupportLink>Plexi sooviloendisse</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Avastamise piirkond\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtreeri sisu piirkondliku kättesaadavuse järgi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Roll\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Salvesta muudatused\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Salvestamine…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Sarjataotluste piirang\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Voogedastuse piirkond\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Näita voogedastusplatvorme piirkondliku kättesaadavuse järgi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Seadete salvestamisel läks midagi valesti.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"See e-posti aadress on juba kasutusel!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"See kasutajanimi on juba teise kasutaja poolt võetud. Pead lisama e-posti aadressi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Seaded on edukalt salvestatud!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Kasutaja\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Pead sisestama kehtiva Discordi kasutaja ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Vajalik on kehtiv e-posti aadress\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"E-posti aadress on nõutav\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Lingitud konto kustutamine ebaõnnestus.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Ilmnes tundmatu viga\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Lingitud kontod\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Need välised kontod on lingitud sinu {applicationName} kontoga.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Sinu kontoga pole lingitud ühtegi välist kontot.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Sul puuduvad õigused selle kasutaja lingitud kontode muutmiseks.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"See konto on juba lingitud Plexi kasutajaga\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Sinu andmetega ei õnnestunud Plexiga ühendust luua\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Aktiivne tellimus\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Brauser\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Loodud\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Kustuta tellimus\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Seade\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Lülita veebitõuketeated välja\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Veebitõuketeadete väljalülitamisel läks midagi valesti.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Lülita veebitõuketeated sisse\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Veebitõuketeadete sisselülitamisel läks midagi valesti.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Mootor\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Halda seadmeid\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Sul pole ühtegi kuvatavat veebitõuketeadete tellimust.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Operatsioonisüsteem\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Tellimus kustutatud.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Kasutaja tellimuse kustutamisel läks midagi valesti.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"tüüp\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Tundmatu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Veebitõuketeated on välja lülitatud.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Veebitõuketeated on sisse lülitatud.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Veebitõuketeadete seadete salvestamine ebaõnnestus.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Veebitõuketeadete seaded on edukalt salvestatud!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Seadme vaikesäte\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Kasutaja ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"Sinu kasutajakontoga seotud <FindDiscordIdLink>mitmekohaline ID-number</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Discordi teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discordi teavituste seaded on edukalt salvestatud!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-post\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"E-posti teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"E-posti teavituste seaded on edukalt salvestatud!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Teavitused\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Teavituste seaded\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Avalik PGP-võti\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Krüpteeri e-kirjad, kasutades <OpenPgpLink>OpenPGP</OpenPgpLink>-d\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Juurdepääsuluba (Access Token)\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Loo luba oma <PushbulletSettingsLink>kontoseadetes</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Pushbulleti teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbulleti teavituste seaded on edukalt salvestatud!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Rakenduse API-luba\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registreeri rakendus</ApplicationRegistrationLink>, et kasutada seda koos rakendusega {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Kasutaja või grupi võti\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Sinu 30-kohaline <UsersGroupsLink>kasutaja või grupi identifikaator</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Pushoveri teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushoveri teavituste seaded on edukalt salvestatud!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Saada hääletult\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Saada teavitused ilma helita\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Teavituse heli\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Vestluse ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Alusta vestlust</TelegramBotLink>, lisa <GetIdBotLink>@get_id_bot</GetIdBotLink> ja sisesta käsk <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Lõime/teema ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Kui sinu grupivestluses on teemad (topics) lubatud, saad siin määrata konkreetse lõime või teema ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Telegrami teavituste seadete salvestamine ebaõnnestus.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegrami teavituste seaded on edukalt salvestatud!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Pead sisestama kehtiva kasutaja ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Pead sisestama kehtiva avaliku PGP-võtme\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Pead sisestama juurdepääsuloa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Pead sisestama kehtiva rakenduse loa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Pead sisestama kehtiva kasutaja või grupi võtme\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Pead sisestama kehtiva vestluse ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"Lõime/teema ID peab olema positiivne täisarv\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Veebitõuketeated\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Kinnita parool\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Praegune parool\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Uus parool\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Sellel kasutajakontol pole hetkel parooli määratud. Määra parool allpool, et võimaldada selle kontoga sisselogimist „kohaliku kasutajana.“\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Sinu kontol pole hetkel parooli määratud. Määra parool allpool, et saaksid oma e-posti aadressiga „kohaliku kasutajana“ sisse logida.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Sul puuduvad õigused selle kasutaja parooli muutmiseks.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Parool\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Parooli salvestamisel läks midagi valesti.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Parooli salvestamisel läks midagi valesti. Kas sisestasid oma praeguse parooli õigesti?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Parool on edukalt salvestatud!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Pead uue parooli kinnitama\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Paroolid peavad kattuma\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Pead sisestama oma praeguse parooli\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Pead sisestama uue parooli\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Parool on liiga lühike; see peab olema vähemalt 8 märki pikk\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Õigused\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Seadete salvestamisel läks midagi valesti.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Õigused on edukalt salvestatud!\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Sa ei saa muuta enda õigusi.\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Parool\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Üldine\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Lingitud kontod\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Teavitused\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Õigused\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Sul puuduvad õigused selle kasutaja seadete muutmiseks.\",\n  \"components.UserProfile.emptywatchlist\": \"Sinu <PlexWatchlistSupportLink>Plexi sooviloendisse</PlexWatchlistSupportLink> lisatud meedia ilmub siia.\",\n  \"components.UserProfile.limit\": \"{remaining} / {limit}\",\n  \"components.UserProfile.localWatchlist\": \"Kasutaja {username} sooviloend\",\n  \"components.UserProfile.movierequests\": \"Filmitaotlused\",\n  \"components.UserProfile.pastdays\": \"{type} (viimased {days} päeva)\",\n  \"components.UserProfile.plexwatchlist\": \"Plexi sooviloend\",\n  \"components.UserProfile.recentlywatched\": \"Hiljuti vaadatud\",\n  \"components.UserProfile.recentrequests\": \"Viimased taotlused\",\n  \"components.UserProfile.requestsperdays\": \"{limit} on jäänud\",\n  \"components.UserProfile.seriesrequest\": \"Sarjataotlused\",\n  \"components.UserProfile.totalrequests\": \"Taotlusi kokku\",\n  \"components.UserProfile.unlimited\": \"Piiramatu\",\n  \"i18n.addToBlocklist\": \"Lisa musta nimekirja\",\n  \"i18n.advanced\": \"Täpsemalt\",\n  \"i18n.all\": \"Kõik\",\n  \"i18n.approve\": \"Kiida heaks\",\n  \"i18n.approved\": \"Heaks kiidetud\",\n  \"i18n.areyousure\": \"Kas oled kindel?\",\n  \"i18n.available\": \"Saadaval\",\n  \"i18n.back\": \"Tagasi\",\n  \"i18n.blocklist\": \"Must nimekiri\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{{title}</strong> on juba mustas nimekirjas.\",\n  \"i18n.blocklistError\": \"Midagi läks valesti. Palun proovi uuesti.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> lisati edukalt musta nimekirja.\",\n  \"i18n.blocklisted\": \"Mustas nimekirjas\",\n  \"i18n.cancel\": \"Tühista\",\n  \"i18n.canceling\": \"Tühistamine…\",\n  \"i18n.close\": \"Sulge\",\n  \"i18n.collection\": \"Kogumik\",\n  \"i18n.completed\": \"Lõpetatud\",\n  \"i18n.decline\": \"Lükka tagasi\",\n  \"i18n.declined\": \"Tagasi lükatud\",\n  \"i18n.delete\": \"Kustuta\",\n  \"i18n.deleted\": \"Kustutatud\",\n  \"i18n.deleting\": \"Kustutamine…\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.edit\": \"Muuda\",\n  \"i18n.experimental\": \"Eksperimentaalne\",\n  \"i18n.failed\": \"Ebaõnnestus\",\n  \"i18n.import\": \"Impordi\",\n  \"i18n.importing\": \"Importimine…\",\n  \"i18n.loading\": \"Laadimine…\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.movies\": \"Filmid\",\n  \"i18n.next\": \"Järgmine\",\n  \"i18n.noresults\": \"Tulemusi ei leitud.\",\n  \"i18n.notrequested\": \"Pole taotletud\",\n  \"i18n.open\": \"Ava\",\n  \"i18n.partiallyavailable\": \"Osaliselt saadaval\",\n  \"i18n.pending\": \"Ootel\",\n  \"i18n.previous\": \"Eelmine\",\n  \"i18n.processing\": \"Töötlemine\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> eemaldati edukalt mustast nimekirjast.\",\n  \"i18n.removefromBlocklist\": \"Eemalda mustast nimekirjast\",\n  \"i18n.request\": \"Taotle\",\n  \"i18n.request4k\": \"Taotle 4K-s\",\n  \"i18n.requested\": \"Taotletud\",\n  \"i18n.requesting\": \"Taotlemine…\",\n  \"i18n.resolved\": \"Lahendatud\",\n  \"i18n.restartRequired\": \"Vajalik taaskäivitamine\",\n  \"i18n.resultsperpage\": \"Näita {pageSize} tulemust lehel\",\n  \"i18n.retry\": \"Proovi uuesti\",\n  \"i18n.retrying\": \"Uuesti proovimine…\",\n  \"i18n.save\": \"Salvesta muudatused\",\n  \"i18n.saving\": \"Salvestamine…\",\n  \"i18n.settings\": \"Seaded\",\n  \"i18n.showingresults\": \"Kuvatakse tulemused <strong>{from}</strong> - <strong>{to}</strong> kokku <strong>{total}</strong> tulemust\",\n  \"i18n.specials\": \"Eriosad\",\n  \"i18n.status\": \"Staatus\",\n  \"i18n.test\": \"Testi\",\n  \"i18n.testing\": \"Testimine…\",\n  \"i18n.tvshow\": \"Sari\",\n  \"i18n.tvshows\": \"Sarjad\",\n  \"i18n.unavailable\": \"Pole saadaval\",\n  \"i18n.usersettings\": \"Kasutaja seaded\",\n  \"i18n.view\": \"Vaata\",\n  \"pages.errormessagewithcode\": \"{statusCode} – {error}\",\n  \"pages.internalservererror\": \"Sisemine serveritõrge\",\n  \"pages.oops\": \"Oih\",\n  \"pages.pagenotfound\": \"Lehte ei leitud\",\n  \"pages.returnHome\": \"Tagasi avalehele\",\n  \"pages.serviceunavailable\": \"Teenus pole saadaval\",\n  \"pages.somethingwentwrong\": \"Midagi läks valesti\",\n  \"components.Discover.timeWindowDay\": \"Igapäevane\",\n  \"components.Discover.timeWindowWeek\": \"Iganädalane\"\n}\n"
  },
  {
    "path": "src/i18n/locale/eu.json",
    "content": "{\n  \"components.CollectionDetails.numberofmovies\": \"{count} film\",\n  \"components.CollectionDetails.overview\": \"Ikuspegi orokorra\",\n  \"components.AirDateBadge.airedrelative\": \"{relativeTime} igorrita\",\n  \"components.AirDateBadge.airsrelative\": \"{relativeTime} igortzen\",\n  \"components.Discover.CreateSlider.addSlider\": \"Gehitu irristaria\",\n  \"components.Discover.CreateSlider.addfail\": \"Irristari berria sortzeak huts egin du.\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Kendu\",\n  \"components.Discover.FilterSlideover.genres\": \"Generoak\",\n  \"components.Discover.FilterSlideover.keywords\": \"Gako-hitzak\",\n  \"components.Discover.FilterSlideover.runtime\": \"Iraupena\",\n  \"components.IssueDetails.comments\": \"Iruzkinak\",\n  \"components.IssueDetails.issuetype\": \"Mota\",\n  \"components.IssueDetails.leavecomment\": \"Iruzkindu\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Egoera\",\n  \"components.IssueList.IssueItem.issuetype\": \"Mota\",\n  \"components.IssueList.IssueItem.opened\": \"Irekita\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Ezezaguna\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueModal.issueOther\": \"Bestelakoa\",\n  \"components.IssueModal.issueVideo\": \"Bideoa\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmak\",\n  \"components.Layout.Sidebar.dashboard\": \"Aurkitu\",\n  \"components.Layout.Sidebar.issues\": \"Intzidentziak\",\n  \"components.Layout.Sidebar.requests\": \"Eskaerak\",\n  \"components.Layout.Sidebar.settings\": \"Ezarpenak\",\n  \"components.Layout.Sidebar.users\": \"Erabiltzaileak\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profila\",\n  \"components.Layout.UserDropdown.requests\": \"Eskaerak\",\n  \"components.Layout.UserDropdown.settings\": \"Ezarpenak\",\n  \"components.Login.initialsigningin\": \"Konektatzen…\",\n  \"components.Login.password\": \"Pasahitza\",\n  \"components.Login.port\": \"Ataka\",\n  \"components.Login.save\": \"Gehitu\",\n  \"components.Login.saving\": \"Gehitzen…\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Aurreratua\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Multimedia\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Eskaerak\",\n  \"components.ManageSlideOver.movie\": \"filma\",\n  \"components.MovieDetails.budget\": \"Aurrekontua\",\n  \"components.MovieDetails.cast\": \"Aktoreak\",\n  \"components.MovieDetails.recommendations\": \"Gomendioak\",\n  \"components.MovieDetails.revenue\": \"Bilduta\",\n  \"components.PermissionEdit.autoapprove\": \"Auto-onarpena\",\n  \"components.PermissionEdit.request\": \"Eskaera\",\n  \"components.PersonDetails.crewmember\": \"Taldea\",\n  \"components.QuotaSelector.unlimited\": \"Mugagabea\",\n  \"components.RequestList.RequestItem.profileName\": \"Profila\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Eskatuta\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Aurreratuak\",\n  \"components.ResetPassword.password\": \"Pasahitza\",\n  \"components.Selector.canceled\": \"Utzita\",\n  \"components.Selector.ended\": \"Bukatuta\",\n  \"components.Selector.planned\": \"Planifikatuta\",\n  \"components.Settings.RadarrModal.port\": \"Ataka\",\n  \"components.Settings.RadarrModal.released\": \"Kaleratuta\",\n  \"components.Settings.RadarrModal.tags\": \"Etiketak\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Azken bertsioa\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Bertsioak\",\n  \"components.Settings.SettingsAbout.about\": \"Honi buruz\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentazioa\",\n  \"components.Settings.SettingsAbout.version\": \"Bertsioa\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Kontsultak\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Hutsegiteak\",\n  \"components.Settings.SettingsJobsCache.command\": \"Komandoa\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Atazak\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Mota\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Arazketa\",\n  \"components.Settings.SettingsLogs.filterError\": \"Errorea\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Informazioa\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Oharra\",\n  \"components.Settings.SettingsLogs.label\": \"Etiketa\",\n  \"components.Settings.SettingsLogs.level\": \"Larritasuna\",\n  \"components.Settings.SettingsLogs.logs\": \"Erregistroak\",\n  \"components.Settings.SettingsLogs.message\": \"Mezua\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pausatu\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Jarraitu\",\n  \"components.Settings.SettingsLogs.time\": \"Denbora-zigilua\",\n  \"components.Settings.SonarrModal.port\": \"Ataka\",\n  \"components.Settings.address\": \"Helbidea\",\n  \"components.Settings.default\": \"Lehenetsia\",\n  \"components.Settings.menuAbout\": \"Honi buruz\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.menuLogs\": \"Erregistroak\",\n  \"components.Settings.menuNotifications\": \"Jakinarazpenak\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Zerbitzuak\",\n  \"components.Settings.menuUsers\": \"Erabiltzaileak\",\n  \"components.Settings.notifications\": \"Jakinarazpenak\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.saving\": \"Gordetzen…\",\n  \"components.Settings.scanning\": \"Sinkronizatzen…\",\n  \"components.Settings.serverLocal\": \"lokala\",\n  \"components.Settings.serverRemote\": \"urrunekoa\",\n  \"components.Settings.serverSecure\": \"segurua\",\n  \"components.Settings.serverpreset\": \"Zerbitzaria\",\n  \"components.Settings.services\": \"Zerbitzuak\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.tip\": \"Aholkua\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Setup.continue\": \"Jarraitu\",\n  \"components.Setup.finishing\": \"Amaitzen…\",\n  \"components.Setup.setup\": \"Konfigurazioa\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.TvDetails.anime\": \"Animea\",\n  \"components.TvDetails.cast\": \"Aktoreak\",\n  \"components.TvDetails.recommendations\": \"Gomendioak\",\n  \"components.TvDetails.seasonstitle\": \"Denboraldiak\",\n  \"components.UserList.accounttype\": \"Mota\",\n  \"components.UserList.create\": \"Sortu\",\n  \"components.UserList.created\": \"Bat eginda\",\n  \"components.UserList.creating\": \"Sortzen…\",\n  \"components.UserList.owner\": \"Jabea\",\n  \"components.UserList.password\": \"Pasahitza\",\n  \"components.UserList.role\": \"Rola\",\n  \"components.UserList.user\": \"Erabiltzailea\",\n  \"components.UserList.username\": \"Erabiltzaile-izena\",\n  \"components.UserList.users\": \"Erabiltzaileak\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-posta\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Orokorra\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Jabea\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Gordetzen…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Erabiltzailea\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Jakinarazpenak\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Pasahitza\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Orokorra\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Jakinarazpenak\",\n  \"components.UserProfile.unlimited\": \"Mugagabeak\",\n  \"i18n.advanced\": \"Aurreratua\",\n  \"i18n.all\": \"Denak\",\n  \"i18n.approve\": \"Onartu\",\n  \"i18n.available\": \"Eskuragarri\",\n  \"i18n.back\": \"Itzuli\",\n  \"i18n.cancel\": \"Utzi\",\n  \"i18n.canceling\": \"Uzten…\",\n  \"i18n.close\": \"Itxi\",\n  \"i18n.collection\": \"Bilduma\",\n  \"i18n.decline\": \"Uko egin\",\n  \"i18n.declined\": \"Ukatuta\",\n  \"i18n.delete\": \"Ezabatu\",\n  \"i18n.edit\": \"Editatu\",\n  \"i18n.experimental\": \"Esperimentala\",\n  \"i18n.failed\": \"Huts egin du\",\n  \"i18n.import\": \"Inportatu\",\n  \"i18n.importing\": \"Inportatzen…\",\n  \"i18n.loading\": \"Kargatzen…\",\n  \"i18n.movie\": \"Filma\",\n  \"i18n.movies\": \"Filmak\",\n  \"i18n.next\": \"Aurrera\",\n  \"i18n.open\": \"Ireki\",\n  \"i18n.pending\": \"Zain\",\n  \"i18n.previous\": \"Aurrekoa\",\n  \"i18n.request\": \"Eskatu\",\n  \"i18n.requested\": \"Eskatuta\",\n  \"i18n.requesting\": \"Eskatzen…\",\n  \"i18n.resolved\": \"Ebatzita\",\n  \"i18n.retry\": \"Saiatu berriro\",\n  \"i18n.retrying\": \"Berriro saiatzen…\",\n  \"i18n.saving\": \"Gordetzen…\",\n  \"i18n.settings\": \"Ezarpenak\",\n  \"i18n.specials\": \"Bereziak\",\n  \"i18n.test\": \"Frogatu\",\n  \"i18n.testing\": \"Frogatzen…\",\n  \"i18n.unavailable\": \"Ez dago\",\n  \"i18n.view\": \"Ikusi\",\n  \"pages.oops\": \"Ai!\",\n  \"components.CollectionDetails.requestcollection\": \"Eskatu bilduma\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Gehigarriak\",\n  \"components.MovieDetails.overview\": \"Ikuspegi orokorra\",\n  \"components.PermissionEdit.autorequest\": \"Auto-eskaera\",\n  \"components.PersonDetails.appearsin\": \"Agerraldiak\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"filmak\",\n  \"components.Selector.pilot\": \"Pilotoa\",\n  \"components.Settings.RadarrModal.announced\": \"Iragarrita\",\n  \"components.Settings.timeout\": \"Denbora-muga\",\n  \"components.UserList.admin\": \"Administratzailea\",\n  \"components.UserList.totalrequests\": \"Eskaerak\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-posta\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Baimenak\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmak\",\n  \"components.CollectionDetails.requestcollection4k\": \"Eskatu bilduma 4K-n\",\n  \"components.IssueDetails.issuepagetitle\": \"Intzidentzia\",\n  \"components.IssueList.issues\": \"Intzidentziak\",\n  \"components.ManageSlideOver.downloadstatus\": \"Deskargaren egoera\",\n  \"components.PermissionEdit.admin\": \"Administratzailea\",\n  \"components.RequestList.requests\": \"Eskaerak\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Etiketak\",\n  \"components.RequestModal.QuotaDisplay.season\": \"denboraldia\",\n  \"components.Search.search\": \"Bilatu\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Unekoa\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Sortu irristari pertsonalizatua\",\n  \"components.Discover.CreateSlider.editSlider\": \"Editatu irristaria\",\n  \"components.IssueDetails.unknownissuetype\": \"Ezezaguna\",\n  \"components.Login.username\": \"Erabiltzaile-izena\",\n  \"components.Settings.Notifications.encryptionNone\": \"Bat ere ez\",\n  \"components.Settings.SettingsUsers.users\": \"Erabiltzaileak\",\n  \"components.Settings.email\": \"E-posta\",\n  \"components.Settings.mediaTypeMovie\": \"filma\",\n  \"components.Settings.port\": \"Ataka\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Pasahitza\",\n  \"i18n.deleting\": \"Ezabatzen…\",\n  \"i18n.processing\": \"Prozesatzen\",\n  \"components.Discover.FilterSlideover.filters\": \"Iragazkiak\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Telesailak\",\n  \"components.IssueModal.issueSubtitles\": \"Azpititulua\",\n  \"components.Login.initialsignin\": \"Konektatu\",\n  \"components.RequestList.RequestItem.modified\": \"Aldatuta\",\n  \"components.RequestList.RequestItem.requested\": \"Eskatuta\",\n  \"components.RequestModal.season\": \"Denboraldia\",\n  \"components.Settings.SettingsMain.general\": \"Orokorra\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Baimenak\",\n  \"i18n.status\": \"Egoera\",\n  \"components.Discover.FilterSlideover.status\": \"Egoera\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cachea\",\n  \"components.Settings.SettingsJobsCache.process\": \"Prozesua\",\n  \"components.Settings.SonarrModal.tags\": \"Etiketak\",\n  \"components.Settings.menuGeneralSettings\": \"Orokorra\",\n  \"components.Settings.syncing\": \"Sinkronizatzen\",\n  \"components.TvDetails.overview\": \"Ikuspegi orokorra\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administratzailea\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rola\",\n  \"i18n.approved\": \"Onartuta\",\n  \"components.Discover.CreateSlider.nooptions\": \"Emaitzarik ez.\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Bilatu generoak…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Bilatu estudioak…\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} filmak\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} filmak\",\n  \"components.Discover.FilterSlideover.studio\": \"Estudioa\",\n  \"components.Discover.studios\": \"Estudioak\",\n  \"components.IssueDetails.IssueDescription.description\": \"Deskribapena\",\n  \"components.Layout.Sidebar.browsetv\": \"Telesailak\",\n  \"components.ManageSlideOver.tvshow\": \"telesailak\",\n  \"components.Settings.mediaTypeSeries\": \"telesaila\",\n  \"i18n.tvshow\": \"Telesailak\",\n  \"i18n.tvshows\": \"Telesailak\",\n  \"components.Discover.StudioSlider.studios\": \"Estudioak\",\n  \"components.Discover.networks\": \"Sareak\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Aukeran, barne eta kanpo-konexioko puntuak konfiguratu {mediaServerName} zerbitzariarentzat. Kasu gehienetan, kanpoko URLa barnekoaren desberdina da. Era berean, pasahitza berrezartzeko URL pertsonalizatu bat ezar daiteke {mediaServerName} saioaren hasierarako, pasahitz desberdin bat berrezartzeko orri bat nahi baduzu. Jellyfinen API gakoa ere aldatu daiteke, lehenago automatikoki sortua.\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Zure jarraipenak\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex jarraipen-zerrenda\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Jatorrizko hizkuntza\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Argitalpen data\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streaming zerbitzuak\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Film generoak\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Film generoak\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Zure jarraipenak\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Duela gutxi gehituta\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Telesailen generoak\",\n  \"components.Discover.tmdbstudio\": \"TMDB Estudioa\",\n  \"components.Discover.tvgenres\": \"Telesailen generoak\",\n  \"components.Discover.upcoming\": \"Hurrengo filmak\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Ezabatu intzidentzia\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Editatu deskribapena\",\n  \"components.IssueDetails.allepisodes\": \"Atal guztiak\",\n  \"components.IssueDetails.allseasons\": \"Denboraldi guztiak\",\n  \"components.IssueDetails.closeissue\": \"Itxi intzidentzia\",\n  \"components.IssueDetails.deleteissue\": \"Ezabatu intzidentzia\",\n  \"components.IssueDetails.episode\": \"{episodeNumber} atala\",\n  \"components.IssueDetails.lastupdated\": \"Azken eguneraketa\",\n  \"components.IssueDetails.nocomments\": \"Iruzkinik ez.\",\n  \"components.IssueDetails.reopenissue\": \"Ireki intzidentzia berriro\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Kaltetutako atala\",\n  \"components.IssueList.IssueItem.viewissue\": \"Ikusi intzidentzia\",\n  \"components.IssueList.sortAdded\": \"Azkenak\",\n  \"components.IssueList.sortModified\": \"Azkenik aldatuak\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Atal guztiak\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Denboraldi guztiak\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"{episodeNumber} atala\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Kaltetutako atala\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Kaltetutako denboraldia\",\n  \"components.IssueModal.CreateIssueModal.season\": \"{seasonNumber} denboraldia\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Bidali intzidentzia\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Ikusi intzidentzia\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Zer gertatzen da?\",\n  \"components.LanguageSelector.languageServerDefault\": \"({language}) lehenetsia\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Hizkuntza guztiak\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Bistaratzeko hizkuntza\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Film eskaerak\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Telesail eskaerak\",\n  \"components.Layout.UserDropdown.signout\": \"Itxi saioa\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Develop\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stable\",\n  \"components.Login.back\": \"Itzuli\",\n  \"components.Login.email\": \"Helbide elektronikoa\",\n  \"components.Login.enablessl\": \"Erabili SSL\",\n  \"components.Login.forgotpassword\": \"Pasahitza ahaztu duzu?\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.servertype\": \"Zerbitzari mota\",\n  \"components.Login.signin\": \"Hasi saioa\",\n  \"components.Login.signingin\": \"Saioa hasten…\",\n  \"components.Login.title\": \"Gehitu e-posta\",\n  \"components.Login.urlBase\": \"Oinarrizko URLa\",\n  \"components.Login.validationEmailFormat\": \"Helbide elektroniko hau baliogabea da\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Honek {mediaType}-ko datu guztiak betirako ezabatuko ditu, eskaera guztiak barne. Elementu hau {mediaServerName} liburutegian badago, edukiaren informazioa hurrengo eskanerrean birsortuko da.\",\n  \"components.Login.validationusernamerequired\": \"Erabiltzaile-izen bat behar da\",\n  \"components.ManageSlideOver.alltime\": \"Denbora guztia\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Garbitu datuak\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Irekitako intzidentziak\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K edukia\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Eskaerarik ez.\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Kudeatu {mediaType}\",\n  \"components.ManageSlideOver.playedby\": \"Honek erreproduzituta\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Ikusi gehiago\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Aktore guztiak\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Talde guztiak\",\n  \"components.MovieDetails.digitalrelease\": \"Argitalpen digitala\",\n  \"components.MovieDetails.downloadstatus\": \"Deskargaren egoera\",\n  \"components.MovieDetails.managemovie\": \"Kudeatu filma\",\n  \"components.MovieDetails.originallanguage\": \"Jatorrizko hizkuntza\",\n  \"components.MovieDetails.originaltitle\": \"Jatorrizko izenburua\",\n  \"components.MovieDetails.overviewunavailable\": \"Ikuspegi orokorra ez dago eskuragarri.\",\n  \"components.MovieDetails.physicalrelease\": \"Argitalpen fisikoa\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutu\",\n  \"components.MovieDetails.showless\": \"Erakutsi gutxiago\",\n  \"components.MovieDetails.showmore\": \"Erakutsi gehiago\",\n  \"components.MovieDetails.watchtrailer\": \"Ikusi trailerra\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Intzidentziaren iruzkina\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Intzidentzia bidalita\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Intzidentzia berriro irekita\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Intzidentzia konponduta\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Eskaera onartuta\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Eskaera eskuragarri\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Jakinarazpen motak\",\n  \"components.PermissionEdit.advancedrequest\": \"Eskaera aurreratuak\",\n  \"components.PermissionEdit.autoapprove4k\": \"Auto-onartu 4K\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Auto-onartu filmak\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Auto-onartu telesailak\",\n  \"components.PermissionEdit.autorequestMovies\": \"Auto-eskatu filmak\",\n  \"components.PermissionEdit.createissues\": \"Bidali intzidentziak\",\n  \"components.PermissionEdit.manageissues\": \"Kudeatu intzidentziak\",\n  \"components.PermissionEdit.managerequests\": \"Kudeatu eskaerak\",\n  \"components.PermissionEdit.request4k\": \"Eskatu 4K\",\n  \"components.PermissionEdit.requestMovies\": \"Eskatu filmak\",\n  \"components.PermissionEdit.requestTv\": \"Eskatu telesailak\",\n  \"components.PermissionEdit.users\": \"Kudeatu erabiltzaileak\",\n  \"components.PermissionEdit.viewissues\": \"Ikusi intzidentziak\",\n  \"components.PermissionEdit.viewrequests\": \"Ikusi eskaerak\",\n  \"components.PersonDetails.ascharacter\": \"{character} gisa\",\n  \"components.PersonDetails.birthdate\": \"{birthdate}(e)an jaiota\",\n  \"components.RequestBlock.approve\": \"Onartu eskaera\",\n  \"components.RequestBlock.decline\": \"Ukatu eskaera\",\n  \"components.RequestBlock.delete\": \"Ezabatu eskaera\",\n  \"components.RequestBlock.edit\": \"Editatu eskaera\",\n  \"components.RequestBlock.languageprofile\": \"Hizkuntza profila\",\n  \"components.RequestBlock.profilechanged\": \"Kalitate profila\",\n  \"components.RequestBlock.requestdate\": \"Eskaera data\",\n  \"components.RequestBlock.requestedby\": \"Honek eskatuta\",\n  \"components.RequestBlock.requestoverrides\": \"Eskaera anulazioak\",\n  \"components.RequestButton.approverequest\": \"Onartu eskaera\",\n  \"components.RequestButton.declinerequest\": \"Ukatu eskaera\",\n  \"components.RequestButton.requestmore\": \"Eskatu gehiago\",\n  \"components.RequestButton.viewrequest\": \"Ikusi eskaera\",\n  \"components.RequestCard.approverequest\": \"Onartu eskaera\",\n  \"components.RequestCard.cancelrequest\": \"Utzi eskaera\",\n  \"components.RequestCard.declinerequest\": \"Ukatu eskaera\",\n  \"components.RequestCard.deleterequest\": \"Ezabatu eskaera\",\n  \"components.RequestCard.editrequest\": \"Editatu eskaera\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestCard.unknowntitle\": \"Izenburu ezezaguna\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Utzi eskaera\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Ezabatu eskaera\",\n  \"components.RequestList.RequestItem.editrequest\": \"Editatu eskaera\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Izenburu ezezaguna\",\n  \"components.RequestList.sortAdded\": \"Azkenak\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Lehenetsia)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Helburuko zerbitzaria\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Hizkuntza profila\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Kalitate profila\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Hautatu etiketak\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Gutxienez <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} erabilgarri izan behar duzu/dituzu telesail honetarako eskaera bat bidaltzeko.\",\n  \"components.RequestModal.alreadyrequested\": \"Eskatuta dagoeneko\",\n  \"components.RequestModal.approve\": \"Onartu eskaera\",\n  \"components.RequestModal.autoapproval\": \"Onarpen automatikoa\",\n  \"components.RequestModal.cancel\": \"Utzi eskaera\",\n  \"components.RequestModal.edit\": \"Editatu eskaera\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Seerr-en <code>garapen</code> adarra exekutatzen ari zara, garapenean laguntzen duten edo \\\"bleeding-edge\\\" probetan laguntzen dutenentzat bakarrik gomendatzen dena.\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Ezarpenetan gaituta dagoenean, Seerr-ek aurrez konfiguratutako kanpoko iturrietatik proxya egin eta irudiak cacheatuko ditu. Cachean gordetako irudiak zure konfigurazio karpetan gordetzen dira. Fitxategiak <code>{appDataPath}/cache/images</code> bide-izenean aurki ditzakezu.\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr-ek mantentze-lan batzuk egiten ditu aldizka programatutako lan gisa, baina behean eskuz ere abiarazi daitezke. Lan bat eskuz exekutatzeak ez du bere programazioa aldatuko.\",\n  \"components.Settings.manualscanDescription\": \"Normalean, hau 24 orduz behin bakarrik egingo da. Seerr-ek zure Plex zerbitzariaren berriki gehitutakoak gehiagotan egiaztatuko dira. Plex konfiguratzen duzun lehen aldia bada, liburutegi osoa eskuz eskaneatzea gomendatzen da!\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalean, hau 24 orduz behin bakarrik egingo da. Seerr-ek zure {mediaServerName} zerbitzariaren berriki gehitutakoak gehiagotan egiaztatuko dira. Jellyseerr konfiguratzen duzun lehen aldia bada, liburutegi osoa eskuz eskaneatzea gomendatzen da!\",\n  \"components.Settings.noDefaultNon4kServer\": \"{serverType} zerbitzari bakarra baduzu 4K eta ez-4K edukirako (edo 4k edukia soilik deskargatzen baduzu), zure {serverType} zerbitzaria <strong>EZ</strong> da 4k zerbitzari gisa markatu behar.\",\n  \"components.Settings.settingUpPlexDescription\": \"Plex konfiguratzeko, xehetasunak eskuz sartu edo <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>-tik lortutako zerbitzari bat hauta dezakezu. Sakatu goitibeherako menuaren eskuinean dagoen botoia erabilgarri dauden zerbitzariak lortzeko.\",\n  \"components.Settings.plexlibrariesDescription\": \"Seerr-ek eskaneatuko dituen liburutegiak. Konfiguratu eta gorde zure Plex konexioaren ezarpenak, eta egin klik beheko botoian liburutegirik zerrendatzen ez bada.\",\n  \"components.UserList.newJellyfinsigninenabled\": \"<strong>Gaitu {mediaServerName} saio-hasiera berria</strong> ezarpena gaituta dago une honetan. Liburutegirako sarbidea duten {mediaServerName} erabiltzaileak ez dira inportatu behar saioa hasteko.\",\n  \"components.UserList.newplexsigninenabled\": \"<strong>Gaitu Plex-en saioa hasteko modu berria</strong> ezarpena gaituta dago une honetan. Liburutegirako sarbidea duten Plex erabiltzaileak ez dira inportatu behar saioa hasteko.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Zure kontuak ez du pasahitzik ezarrita. Konfiguratu pasahitz bat behean kontu hau \\\"erabiltzaile lokal\\\" gisa saioa hasteko zure helbide elektronikoa erabiliz.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Erabiltzaile honek gutxienez <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} erabilgarri izan behar du/ditu telesail honetarako eskaera bat bidaltzeko.\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Telesailak\",\n  \"components.IssueDetails.problemepisode\": \"Kaltetutako atala\",\n  \"components.IssueDetails.season\": \"{seasonNumber} denboraldia\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Eskatu erabiltzaile honen izenean\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Erabiltzaile-kontu honek ez du pasahitzik ezarrita. Konfiguratu pasahitz bat behean kontu hau \\\"erabiltzaile lokal\\\" gisa saioa hasi dezan.\",\n  \"components.IssueDetails.IssueComment.edit\": \"Editatu iruzkina\",\n  \"components.IssueDetails.problemseason\": \"Kaltetutako denboraldia\",\n  \"components.RequestList.sortModified\": \"Azkenekoz aldatutakoak\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Telesailen generoak\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Eskaera ukatuta\",\n  \"components.PermissionEdit.autorequestSeries\": \"Auto-eskatu telesailak\",\n  \"components.MovieDetails.theatricalrelease\": \"Zineman argitaratuta\",\n  \"components.RequestBlock.server\": \"Helburuko zerbitzaria\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Etiketarik gabe.\",\n  \"components.Settings.serviceSettingsDescription\": \"Konfiguratu zure {serverType} zerbitzaria(k) jarraian. Hainbat {serverType} zerbitzari konekta ditzakezu, baina horietako bi bakarrik markatu daitezke lehetsi gisa (bata 4K eta bestea 4K ez dena). Administratzaileek eskaera berriak prozesatzeko erabilitako zerbitzaria baliogabetu dezakete onartu aurretik.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Eduki-eskaerak kudeatzeko baimenak ematen ditu. Baimen hau duen erabiltzaile baten eskaera guztiak automatikoki onartuko dira.\",\n  \"components.Settings.noDefault4kServer\": \"{serverType}-(e)ko 4K zerbitzari bat lehenetsi behar da erabiltzaileen {mediaType}-(e)ko 4K eskaerak gaitu ahal izateko.\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Pasahitza berrezartzeko esteka bat adierazitako helbide elektronikora bidaliko da, erabiltzaile baliozko bati lotuta badago.\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code> bolumenaren muntaia ez da behar bezala konfiguratu. Datu guztiak ezabatu egingo dira edukiontzia gelditu edo berriro hasten denean.\",\n  \"components.Login.description\": \"{applicationName} aplikazioan saioa hasten duzun lehen aldia denez, baliozko helbide elektroniko bat gehitu behar duzu.\",\n  \"components.PermissionEdit.usersDescription\": \"Eman baimena erabiltzaileak kudeatzeko. Baimen hau duten erabiltzaileek ezin dituzte administratzaile-pribilegioa duten erabiltzaileak aldatu edo pribilegio hau eman.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr-ek kanpoko APIaren eskaerak cachean gordetzen ditu, errendimendua optimizatzeko eta beharrezkoak ez diren API deirik ez egiteko.\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Konfiguratu zerbitzarirako doikuntzak {mediaServerName}-(e)rako. {mediaServerName} liburutegiak eskaneatzen ditu, zer eduki dagoen ikusteko.\",\n  \"components.Settings.noDefaultServer\": \"Gutxienez {serverType} zerbitzari bat lehenetsi gisa markatu behar da {mediaType} eskaerak prozesatu ahal izateko.\",\n  \"components.Settings.tautulliSettingsDescription\": \"Aukeran, konfiguratu zure Tautulli zerbitzariaren ezarpenak. Seerr-ek Tautulliren Plex multimedia erreprodukzioen historialaren datuak lortu ditu.\",\n  \"components.Settings.plexsettingsDescription\": \"Konfiguratu zure Plex zerbitzariaren ezarpenak. Seerr-ek zure Plexeko liburutegiak eskaneatzen ditu edukiaren erabilgarritasuna zehazteko.\",\n  \"components.Settings.webAppUrlTip\": \"Aukeran erabiltzaileak zure zerbitzariko web aplikaziora zuzendu, web-aplikazio \\\"ostatuaren\\\" ordez\",\n  \"components.UserList.deleteconfirm\": \"Ziur al zaude erabiltzaile hau ezabatu nahi duzula? Bere eskaera guztiak betirako ezabatuko dira.\",\n  \"components.Login.emailtooltip\": \"Helbidea ez da zertan zure {mediaServerName} instantziari lotu behar.\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Honek {mediaType} hau betirako ezabatuko du {arr}(e)tik, fitxategi guztiak barne.\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Bidali jakinarazpenak multimedia eskaerak Radarr eta Sonarr-en gehitzeak huts egiten badu.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Jakinarazi beste erabiltzaileek automatikoki onartzen diren multimedia eskaera berriak bidaltzen dituztenean.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Jakinarazi multimedia eskaerak Radarr edo Sonarr-en gehitzen ez direnean.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Bidali jakinarazpenak erabiltzaileek automatikoki onartzen diren multimedia eskaera berriak bidaltzen dituztenean.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Jakinarazi beste erabiltzaile batzuek onartu beharreko multimedia eskaerak bidaltzen dituztenean.\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Bidali jakinarazpenak erabiltzaileek onarpena behar duten multimedia eskaera berriak bidaltzen dituztenean.\",\n  \"components.PermissionEdit.autorequestDescription\": \"Baimendu Plexen jarraipen-zerrendaren bidez 4K ez diren eskaerak automatikoki bidaltzeko.\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Baimendu Plexen jarraipen-zerrendaren bidez 4K ez diren film eskaerak automatikoki bidaltzeko.\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Baimendu Plexen jarraipen-zerrendaren bidez 4K ez diren telesail eskaerak automatikoki bidaltzeko.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Ezin izan dugu telesail hau automatikoki lotu. Mesedez, hautatu bat datorrena azpian.\",\n  \"components.Settings.Notifications.chatIdTip\": \"Hasi txat bat zure bot-arekin, gehitu <GetIdBotLink>@get_id_bot</GetIdBotLink> eta egin <code>/my_id</code> komandoa\",\n  \"components.Settings.Notifications.encryptionTip\": \"Kasu gehienetan, TLS inplizituak 465 portua eta STARTTLSk 587 portua erabiltzen dute\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Gehitu etiketa gehigarri bat automatikoki eskaeraren erabiltzaile ID eta erabiltzaile-izenarekin\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Erregistro horiek zuzenean ikus ditzakezu <code>stdout</code> edo <code>{appDataPath}/logs/seerr.log</code> bidez.\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Gehitu etiketa gehigarri bat automatikoki eskaeraren erabiltzaile ID eta erabiltzaile-izenarekin\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr berrabiarazi egin behar da aldaketa hauek indarrean jartzeko\",\n  \"components.UserList.passwordinfodescription\": \"Konfiguratu aplikazioaren URL bat eta gaitu posta elektronikoko jakinarazpenak pasahitz sortze automatikoa ahalbidetzeko.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Arazoren bat izan da pasahitza gordetzean. Zure uneko pasahitza behar bezala sartu duzu?\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"Webhook mezuan aipatu beharreko rolaren IDa. Utzi hutsik aipamenak desgaitzeko\",\n  \"components.Discover.resetwarning\": \"Berrezarri kontrol irristari guztiak modu lehenetsira. Honek kontrol irristari pertsonalizatuak ere ezabatuko ditu!\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Zure eskaera-mugen laburpena ikus dezakezu zure <ProfileLink>profil-orrian</ProfileLink>.\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Web push jakinarazpenak jasotzeko, Seerr HTTPS bidez zerbitzatu behar da.\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {Gaitutako iragazki #} other {Gaitutako # iragazki}}\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {Gaitutako iragazki #} other {Gaitutako # iragazki}}\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {Gaitutako iragazki #} other {Gaitutako # iragazki}}\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Mesedez, eman aurkitu duzun arazoaren azalpen zehatza.\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Jakinarazi multimedia eskaera berriak automatikoki bidaltzen direnean zure jarraipen-zerrendan.\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Baimendu beste erabiltzaileek sortutako multimedia arazoak ikustea.\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Baimendu orain dela gutxi gehitutako multimedia-zerrenda ikustea.\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Baimendu beste erabiltzaile batzuek bidalitako bitarteko-eskaerak ikustea.\",\n  \"components.RequestButton.approve4krequests\": \"Onartu {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.decline4krequests\": \"Ukatu {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"<strong> {limit} </strong> {type} eskaera egin ditzakezu <strong>{days}</strong> egunero.\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Ezin izan da telesail honetarako bat-etortze bat aurkitu.\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Pasahitza laburregia da; gutxienez 8 karaktere izan beharko lituzke\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Baimendu erabiltzaileei zure bot-ekin txat bat hasi eta jakinarazpenak konfiguratzen\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Kanpotik ateratako irudiak cacheatu (biltegi kantitate handia behar du)\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"{mediaServerName}-(e)k eskaneatzen dituen liburutegiak. Egin klik beheko botoian liburutegirik zerrendatzen ez bada.\",\n  \"components.Settings.scanbackground\": \"Eskaneatzea atzeko planoan egongo da. Bitartean konfigurazio prozesua jarraitu dezakezu.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Emandako helbide elektronikoa dagoeneko beste erabiltzaile batek darabil.\",\n  \"components.UserList.validationpasswordminchars\": \"Pasahitza laburregia da; gutxienez 8 karaktere izan beharko lituzke\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Beste erabiltzaile batek dagoeneko erabiltzaile-izen hori du. Helbide elektronikoa ezarri behar duzu\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Ez duzu baimenik erabiltzaile honen pasahitza aldatzeko.\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Ez duzu baimenik erabiltzaile honen ezarpenak aldatzeko.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Pasahitza laburregia da; gutxienez 8 karaktere izan beharko lituzke\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Baimendu erabiltzaileei haien helbide elektronikoa eta pasahitza erabiliz saioa hasten\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Erabiltzaile honek <strong> {limit} </strong> {type} eskaera egin ditzake <strong>{days}</strong> egunero.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Erabiltzailearen eskaera-mugen laburpena ikus dezakezu <ProfileLink> profil orrian</ProfileLink>.\",\n  \"components.RequestModal.requestmovies4k\": \"Eskatu {count} {count, plural, one {film} other {film}} 4K-n\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {0} other {<strong>#</strong>}} {type} {remaining, plural, one {eskaera} other {eskaera}} geratzen dira\",\n  \"components.Discover.CreateSlider.needresults\": \"Gutxienez emaitza 1 behar duzu.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Irristaria editatuta eta pertsonalizazio ezarpenak gordeta.\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Zure <PlexWatchlistSupportLink>Plex jarraipen-zerrendara</PlexWatchlistSupportLink> gehitutako multimedia hemen agertuko da.\",\n  \"components.Discover.emptywatchlist\": \"Zure <PlexWatchlistSupportLink>Plex jarraipen-zerrendara</PlexWatchlistSupportLink> gehitutako multimedia hemen agertuko da.\",\n  \"components.Discover.resetfailed\": \"Zerbait gaizki atera da pertsonalizazioaren konfigurazioa berrezartzean.\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Ziur zaude iruzkin hau ezabatu nahi duzula?\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Ziur zaude intzidentzia hau ezabatu nahi duzula?\",\n  \"components.Login.adminerror\": \"Administratzaile kontu bat erabili behar duzu saioa hasteko.\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"URLa ez du amaierako barra batean amaitu behar\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Jakinarazi beste erabiltzaile batzuek intzidentziak berriro irekitzen dituztenean.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Jakinarazi beste erabiltzaile batzuek intzidentziak konpontzen dituztenean.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Jakinarazki intzidentziak iruzkin berriak jasotzen dituztenean.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Gutxienez jakinarazpen mota bat aukeratu behar duzu\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Erregistratu aplikazio bat</ApplicationRegistrationLink> Seerr-en erabiltzeko\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Baliozko aplikazio token bat eman behar duzu\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Baliozko JSON edukia eman behar duzu\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Web push proba jakinarazpena bidaltzeak huts egin du.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Web push jakinarazpenen ezarpenak gordetzeak huts egin du.\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Sortu bot bat</CreateBotLink> Seerr-en erabiltzeko\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Baliozko ostalari-izen edo IP helbide bat eman behar duzu\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Baliozko PGP gako pribatu bat eman behar duzu\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Baliozko Discord rol baten IDa eman behar duzu\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URLa ez du amaierako barra batean amaitu behar\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Baliozko ostalari-izen edo IP helbide bat eman behar duzu\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URLak ez du barra batean amaitu behar\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"{jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"{jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"{jobScheduleSeconds, plural, one {second} other {{jobScheduleSeconds} seconds}}\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Zerbait gaizki joan da API gako berria sortzean.\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Onartu {mediaServerName} erabiltzaileak saioa hastea inportatu gabe\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URLak ez du barra batean amaitu behar\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"URLa ez du amaierako barra batean amaitu behar\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Baliozko ostalari-izen edo IP helbide bat eman behar duzu\",\n  \"components.Settings.deleteserverconfirm\": \"Ziur zaude zerbitzari hau ezabatu nahi duzula?\",\n  \"components.Settings.experimentalTooltip\": \"Ezarpen hau gaitzeak aplikazioaren ustekabeko portaera sortu dezake\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URLak ez du barra batean amaitu behar\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Autentifikazio pertsonalizatua liburutegiko taldekatze automatikoarekin ez da onartzen\",\n  \"components.Settings.validationHostnameRequired\": \"Baliozko ostalari-izen edo IP helbide bat eman behar duzu\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"URLa ez da barra batean amaitu behar\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URLak ez du barra batean amaitu behar\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Mesedez, egin klik azpiko botoian aplikazioa freskatzeko.\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Mesedez, berrabiarazi zerbitzaria eguneratutako ezarpenak aplikatzeko.\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {Atal #} other {# atal}}\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {erabiltzaile} other {erabiltzaile}} ondo inportatu dira!\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {erabiltzaile} other {erabiltzaile}} ondo inportatu dira!\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {Denboraldi #} other {# denboraldi}}\",\n  \"components.UserList.localLoginDisabled\": \"<strong>Gaitu tokiko saioa</strong> ezarpena desgaituta dago.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Zure Discord kontuarekin bat datorren <FindDiscordIdLink>multi-digitu ID zenbakia</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Baliozko Discord erabiltzaile ID bat eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"Zure kontuarekin bat datorren <FindDiscordIdLink>multi-digitu ID zenbakia</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Baliozko erabiltzaile edo talde-gakoa eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Baliozko PGP gako publiko bat eman behar duzu\",\n  \"components.UserProfile.emptywatchlist\": \"Zure <PlexWatchlistSupportLink>Plex jarraipen-zerrendara</PlexWatchlistSupportLink> gehitutako multimedia hemen agertuko da.\",\n  \"components.RequestModal.requestseasons4k\": \"Eskatu {seasonCount} {seasonCount, plural, one {denboraldi} other {denboraldi}} 4K-n\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Hasi txat bat</TelegramBotLink>, gehitu <GetIdBotLink>@get_id_bot</GetIdBotLink>, eta egin <code>/my_id</code> komandoa\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Gutxienez jakinarazpen mota bat aukeratu behar duzu\",\n  \"components.Settings.Notifications.validationTypes\": \"Gutxienez jakinarazpen mota bat aukeratu behar duzu\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Sortu token bat zure <PushbulletSettingsLink>kontuaren ezarpenetatik</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Baliozko erabiltzaile edo talde-gakoa eman behar duzu\",\n  \"components.Settings.advancedTooltip\": \"Ezarpen hau gaizki konfiguratzeak funtzionalitatea apurtu dezake\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Gutxienez jakinarazpen mota bat aukeratu behar duzu\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Irristari berria sortu eta pertsonalizazio ezarpenak gorde dira.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Gutxienez jakinarazpen mota bat aukeratu behar duzu\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Balio bat eman behar duzu.\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Bozka zenbakia {minValue} eta {maxValue} artean\",\n  \"components.Discover.updatefailed\": \"Zerbait gaizki atera da ezarpen pertsonalizatuak eguneratzean.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Zerbait gaizki atera da intzidentziaren egoera eguneratzean.\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Atal} other {Atal}}\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Denboraldi} other {Denboraldi}}\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commit}} atzetik\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Zerbait gaizki joan da intzidentzia bidaltzean.\",\n  \"components.Login.loginerror\": \"Zerbait gaizki atera da saioa hastean.\",\n  \"components.Login.validationUrlTrailingSlash\": \"URLak ez du barra batean amaitu behar\",\n  \"components.Login.validationPortRequired\": \"Baliozko ataka zenbakia eman behar da\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"URLak ez du hasierako barra bat izan behar\",\n  \"components.Login.validationemailrequired\": \"Baliozko helbide elektroniko bat eman behar duzu\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {erreprodukzio} other {erreprodukzio}}\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Markatu 4K-n eskuragarri dauden denboraldi guztiak\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Kaleratze data} other {Kaleratze datak}}\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Jakinarazi beste erabiltzaileek intzidentziatan iruzkinak bidaltzen dituztenean.\",\n  \"components.MovieDetails.productioncountries\": \"Produkzioa {countryCount, plural, one {herrialde} other {herrialde}}\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Bidali jakinarazpenak intzidentziak iruzkin berriak jasotzen dituztenean.\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Bidali jakinarazpenak multimedia eskaerak eskuz onartzen direnean.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Jakinarazki zuk bidalitako intzidentziak berriro irekitzen badira.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Jakinarazki zuk bidalitako intzidentziak konpontzen badira.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Jakinarazki zure multimedia eskaerak onartzen badira.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Jakinarazi zure multimedia eskaerak eskuragarri egiten badira.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Jakinarazi zure multimedia eskaerak ukatzen badira.\",\n  \"components.PermissionEdit.adminDescription\": \"Administratzaile sarbide osoa. Beste baimen egiaztapen guztiak saihesten ditu.\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Baimendu multimedia eskaera aukera aurreratuak editatzea.\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Baimendu onarpen automatikoa 4K multimedia eskaeretarako.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Bidali jakinarazpenak multimedia eskaerak eskuragarri daudenean.\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Bidali jakinarazpenak multimedia eskaerak ukatzen direnean.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Jakinarazki beste erabiltzaileek intzidentziak irekitzen dituztenean.\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Onartu 4K filma eskaerak automatikoki.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Baimendu onarpen automatikoa ez-4K multimedia eskaeretarako.\",\n  \"components.PermissionEdit.request4kDescription\": \"Baimendu 4K multimedia eskatzea.\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Baimendu 4K film eskaerak bidaltzea.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Baimendu 4K telesail eskaerak bidaltzea.\",\n  \"components.PermissionEdit.requestDescription\": \"Baimendu ez-4K multimedia eskaerak bidaltzea.\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Baimendu ez-4K film eskaerak bidaltzea.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Baimendu ez-4K telesail eskaerak bidaltzea.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Onartu 4K telesailak automatikoki.\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Onartu ez-4K filma eskaerak automatikoki.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Onartu ez-4K telesailen eskaerak automatikoki.\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Baimendu beste erabiltzaileen {mediaServerName} jarraipen-zerrendak ikustea.\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {denboraldi} other {denboraldi}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Denboraldi} other {Denboraldi}}\",\n  \"components.RequestButton.approverequests\": \"Onartu {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.declinerequests\": \"Ukatu {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestCard.failedretry\": \"Zerbait gaizki joan da eskaera berriro saiatzean.\",\n  \"components.RequestList.RequestItem.failedretry\": \"Zerbait gaizki joan da eskaera berriro saiatzean.\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Denboraldi} other {Denboraldi}}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Denboraldi} other {Denboraldi}}\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Telesail hau anime bat da.\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {denboraldi} other {denboraldi}}\",\n  \"components.RequestModal.errorediting\": \"Zerbait gaizki joan da eskaera editatzean.\",\n  \"components.RequestModal.requesterror\": \"Zerbait gaizki joan da eskaera bidaltzean.\",\n  \"components.RequestModal.requestseasons\": \"Eskatu {seasonCount} {seasonCount, plural, one {denboraldia} other {denboraldiak}}\",\n  \"components.ResetPassword.validationemailrequired\": \"Baliozko helbide elektroniko bat eman behar duzu\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URLak ez du barra batean amaitu behar\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Baliozko URL bat eman behar duzu\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Bot baimen token bat eman behar duzu\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Baliozko txat ID bat eman behar duzu\",\n  \"components.Settings.Notifications.validationEmail\": \"Baliozko helbide elektroniko bat eman behar duzu\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Baliozko ataka zenbaki bat eman behar duzu\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Sortu <DiscordWebhookLink>webhook integrazio</DiscordWebhookLink> bat zure zerbitzarian\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URLak ez du hasierako barra bat izan behar\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Baliozko ataka zenbaki bat eman behar duzu\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Zerbait gaizki joan da zeregina gordetzean.\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Konfiguratu Seerr-en ezarpen global eta lehenetsiak.\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Oinarrizko URLak hasierako barra bat izan behar du\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Baliozko ataka zenbakia eman behar da\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Zerbait gaizki joan da {mediaServerName} ezarpenak gordetzean.\",\n  \"components.Settings.serverpresetLoad\": \"Sakatu botoia zerbitzari eskuragarriak kargatzeko\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Zerbait gaizki joan da Tautulli ezarpenak gordetzean.\",\n  \"components.Settings.validationPortRequired\": \"Baliozko ataka zenbaki bat eman behar duzu\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URLak ez du hasierako barra bat izan behar\",\n  \"components.Setup.subtitle\": \"Hasi zure multimedia zerbitzaria aukeratzearekin\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Zerbait gaizki joan da denboraldiaren datuak lortzerakoan.\",\n  \"components.TvDetails.productioncountries\": \"Produkzioa {countryCount, plural, one {herrialde} other {herrialde}}\",\n  \"components.UserList.autogeneratepasswordTip\": \"Bidali zerbitzariak sortutako pasahitza erabiltzaileari e-posta bidez\",\n  \"components.UserList.importfromJellyfinerror\": \"Zerbait gaizki joan da {mediaServerName} erabiltzaileak inportatzerakoan.\",\n  \"components.UserList.importfromplexerror\": \"Zerbait gaizki joan da Plex erabiltzaileak inportatzerakoan.\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Ez dago {mediaServerName} erabiltzailerik inportatzeko.\",\n  \"components.UserList.nouserstoimport\": \"Ez dago Plex erabiltzailerik inportatzeko.\",\n  \"components.UserList.usercreatedfailed\": \"Zerbait gaizki joan da erabiltzailea sortzerakoan.\",\n  \"components.UserList.userdeleteerror\": \"Zerbait gaizki joan da erabiltzailea ezabatzerakoan.\",\n  \"components.UserList.userfail\": \"Zerbait gaizki joan da erabiltzailearen baimenak gordetzerakoan.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Automatikoki eskatu zure <PlexWatchlistSupportLink>Plex jarraipen zerrendan</PlexWatchlistSupportLink> dauden filmak\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Sortu token bat zure <PushbulletSettingsLink>kontuaren ezarpenetatik</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Baliozko erabiltzaile ID bat eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Baliozko aplikazio token bat eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Baliozko txat ID bat eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Zerbait gaizki joan da pasahitza gordetzean.\",\n  \"i18n.showingresults\": \"<strong>{total}</strong>(e)tik <strong>{from}</strong>(e)tik <strong>{to}</strong>(e)ra emaitza erakusten\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Zerbait gaizki atera da intzidentziaren deskribapena editatzean.\",\n  \"components.RequestModal.requestmovies\": \"Eskatu {count} {count, plural, one {film} other {film}}\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Zerbait gaizki joan da intzidentzia ezabatzean.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Automatikoki eskatu zure <PlexWatchlistSupportLink>Plex jarraipen zerrendan</PlexWatchlistSupportLink> dauden telesailak\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Gutxienez jakinarazpen mota bat aukeratu behar duzu\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {film}}\",\n  \"components.RequestModal.requestadmin\": \"Eskaera hau automatikoki onartuko da.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify proba jakinarazpena bidaltzeak huts egin du.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbullet jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Aplikazio token bat eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Erregistratu aplikazio bat</ApplicationRegistrationLink> {applicationTitle}-(r)ekin erabiltzeko\",\n  \"components.Discover.CreateSlider.editfail\": \"Irristaria editatzeak huts egin du.\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Eman TMDB gako ID bat\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Eman TMDB sarearen IDa\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Eman bilaketa-kontsulta bat\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Izenburu bat eman behar duzu.\",\n  \"components.Discover.CreateSlider.starttyping\": \"Hasi idazten bilatzeko.\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Bilatu gako hitzak…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Irristariaren izena\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Film {language}-(e)ak\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Ospea gorantz\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Ospea beherantz\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Irristaria ezabatzeak huts egin du.\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Lehen emisioaren data gorantz\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Lehen emisioaren data beherantz\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Kaleratze data gorantz\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Kaleratze data beherantz\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Izenburua (A-Z) gorantz\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Izenburua (Z-A) beherantz\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB puntuazioa gorantz\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB puntuazioa beherantz\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network}-(e)ko telesailak\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Txandakatu ikusgarritasuna\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio}-(e)ko filmak\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Irristaria ondo ezabatu da.\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Izenburua (A-Z) gorantz\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Izenburua (Z-A) beherantz\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Ospea gorantz\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Ospea beherantz\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre}-(e)ko telesailak\",\n  \"components.Discover.FilterSlideover.ratingText\": \"{minValue} eta {maxValue} arteko balorazioak\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Garbitu gaitutako iragazkiak\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Lehen emisio data\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minutuko iraupena\",\n  \"components.Discover.FilterSlideover.from\": \"Hemendik\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB erabiltzaileen bozka zenbakia\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB erabiltzaileen puntuazioa\",\n  \"components.Discover.FilterSlideover.to\": \"Hona\",\n  \"components.Discover.NetworkSlider.networks\": \"Sareak\",\n  \"components.Discover.createnewslider\": \"Sortu irristari berria\",\n  \"components.Discover.customizediscover\": \"Pertsonalizatu aurkitu\",\n  \"components.Discover.resettodefault\": \"Berrezarri lehenetsira\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB film generoa\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB film gakoa\",\n  \"components.Discover.plexwatchlist\": \"Zure jarraipenak\",\n  \"components.Discover.popularmovies\": \"Film ospetsuak\",\n  \"components.Discover.populartv\": \"Telesail ospetsuak\",\n  \"components.Discover.recentlyAdded\": \"Duela gutxi gehituta\",\n  \"components.Discover.recentrequests\": \"Eskaera berriak\",\n  \"components.Discover.stopediting\": \"Editatzen utzi\",\n  \"components.Discover.discover\": \"Aurkitu\",\n  \"components.Discover.moviegenres\": \"Film generoak\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB film streaming zerbitzuak\",\n  \"components.Discover.resetsuccess\": \"Aurkitu pertsonalizazio ezarpenak ondo berrezarri dira.\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: {seasonNumber}. denboraldia {episodeNumber}. atala\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TV streaming zerbitzuak\",\n  \"components.IssueDetails.IssueComment.postedby\": \"{username}-(e)k {relativeTime} datan bidalita\",\n  \"components.Discover.updatesuccess\": \"Aurkitu pertsonalizazio ezarpenak eguneratu dira.\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB telesail generoa\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB telesail gakoa\",\n  \"components.Discover.tmdbnetwork\": \"TMDB sarea\",\n  \"components.Discover.tmdbsearch\": \"TMDB bilaketa\",\n  \"components.Discover.upcomingmovies\": \"Hurrengo filmak\",\n  \"components.Discover.upcomingtv\": \"Hurrengo telesailak\",\n  \"components.DownloadBlock.estimatedtime\": \"{time} estimatuta\",\n  \"components.IssueDetails.IssueComment.delete\": \"Ezabatu iruzkina\",\n  \"components.Discover.trending\": \"Joerak\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"{username}-(e)k bidalita {relativeTime} datan (Editatuta)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Mezu bat idatzi behar duzu\",\n  \"components.IssueDetails.openedby\": \"#{issueId} irekita {relativeTime} datan {username}-(r)engatik\",\n  \"components.IssueDetails.openin4karr\": \"Ireki 4K-n {arr}\",\n  \"components.IssueDetails.closeissueandcomment\": \"Itxi iruzkinarekin\",\n  \"components.IssueDetails.commentplaceholder\": \"Gehitu iruzkin bat…\",\n  \"components.IssueDetails.openinarr\": \"Ireki {arr}-en\",\n  \"components.IssueDetails.play4konplex\": \"Ikusi 4K-n {mediaServerName}-(e)n\",\n  \"components.IssueDetails.playonplex\": \"Ikusi {mediaServerName}-(e)n\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Ireki berriro iruzkinarekin\",\n  \"components.IssueDetails.toastissuedeleted\": \"Intzidentzia ondo ezabatu da!\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} {user} erabiltzailearengatik\",\n  \"components.IssueDetails.toaststatusupdated\": \"Intzidentziaren egoera ondo editatu da!\",\n  \"components.IssueList.showallissues\": \"Erakutsi intzidentzia guztiak\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Deskribapen bat eman behar duzu\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Helbide elektronikoa beharrezkoa da.\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Bilatu filmak eta telesailak\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Helbide elektronikoa baliogabea da.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Pasahitza behar da.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Bidali intzidentzia bat\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"<strong>{title}</strong> intzidentzia txostena ondo bidali da!\",\n  \"components.Login.credentialerror\": \"Erabiltzailea edo pasahitza baliogabeak dira.\",\n  \"components.Login.invalidurlerror\": \"Ezin da {mediaServerName} zerbitzarira konektatu.\",\n  \"components.Login.validationEmailRequired\": \"Helbide elektroniko bat eman behar duzu\",\n  \"components.Login.validationpasswordrequired\": \"Pasahitz bat eman behar duzu\",\n  \"components.Login.validationservertyperequired\": \"Mesedez, hautatu zerbitzari mota bat\",\n  \"components.Login.signinheader\": \"Hasi saioa jarraitzeko\",\n  \"components.Login.signinwithjellyfin\": \"Erabili zure {mediaServerName} kontua\",\n  \"components.Login.signinwithoverseerr\": \"Erabili zure {applicationTitle} kontua\",\n  \"components.Login.signinwithplex\": \"Erabili zure Plex kontua\",\n  \"components.Layout.VersionStatus.outofdate\": \"Zaharkituta\",\n  \"components.Login.validationemailformat\": \"Baliozko helbide elektronikoa behar da\",\n  \"components.Login.validationhostformat\": \"Baliozko URLa behar da\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URLa behar da\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Markatu 4K-n eskuragarri\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Markatu denboraldi guztiak eskuragarri\",\n  \"components.MovieDetails.mark4kavailable\": \"Markatu 4K-n eskuragarri\",\n  \"components.ManageSlideOver.openarr4k\": \"Ireki 4K-n {arr}\",\n  \"components.ManageSlideOver.pastdays\": \"Azken {days, number} egunetan\",\n  \"components.ManageSlideOver.removearr4k\": \"Kendu 4K {arr}\",\n  \"components.MovieDetails.openradarr\": \"Ireki filma Radarr-en\",\n  \"components.ManageSlideOver.markavailable\": \"Markatu eskuragarri gisa\",\n  \"components.ManageSlideOver.openarr\": \"Ireki {arr}-en\",\n  \"components.ManageSlideOver.opentautulli\": \"Ireki Tautullin\",\n  \"components.ManageSlideOver.removearr\": \"Kendu {arr}-etik\",\n  \"components.MovieDetails.addtowatchlist\": \"Gehitu jarraipen zerrendara\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB erabiltzaileen puntuazioa – botoak: {formattedCount}\",\n  \"components.MovieDetails.markavailable\": \"Markatu eskuragarri gisa\",\n  \"components.MovieDetails.openradarr4k\": \"Ireki filma 4K Radarr-en\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Estudio} other {Estudio}}\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Bidali jakinarazpenak intzidentziak sortzen direnean.\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Bidali jakinarazpenak intzidentziak berriro irekitzen direnean.\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Bidali jakinarazpenak intzidentziak konpontzen direnean.\",\n  \"components.MovieDetails.watchlistError\": \"Zerbait gaizki joan da. Mesedez, saiatu berriro.\",\n  \"components.MovieDetails.play4k\": \"Ikusi 4K-n {mediaServerName}-(e)n\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes audientzia puntuazioa\",\n  \"components.MovieDetails.play\": \"Ikusi {mediaServerName}-(e)n\",\n  \"components.MovieDetails.removefromwatchlist\": \"Kendu jarraipen zerrendatik\",\n  \"components.MovieDetails.reportissue\": \"Bidali intzidentzia bat\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.MovieDetails.streamingproviders\": \"Orain emititzen hemen\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB erabiltzaileen puntuazioa\",\n  \"components.MovieDetails.viewfullcrew\": \"Ikusi talde osoa\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Eskaera automatikoki onartuta\",\n  \"components.MovieDetails.similar\": \"Antzeko filmak\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> jarraipen-zerrendatik ondo kendu da!\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> ondo gehitu da jarraipen zerrendara!\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Eskaera automatikoki bidalita\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Eskaera prozesatzeak huts egin du\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Eskaera onartzeko zain dago\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Auto-onartu 4K filmak\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Auto-onartu 4K telesailak\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Baimendu multimedia intzidentziak kudeatzea.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Baimendu multimedia intzidentziak sortzea.\",\n  \"components.PermissionEdit.request4kMovies\": \"Eskatu 4K filmak\",\n  \"components.PermissionEdit.request4kTv\": \"Eskatu 4K telesailak\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {egun} other {egun}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {film}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} {quotaDays} {days}</quotaUnits>\",\n  \"components.PersonDetails.alsoknownas\": \"Beste izen batzuk: {names}\",\n  \"components.PermissionEdit.viewrecent\": \"Ikusi berriki gehituta\",\n  \"components.PermissionEdit.viewwatchlists\": \"Ikusi {mediaServerName} jarraipen zerrendak\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.RequestBlock.lastmodifiedby\": \"Azkenengoz editatuta honengatik\",\n  \"components.RegionSelector.regionDefault\": \"Eskualde guztiak\",\n  \"components.RegionSelector.regionServerDefault\": \"Lehenetsia ({region})\",\n  \"components.RequestBlock.rootfolder\": \"Erro karpeta\",\n  \"components.RequestButton.requestmore4k\": \"Eskatu gehiago 4K-n\",\n  \"components.RequestButton.approverequest4k\": \"Onartu 4K eskaera\",\n  \"components.RequestButton.declinerequest4k\": \"Ukatu 4K eskaera\",\n  \"components.RequestButton.viewrequest4k\": \"Ikusi 4K eskaera\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} ez da aurkitu\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} ez da aurkitu\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} {user} erabiltzailearengatik\",\n  \"components.RequestList.RequestItem.removearr\": \"Kendu {arr}-etik\",\n  \"components.RequestList.showallrequests\": \"Erakutsi eskaera guztiak\",\n  \"components.RequestList.sortDirection\": \"Txandakatu ordenaren norabidea\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Erro karpeta\",\n  \"components.RequestModal.numberofepisodes\": \"Atal #\",\n  \"components.RequestModal.pending4krequest\": \"Onartzeke 4K eskaera\",\n  \"components.RequestModal.pendingrequest\": \"Eskaera zain\",\n  \"components.RequestModal.requestCancel\": \"<strong>{title}</strong> eskaera utzita.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> ondo eskatu da!\",\n  \"components.RequestModal.requestcancelled\": \"<strong>{title}</strong> eskaera utzita.\",\n  \"components.RequestModal.requestfrom\": \"{username}-(r)en eskaera onartzeko zain dago.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Eskatu filma 4K-n\",\n  \"components.RequestModal.requestcollectiontitle\": \"Eskatu bilduma\",\n  \"components.RequestModal.requestmovietitle\": \"Eskatu filma\",\n  \"components.RequestModal.requestseriestitle\": \"Eskatu telesailak\",\n  \"components.RequestModal.seasonnumber\": \"{number}. denboraldia\",\n  \"components.ResetPassword.confirmpassword\": \"Berretsi pasahitza\",\n  \"components.ResetPassword.email\": \"Helbide elektronikoa\",\n  \"components.ResetPassword.gobacklogin\": \"Itzuli saioa hasteko orrira\",\n  \"components.ResetPassword.passwordreset\": \"Pasahitza berrezarri\",\n  \"components.ResetPassword.resetpassword\": \"Berrezarri zure pasahitza\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Pasahitzak bat egin behar dute\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Pasahitza ondo berrezarri da!\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Pasahitz bat eman behar duzu\",\n  \"components.Search.searchresults\": \"Bilaketa emaitzak\",\n  \"components.Selector.inProduction\": \"Ekoizpenean\",\n  \"components.Selector.nooptions\": \"Emaitzarik ez.\",\n  \"components.Selector.returningSeries\": \"Itzulitako telesaila\",\n  \"components.Selector.searchKeywords\": \"Bilatu gako hitzak…\",\n  \"components.Selector.searchStudios\": \"Bilatu estudioak…\",\n  \"components.Selector.showmore\": \"Erakutsi gehiago\",\n  \"components.Selector.starttyping\": \"Hasi idazten bilatzeko.\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Gaitu agentea\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify proba jakinarazpena bidalita!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Aplikazioaren tokena\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Zerbitzariaren URLa\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Sarbide tokena\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Kanalaren etiketa\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Pushbullet proba jakinarazpena bidaltzen…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet proba jakinarazpena bidalita!\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Aplikazioaren API tokena\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushover jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover proba jakinarazpena bidaltzeak huts egin du.\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Zure 30 karaktereko <UsersGroupsLink>erabiltzaile edo talde identifikatzailea</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Pushover proba jakinarazpena bidaltzen…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover proba jakinarazpena bidalita!\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Erabiltzaile edo talde gakoa\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Gaitu agentea\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Gailu lehenetsia\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Jakinarazpen soinua\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Gaitu agentea\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack proba jakinarazpena bidaltzeak huts egin du.\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Baliozko URL bat eman behar duzu\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Slack proba jakinarazpena bidaltzen…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack proba jakinarazpena bidalita!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Berrezarri lehenetsira\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Txantiloien aldagai laguntza\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook URLa\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Gaitu agentea\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Baimen goiburua\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON edukia\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON edukia ondo berrezarri da!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Baliozko URL bat eman behar duzu\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Webhook proba jakinarazpena bidaltzen…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook proba jakinarazpena bidalita!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook URLa\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discord jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"E-posta jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Sinatu zifratutako mezuak <OpenPgpLink>OpenPGP</OpenPgpLink> erabiliz\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Web push proba jakinarazpena bidaltzen…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Web push proba jakinarazpena bidalita!\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Erabili STARTTLS eskuragarri badago\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Baimendu auto-sinatutako ziurtagiriak\",\n  \"components.Settings.Notifications.botAPI\": \"Bot baimen tokena\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Bot avatar URLa\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Erabili TLS implizitua\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Beti erabili STARTTLS\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP gako pribatua\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Gaitu agentea\",\n  \"components.Settings.Notifications.agentenabled\": \"Gaitu agentea\",\n  \"components.Settings.Notifications.authPass\": \"SMTP pasahitza\",\n  \"components.Settings.Notifications.authUser\": \"SMTP erabiltzaile-izena\",\n  \"components.Settings.Notifications.botUsername\": \"Bot erabiltzaile-izena\",\n  \"components.Settings.Notifications.chatId\": \"Txat ID\",\n  \"components.Settings.Notifications.emailsender\": \"Igorlearen helbidea\",\n  \"components.Settings.Notifications.enableMentions\": \"Gaitu aipamenak\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP pasahitza\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Webhook jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Web push jakinarazpen ezarpenak ondo gorde dira!\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"E-posta jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Sinatu zifratutako mezuak <OpenPgpLink>OpenPGP</OpenPgpLink> erabiliz\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegram jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord proba jakinarazpena bidaltzeak huts egin du.\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"E-posta proba jakinarazpena bidaltzeak huts egin du.\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram proba jakinarazpena bidaltzeak huts egin du.\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"PGP pasahitz bat eman behar duzu\",\n  \"components.Settings.Notifications.validationUrl\": \"Baliozko URL bat eman behar duzu\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Bidali jakinarazpenak soinurik gabe\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Discord proba jakinarazpena bidaltzen…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord proba jakinarazpena bidalita!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"E-posta proba jakinarazpena bidaltzen…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"E-posta proba jakinarazpena bidalita!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Telegram proba jakinarazpena bidaltzen…\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram proba jakinarazpena bidalita!\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Behartu erabiltzaileen helbide elektronikoak\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Jakinarazpen Rol IDa\",\n  \"components.Settings.Notifications.sendSilently\": \"Bidali isilean\",\n  \"components.Settings.Notifications.senderName\": \"Igorlearen izena\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP ostalaria\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP ataka\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook URLa\",\n  \"components.Settings.RadarrModal.add\": \"Gehitu zerbitzaria\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Probatu konexioa kalitate profilak kargatzeko\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Probatu konexioa erro karpetak kargatzeko\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Gehitu 4K Radarr zerbitzari berria\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Probatu konexioa etiketak kargatzeko\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Radarr-era konektatzeak huts egin du.\",\n  \"components.Settings.RadarrModal.createradarr\": \"Gehitu Radarr zerbitzari berria\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Editatu 4K Radarr zerbitzaria\",\n  \"components.Settings.RadarrModal.default4kserver\": \"4K zerbitzari lehenetsia\",\n  \"components.Settings.RadarrModal.editradarr\": \"Editatu Radarr zerbitzaria\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Gaitu bilaketa automatikoa\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Kalitate profilak kargatzen…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Erro karpetak kargatzen…\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Hautatu kalitate profila\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Hautatu erro karpeta\",\n  \"components.Settings.RadarrModal.apiKey\": \"API gakoa\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Oinarrizko URLa\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Zerbitzari lehenetsia\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Kanpoko URLa\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Zinematan\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Kargatu etiketak…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Gutxieneko eskuragarritasuna\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Etiketarik gabe.\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Kalitate profila\",\n  \"components.Settings.RadarrModal.selecttags\": \"Hautatu etiketak\",\n  \"components.Settings.RadarrModal.server4k\": \"4K zerbitzaria\",\n  \"components.Settings.RadarrModal.servername\": \"Zerbitzariaren izena\",\n  \"components.Settings.RadarrModal.ssl\": \"Erabili SSL\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Gaitu eskaneoa\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Etiketa eskaerak\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"API gakoa eman behar duzu\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Baliozko URL bat eman behar duzu\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Gutxieneko eskuragarritasuna hautatu behar duzu\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Zerbitzari-izen bat eman behar duzu\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Kalitate profil bat hautatu behar duzu\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Erro karpeta bat hautatu behar duzu\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Kalertaze-data ez dago eskuragarri unean.\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Ikusi GitHuben\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Zaharkituta\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Eguneratuta\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} aldaketa egunkaria\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Ikusi aldaketa egunkaria\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Datuen direktorioa\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Lortu laguntza\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub eztabaidak\",\n  \"components.Settings.SettingsAbout.timezone\": \"Ordu-eremua\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Multimedia guztia\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Eskaera guztiak\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Jellyfin liburutegi osoko eskaneoa\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Jellyfin berriki gehitutakoen eskaneoa\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Multimedia eskuragarritasun sinkronizazioa\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} cachea garbituta.\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Deskarga sinkronizatua berrezarri\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Irudien cache garbiketa\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Cache tamaina guztira\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Ekintza ondo editatu da!\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Ekintzak eta cachea\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Gako guztiak\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Gakoaren tamaina\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Cachearen izena\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Balioaren tamaina\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Utzi ekintza\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Deskarga sinkronizatua\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Aldatu ekintza\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Uneko maiztasuna\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Maiztasun berria\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Garbitu cachea\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Irudien cachea\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Cacheatutako irudiak\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} utzita.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Ekintzaren izena\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} hasita.\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Hurrengo abiarazpena\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Erregistro mezua arbelera kopiatuta.\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plex liburutegi osoko eskaneoa\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plex berriki gehitutako eskaneoa\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex freskatze tokena\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex jarraipen-zerrenda sinkronizazioa\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Kopiatu arbelera\",\n  \"components.Settings.SettingsLogs.showall\": \"Erakutsi erregistro guztiak\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr eskaneoa\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Abiarazi orain\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr eskaneoa\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Ekintza ezezaguna\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Erabiltzaileen avatarrak\",\n  \"components.Settings.SettingsLogs.extraData\": \"Datu gehigarriak\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Erregistroaren xehetasunak\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Ikusi xehetasunak\",\n  \"components.Settings.SettingsMain.apikey\": \"API gakoa\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Aplikazioaren izenburua\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Aplikazioaren URLa\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Erakutsi streaming guneak eskualdeko eskuragarritasunaren arabera\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Zerbait gaizki joan da ezarpenak gordetzean.\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Iragazi edukia eskualdeko eskuragarritasunarengatik\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Iragazi edukia iturrizko hizkuntzarengatik\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Baimendu telesailen eskaera partzialak\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Gaitu irudien cachea\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Ezkutatu eskuragarri dagoen multimedia\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Aurkitu eskualdea\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Ezarpen orokorrak\",\n  \"components.Settings.SettingsMain.locale\": \"Bistaratzeko hizkuntza\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Aurkitu hizkuntza\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Streaming eskualdea\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Aplikazioaren izenburu bat eman behar duzu\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Baliozko URL bat eman behar duzu\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Erabiltzaile berrie ematen zaizkien hasierako baimenak\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Film eskaera muga globala\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Gaitu {mediaServerName} saio hasiera berria\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Gaitu saio hasiera lokala\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Baimen lehenetsiak\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Gehitu 4K Sonarr zerbitzari berria\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Kalitate profilak kargatzen…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Erro karpetak kargatzen…\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Hautatu hizkuntza profila\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Hautatu kalitate profila\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Telesail eskaera muga globala\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Editatu 4K Sonarr zerbitzaria\",\n  \"components.Settings.SonarrModal.hostname\": \"Ostalari-izena edo IP helbidea\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Anime telesail mota\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime hizkuntza profila\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime kalitate profila\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime erro karpeta\",\n  \"components.Settings.SonarrModal.default4kserver\": \"4K zerbitzari lehenetsia\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Gaitu bilaketa automatikoa\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Hizkuntza profilak kargatzen…\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Hautatu erro karpeta\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Erabiltzailearen ezarpenak\",\n  \"components.Settings.SonarrModal.add\": \"Gehitu zerbitzaria\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime etiketak\",\n  \"components.Settings.SonarrModal.apiKey\": \"API gakoa\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Oinarrizko URLa\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Kanpoko URLa\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Hizkuntza profila\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Kargatu etiketak…\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Etiketarik gabe.\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Kalitate profila\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Erro karpeta\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Denboraldien karpetak\",\n  \"components.Settings.SonarrModal.selecttags\": \"Hautatu etiketak\",\n  \"components.Settings.SonarrModal.seriesType\": \"Telesail mota\",\n  \"components.Settings.SonarrModal.servername\": \"Zerbitzariaren izena\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Erabiltzailearen ezarpenak ondo gorde dira!\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Probatu konexioa hizkuntza profilak kargatzeko\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Probatu konexioa kalitate profilak kargatzeko\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Probatu konexioa erro karpetak kargatzeko\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"API gakoa eman behar duzu\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Baliozko URL bat eman behar duzu\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Hizkuntza profil bat hautatu behar duzu\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Zerbitzari-izen bat eman behar duzu\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Kalitate profil bat hautatu behar duzu\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Erro karpeta bat hautatu behar duzu\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Probatu konexioa etiketak kargatzeko\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Sonarr-era konektatzeak huts egin du.\",\n  \"components.Settings.hostname\": \"Ostalari-izena edo IP helbidea\",\n  \"components.Settings.addradarr\": \"Gehitu Radarr zerbitzaria\",\n  \"components.Settings.addsonarr\": \"Gehitu Sonarr zerbitzaria\",\n  \"components.Settings.currentlibrary\": \"Uneko liburutegia: {name}\",\n  \"components.Settings.deleteServer\": \"Ezabatu {serverType} zerbitzaria\",\n  \"components.Settings.SonarrModal.ssl\": \"Erabili SSL\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Gaitu eskaneoa\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Etiketa eskaerak\",\n  \"components.Settings.activeProfile\": \"Gaitutako profila\",\n  \"components.Settings.apiKey\": \"API gakoa\",\n  \"components.Settings.cancelscan\": \"Utzi eskaneoa\",\n  \"components.Settings.default4k\": \"4K lehenetsia\",\n  \"components.Settings.enablessl\": \"Erabili SSL\",\n  \"components.Settings.externalUrl\": \"Kanpoko URLa\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr konexioa ondo ezarri da!\",\n  \"components.Settings.invalidurlerror\": \"Ezin da {mediaServerName} zerbitzarira konektatu.\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Zerbait gaizki joan da liburutegiak sinkronizatzean\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Ez da liburutegirik aurkitu\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Ahaztutako pasahitza URLa\",\n  \"components.Settings.librariesRemaining\": \"Geratzen diren liburutegiak: {count}\",\n  \"components.Settings.manualscan\": \"Eskuzko liburutegi eskaneoa\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName} ezarpenak\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName} liburutegiak\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName} ezarpenak\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName} ezarpenak ondo gorde dira!\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Konfiguratu eta gaitu jakinarazpen agenteak.\",\n  \"components.Settings.manualscanJellyfin\": \"Eskuzko liburutegi eskaneoa\",\n  \"components.Settings.menuJobs\": \"Ekintzak eta cachea\",\n  \"components.Settings.notificationsettings\": \"Jakinarazpen ezarpenak\",\n  \"components.Settings.notrunning\": \"Ez dago exekutatzen\",\n  \"components.Settings.plexlibraries\": \"Plex liburutegiak\",\n  \"components.Settings.plexsettings\": \"Plex ezarpenak\",\n  \"components.Settings.radarrsettings\": \"Radarr ezarpenak\",\n  \"components.Settings.save\": \"Gorde aldaketak\",\n  \"components.Settings.scan\": \"Sinkronizatu liburutegiak\",\n  \"components.Settings.serverpresetManualMessage\": \"Eskuzko konfigurazioa\",\n  \"components.Settings.serverpresetRefreshing\": \"Zerbitzariak lortzen…\",\n  \"components.Settings.sonarrsettings\": \"Sonarr ezarpenak\",\n  \"components.Settings.startscan\": \"Hasi eskaneoa\",\n  \"components.Settings.syncJellyfin\": \"Sinkronizatu liburutegiak\",\n  \"components.Settings.tautulliApiKey\": \"API gakoa\",\n  \"components.Settings.tautulliSettings\": \"Tautulli ezarpenak\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Plex zerbitzariaren zerrenda eskuratzeak huts egin du.\",\n  \"components.Settings.validationApiKey\": \"API gakoa eman behar duzu\",\n  \"components.Settings.validationUrl\": \"Baliozko URL bat eman behar duzu\",\n  \"components.Settings.toastPlexConnecting\": \"Plex zerbitzarira konektatzen saiatzen…\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Plex-era konektatzeak huts egin du.\",\n  \"components.Settings.toastPlexRefresh\": \"Zerbitzarien zerrenda Plex-etik lortzen…\",\n  \"components.Setup.signinMessage\": \"Hasteko, hasi saioa\",\n  \"components.Setup.signinWithEmby\": \"Sartu zure Emby informazioa\",\n  \"components.Setup.signinWithJellyfin\": \"Sartu zure Jellyfin informazioa\",\n  \"components.Setup.signinWithPlex\": \"Sartu zure Plex informazioa\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Web App</WebAppLink> URLa\",\n  \"components.Setup.configuremediaserver\": \"Konfiguratu multimedia zerbitzaria\",\n  \"components.Setup.servertype\": \"Aukeratu zerbitzariaren mota\",\n  \"components.Settings.urlBase\": \"Oinarrizko URLa\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Setup.back\": \"Itzuli\",\n  \"components.Setup.configemby\": \"Konfiguratu Emby\",\n  \"components.Setup.configjellyfin\": \"Konfiguratu Jellyfin\",\n  \"components.Setup.configplex\": \"Konfiguratu Plex\",\n  \"components.Setup.configureservices\": \"Konfiguratu zerbitzuak\",\n  \"components.Setup.finish\": \"Bukatu konfigurazioa\",\n  \"components.Setup.signin\": \"Hasi saioa\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex konexioa ondo ezarri da!\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Plex zerbitzarien zerrenda ondo lortu da!\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli ezarpenak ondo gorde dira!\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Sare} other {Sare}}\",\n  \"components.TitleCard.watchlistError\": \"Zerbait gaizki joan da. Mesedez, saiatu berriro.\",\n  \"components.TitleCard.watchlistCancel\": \"<strong>{title}</strong>-(r)en jarraipen-zerrenda utzita.\",\n  \"components.Setup.welcome\": \"Ongi etorri Seerr-era\",\n  \"components.StatusBadge.openinarr\": \"Ireki {arr}-en\",\n  \"components.StatusBadge.playonplex\": \"Ikusi {mediaServerName}-(e)n\",\n  \"components.StatusChecker.restartRequired\": \"Zerbitzaria berrabiarazi behar da\",\n  \"components.TitleCard.addToWatchList\": \"Gehitu jarraipen zerrendara\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} ez da aurkitu\",\n  \"components.TvDetails.Season.noepisodes\": \"Atal zerrenda ez dago eskuragarri.\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Telesailaren aktore guztiak\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Telesailaren talde osoa\",\n  \"components.TvDetails.firstAirDate\": \"Lehen emisio data\",\n  \"components.TvDetails.nextAirDate\": \"Hurrengo emisioa\",\n  \"components.StatusBadge.managemedia\": \"Kudeatu {mediaType}\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} eguneratuta\",\n  \"components.StatusChecker.reloadApp\": \"Kargatu {applicationTitle} berriro\",\n  \"components.TitleCard.cleardata\": \"Garbitu datuak\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutu\",\n  \"components.TvDetails.manageseries\": \"Kudeatu telesailak\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> jarraipen zerrendatik ondo kendu da!\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> jarraipen zerrendara ondo gehitu da!\",\n  \"components.TvDetails.watchlistError\": \"Zerbait gaizki joan da. Mesedez, saiatu berriro.\",\n  \"components.TvDetails.play4k\": \"Ikusi 4K-n {mediaServerName}-(e)n\",\n  \"components.TvDetails.rtaudiencescore\": \"Rotten Tomatoes audientzia puntuazioa\",\n  \"components.TvDetails.play\": \"Ikusi {mediaServerName}-(e)n\",\n  \"components.TvDetails.removefromwatchlist\": \"Kendu jarraipen zerrendatik\",\n  \"components.TvDetails.reportissue\": \"Bidali intzidentzia bat\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.TvDetails.streamingproviders\": \"Orain emititzen hemen\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB erabiltzaileen puntuazioa\",\n  \"components.TvDetails.viewfullcrew\": \"Ikusi talde osoa\",\n  \"components.UserList.autogeneratepassword\": \"Sortu pasahitza automatikoki\",\n  \"components.UserList.createlocaluser\": \"Sortu erabiltzaile lokala\",\n  \"components.UserList.edituser\": \"Editatu erabiltzaileen baimenak\",\n  \"components.UserList.importfromJellyfin\": \"Inportatu {mediaServerName} erabiltzaileak\",\n  \"components.TvDetails.originallanguage\": \"Jatorrizko hizkuntza\",\n  \"components.TvDetails.originaltitle\": \"Jatorrizko izenburua\",\n  \"components.TvDetails.overviewunavailable\": \"Ikuspegi orokorra ez dago eskuragarri.\",\n  \"components.TvDetails.seasonnumber\": \"{seasonNumber} denboraldia\",\n  \"components.TvDetails.showtype\": \"Telesail mota\",\n  \"components.TvDetails.similar\": \"Antzerako telesailak\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.watchtrailer\": \"Ikusi trailerra\",\n  \"components.UserList.bulkedit\": \"Multzoko edizioa\",\n  \"components.UserList.deleteuser\": \"Ezabatu erabiltzailea\",\n  \"components.UserList.email\": \"Helbide elektronikoa\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> jarraipen-zerrendatik ondo kendu da!\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> ondo gehitu da jarraipen zerrendara!\",\n  \"components.UserList.validationUsername\": \"Erabiltzaile-izen bat eman behar duzu\",\n  \"components.UserList.importfrommediaserver\": \"Inportatu {mediaServerName} erabiltzaileak\",\n  \"components.UserList.importfromplex\": \"Inportatu Plex erabiltzaileak\",\n  \"components.UserList.localuser\": \"Erabiltzaile lokala\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName} erabiltzailea\",\n  \"components.UserList.plexuser\": \"Plex erabiltzailea\",\n  \"components.UserList.sortCreated\": \"Batze data\",\n  \"components.UserList.sortDisplayName\": \"Bistaratze izena\",\n  \"components.UserList.sortRequests\": \"Eskaera zenbakia\",\n  \"components.UserList.userlist\": \"Erabiltzaileen zerrenda\",\n  \"components.UserList.validationEmail\": \"Helbide elektronikoa beharrezkoa da\",\n  \"components.UserList.usercreatedsuccess\": \"Erabiltzailea ondo sortu da!\",\n  \"components.UserList.userdeleted\": \"Erabiltzailea ondo ezabatu da!\",\n  \"components.UserList.userssaved\": \"Erabiltzailearen baimenak ondo gorde dira!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Iragazi edukia eskualdeko eskuragarritasunarengatik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Iragazi edukia iturrizko hizkuntzarengatik\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Erabiltzailearen ID: {userid}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord erabiltzailearen ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Baliogabetu muga globala\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Film eskaera muga\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"{joindate} batu zen\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Ikusi profila\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Editatu ezarpenak\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Kontuaren mota\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Bistaratzeko hizkuntza\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Aurkitu eskualdea\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Bistaratze izena\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Ezarpen orokorrak\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"({language}) lehenetsia\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Erabiltzaile lokala\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName} erabiltzailea\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Aurkitu hizkuntza\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex erabiltzailea\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Auto-eskatu filmak\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Auto-eskatu telesailak\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Erakutsi streaming guneak eskualdeko eskuragarritasunaren arabera\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Zerbait gaizki joan da ezarpenak gordetzean.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Iragazi edukia eskualdeko eskuragarritasunarengatik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Helbide elektroni hau dagoeneko hartuta dago!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Telesail eskaera muga\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Baliozko helbide elektronikoa behar da\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Aurkitu eskualdea\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Gorde aldaketak\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Streaming eskualdea\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Helbide elektronikoa beharrezkoa da\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Ezarpenak ondo gorde dira!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Discord jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"E-posta jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Pushbullet jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Zure 30 karaktereko <UsersGroupsLink>erabiltzaile edo talde identifikatzailea</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Pushover jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Telegram jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Zifratu e-posta mezuak <OpenPgpLink>OpenPGP</OpenPgpLink> erabiliz\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Bidali jakinarazpenak soinurik gabe\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Erabiltzaile edo talde gakoa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"PGP gako publikoa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Erabiltzailearen IDa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Jakinarazpen ezarpenak\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Sarbide tokena\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Bidali isilean\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Jakinarazpen soinua\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Txat ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"E-posta jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Sarbide tokena eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Pasahitz berria berretsi behar duzu\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Zure uneko pasahitza eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Pasahitz berri bat eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Pasahitzak bat egin behar dute\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Berretsi pasahitza\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Uneko pasahitza\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Pasahitz berria\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Pasahitza ondo gorde da!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Zerbait gaizki joan da ezarpenak gordetzean.\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Ezin dituzu zure baimenak aldatu.\",\n  \"components.UserProfile.pastdays\": \"{type} (azken {days} egunak)\",\n  \"components.UserProfile.limit\": \"{limit}-(e)tik {remaining}\",\n  \"components.UserProfile.localWatchlist\": \"{username}-(r)en jarraipen zerrenda\",\n  \"components.UserProfile.movierequests\": \"Film eskaerak\",\n  \"components.UserProfile.plexwatchlist\": \"Plex jarraipen-zerrenda\",\n  \"components.UserProfile.recentlywatched\": \"Berriki ikusita\",\n  \"components.UserProfile.recentrequests\": \"Eskaera berriak\",\n  \"components.UserProfile.requestsperdays\": \"{limit} geratzen dira\",\n  \"components.UserProfile.seriesrequest\": \"Telesail eskaerak\",\n  \"components.UserProfile.totalrequests\": \"Eskaera guztiak\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Baimenak ondo gorde dira!\",\n  \"i18n.resultsperpage\": \"Erakutsi {pageSize} emaitza orri bakoitzean\",\n  \"i18n.areyousure\": \"Ziur zaude?\",\n  \"i18n.request4k\": \"Eskatu 4K-n\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.noresults\": \"Emaitzarik ez.\",\n  \"i18n.notrequested\": \"Eskatu gabe\",\n  \"i18n.partiallyavailable\": \"Partzialki eskuragarri\",\n  \"i18n.restartRequired\": \"Berrabiarazi behar da\",\n  \"i18n.save\": \"Gorde aldaketak\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"Zerbitzariaren barneko errorea\",\n  \"pages.pagenotfound\": \"Orria ez da aurkitu\",\n  \"pages.somethingwentwrong\": \"Zerbait gaizki joan da\",\n  \"i18n.usersettings\": \"Erabiltzailearen ezarpenak\",\n  \"pages.returnHome\": \"Itzuli hasierara\",\n  \"pages.serviceunavailable\": \"Zerbitzua ez dago eskuragarri\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet proba jakinarazpena bidaltzeak huts egin du.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Slack jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Webhook jakinarazpen ezarpenak gordetzeak huts egin du.\",\n  \"components.ResetPassword.emailresetlink\": \"E-posta berreskuratze esteka\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Sarbide tokena eman behar duzu\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Zerbait gaizki joan da ezarpenak gordetzean.\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Konfiguratu erabiltzaileen ezarpen global eta lehenetsiak.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Eman TMDB genero ID bat\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Ez dituzu denboraldi nahiko eskaerarik\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Sortu <WebhookLink>Sarrera Webhook</WebhookLink> integrazio bat\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Eman TMDB estudioaren IDa\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB puntuazioa gorantz\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Hautatu gutxieneko erabilgarritasuna\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Editatu Sonarr zerbitzaria\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Gaitu agentea\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Ezarpenak ondo gorde dira!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Webhook proba jakinarazpena bidaltzeak huts egin du.\",\n  \"components.RequestModal.pendingapproval\": \"Zure eskaera onartzeko zain dago.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Eskatu bilduma 4K-n\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Gehitu Sonarr zerbitzari berria\",\n  \"components.Selector.searchGenres\": \"Hautatu generoak…\",\n  \"components.Selector.searchStatus\": \"Hautatu egoera...\",\n  \"components.Selector.showless\": \"Erakutsi gutxiago\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Erro karpeta\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Intzidentziaren deskribapena ondo editatu da!\",\n  \"components.RequestModal.requestedited\": \"<strong>{title}</strong>-(e)rako eskaera ondo editatu da!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.RequestModal.requestApproved\": \"<strong>{title}</strong> eskaera onartuta!\",\n  \"components.RequestModal.requestseries4ktitle\": \"Eskatu telesaila 4K-n\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Gotify proba jakinarazpena bidaltzen…\",\n  \"components.Settings.RadarrModal.hostname\": \"Ostalari-izena edo IP helbidea\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB puntuazioa beherantz\",\n  \"components.TvDetails.addtowatchlist\": \"Gehitu jarraipen zerrendara\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Aplikazioaren API tokena\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language}-(e)ko telesailak\",\n  \"components.RequestModal.selectmovies\": \"Hautatu filma(k)\",\n  \"components.RequestModal.selectseason\": \"Hautatu denboraldia(k)\",\n  \"components.Settings.Notifications.encryption\": \"Zifratze metodoa\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Zerbitzari lehenetsia\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr konexioa ondo ezarri da!\",\n  \"components.Settings.SonarrModal.server4k\": \"4K zerbitzaria\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Gailu lehenetsia\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"API gako berria ondo sortu da!\",\n  \"components.TvDetails.episodeRuntime\": \"Atalaren iraupena\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify jakinarazpenen ezarpenak ondo gorde dira!\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Kalitate profila\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Hautatu erro-karpeta\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Hurrengo telesailak\",\n  \"components.Login.loginwithapp\": \"Hasi saioa {appName}(r)ekin\",\n  \"components.Login.noadminerror\": \"Ez da administratzaile erabiltzailerik aurkitu zerbitzarian.\",\n  \"components.Login.orsigninwith\": \"Edo hasi saioa honekin\",\n  \"components.Selector.searchUsers\": \"Hautatu erabiltzaileak…\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Baldintzak\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Erro-karpeta\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Hautatu zerbitzua\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Hautatu etiketak\",\n  \"components.Settings.OverrideRuleModal.service\": \"Zerbitzua\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Kontu hau dagoeneko Plex erabiltzaile batera lotuta dago\",\n  \"components.Settings.overrideRulesDescription\": \"Gainidatze-arauek eskaera bat arauarekin bat datorrenean ordezkatuko diren propietateak zehazteko aukera ematen dute.\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Eman erabiltzaileei {mediaServerName} kontua erabiliz saioa hasteko aukera\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Ezin da {mediaServerName}era konektatu zure kredentzialak erabiliz\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Errore ezezaguna gertatu da\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Gainidazte arau berria\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Zure taldeko txatak gaiak gaituta baditu, hari/gai baten ID bat zehaztu dezakezu hemen\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Lotu {mediaServerName} kontua\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Gako-hitzak\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Parametro-aldaketak aplikatu aurretik baldintzak zehazten ditu. Eremu bakoitza balioztatu behar da aplikatu beharreko arauetarako (AND eragiketa). Eremu bat egiaztatutzat hartzen da propietateetariko bat, bat badatorren (OR eragiketa).\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Zure taldeko txatak gaiak gaituta baditu, hari/gai baten ID bat zehaztu dezakezu hemen\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"Hari/gaiaren IDa zenbaki oso positiboa izan behar da\",\n  \"components.Settings.Notifications.messageThreadId\": \"Hari/Gai ID\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Etiketak\",\n  \"components.Settings.OverrideRuleModal.users\": \"Erabiltzaileak\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Baldintzak\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Ezarpen hauen ordez zure edukiontzi/sistemako sare-parametroak erabili behar dira. Ikusi {docs} informazio gehiagorako.\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Goiko baldintzak betetzen direnean zein ezarpen aldatuko diren zehazten du.\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"EZ ezazu ezarpen hau gaitu egiten ari zarena ez badakizu!\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Behartu Seerr IPv4 helbideak konpontzera IPv6ren ordez\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Ezarri kanpoko API sarbidea irakurtzeko soilik (HTTPS behar du)\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Aplikatu arau hau hautatutako zerbitzura.\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Konfiguratu sare ezarpenak zure Seerr instantziarako.\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Gainidazte araua behar bezala sortu da!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Gainidazte araua ondo eguneratu da!\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Baimendu atal berezien eskaerak\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Behartu IPv4 ebazpena lehen\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Editatu gainidazte araua\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Hautatu kalitate profila\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Gaitu CSRF babesa\",\n  \"components.Settings.OverrideRuleModal.create\": \"Sortu araua\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Etiketarik ez.\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Kalitate profila\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Erro-karpeta\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Sare ezarpenak\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Generoak\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Hizkuntzak\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Ezarpenak\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Etiketak\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Generoa\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Gako-hitzak\",\n  \"components.Settings.OverrideRuleTile.language\": \"Hizkuntza\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Ezarpenak\",\n  \"components.Settings.OverrideRuleTile.users\": \"Erabiltzaileak\",\n  \"components.Settings.SettingsNetwork.docs\": \"dokumentazioa\",\n  \"components.Settings.SettingsNetwork.network\": \"Sarea\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Erabili ',' banatzaile gisa eta '*.' azpidomeinuetarako komodin gisa\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Baimendu Seerr-i bezeroen IP helbideak behar bezala erregistratzea proxy baten atzean\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Sartu zure {mediaServerName} kredentzialak zure kontua {applicationName}-rekin lotzeko.\",\n  \"components.Setup.librarieserror\": \"Baliozkotzeak huts egin du. Mesedez, aldatu liburutegiak berriro jarraitzeko.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Kontu hau dagoeneko {applicationName} erabiltzaile batekin lotuta dago\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Gutxienez autentifikazio metodo bat hautatu behar da.\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Zerbait gaizki joan da ezarpenak gordetzean.\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Baliozko ataka bat eman behar duzu\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Saihestu proxya helbide lokaletarako\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Konfiguratu saio hasiera metodoak erabiltzaileentzat.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Pasahitza eman behar duzu\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Erabiltzaile-izena eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Ezin da lotutako kontua ezabatu.\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Erabili SSL proxyrako\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Errore ezezaguna gertatu da\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Proxy ezikusitako helbideak\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Ezarpenak ondo gorde dira!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Gaitu proxy euskarria\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Gaitu {mediaServerName} saio hasiera\",\n  \"components.Settings.addrule\": \"Gainidazte arau berria\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) proxia\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Proxi ostalari-izena\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Proxy pasahitza\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Proxy ataka\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Proxy erabiltzaile-izena\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Saio-hasiera metodoak\",\n  \"components.Settings.overrideRules\": \"Gainidazte arauak\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Lotutako kontuak\",\n  \"components.Settings.menuNetwork\": \"Sarea\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Pasahitza\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Lotu\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Gehitzen…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Erabiltzaile-izena\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Ez duzu kanpoko konturik zure kontura lotuta.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Ez duzu erabiltzaile honen lotutako kontuak aldatzeko baimenik.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Kanpoko kontu hauek zure {applicationName} kontuarekin lotuta daude.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"Hari/gaiaren IDa zenbaki oso positiboa izan behar da\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Ezin da Plexera konektatu zure kredentzialak erabiliz\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Hari/Gai ID\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Lotutako kontuak\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Txertatutako kartela\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr-ek DNS bilaketak cachean gordetzen ditu errendimendua optimizatzeko eta beharrezkoak ez diren API deiak egitea saihesteko.\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Arazoaren deskribapena\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Ntfy jakinarazpenen ezarpenak behar bezala gorde dira!\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Eskuragarri dauden aldagaiak webhook txantiloi aldagaien atalean dokumentatuta daude\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Ez dago aukerarik eskuragarri\",\n  \"components.Settings.Notifications.embedPoster\": \"Txertatutako kartela\",\n  \"components.Settings.menuMetadataProviders\": \"Metadatu hornitzaileak\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Arakatzailea\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"{jobScheduleDays, plural, one {Egunero} other {{jobScheduleDays} egunetik behin}}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Sortuta\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Erabiltzaile-izena + pasahitz autentifikazioa\",\n  \"components.Discover.FilterSlideover.certification\": \"Edukiaren balorazioa\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNS cachea\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"DNS cachearen gutxieneko TTL\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Hutsegiteak\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Hautatutako metadatu hornitzaile guztiak martxan daude\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Metadatu hornitzailearen ezarpenak gordetzeak huts egin du\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Gaitu DNS bilaketen cachea errendimendua optimizatzeko eta beharrezkoak ez diren API deiak egitea saihesteko\",\n  \"components.Settings.clickTest\": \"Egin klik \\\"Probatu\\\" botoian metadatu hornitzaileekin konexioa egiaztatzeko\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"TMDB hornitzaileak ez du funtzionatzen, hautatu beste metadatu hornitzaile bat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Web push jakinarazpen ezarpenak ondo gorde dira!\",\n  \"components.Settings.metadataSettingsSaved\": \"Metadatu hornitzailearen ezarpenak gorde dira\",\n  \"components.Settings.seriesMetadataProvider\": \"Telesailen metadatuen hornitzailea\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"TVDB hornitzaileak ez du funtzionatzen, hautatu beste metadatu hornitzaile bat\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Txertatu kartela\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"{testUrl} gisa ezarri da proba-jakinarazpenaren URLabenetako webhook URLaren ordez.\",\n  \"components.Settings.metadataProviderSelection\": \"Metadatuen hornitzailearen hautaketa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Zerbait gaizki joan da web push-a gaitzean.\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Baztertu gako-hitzak\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Ziurtagiriak kargatzeak huts egin du\",\n  \"components.Selector.CertificationSelector.minRating\": \"Balorazio minimoa\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Hautatu ziurtagiri bat\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Hautatu herrialde bat\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Hasi idazten bilatzeko.\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Lehentasuna\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Lehentasun zenbaki bat ezarri behar duzu\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Gaitu agentea\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Pasahitza\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Ntfy probaren jakinarazpena ezin izan da bidali.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"ntfy proba jakinarazpena bidaltzen…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Ntfy proba jakinarazpena bidali da!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Tokena\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Token autentifikazioa\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Gaia\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Zerbitzariaren erro-URLa\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Erabiltzaile-izena\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Gai bat eman behar duzu\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"URL baliodun bat eman behar duzu\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Gutxienez jakinarazpen mota bat hautatu behar duzu\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Onartu URL aldagaiak\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Estatistika hauek DNS cache sarrera guztietan biltzen dira.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Helbide aktiboa\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Adina\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"{hostname} dns cachea hustu da.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Kontsultak\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Hutsegiteak\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Ostalari-izena\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Garbitu DNS cachea\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Kontsultak\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Kontsulta-tasa\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4 ordezkoak\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Ezkutatu eskuragarri dauden multimedia edukiak aurkikuntza-orrialdeetatik, baina ez bilaketa-emaitzetatik\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Baliozko URL bat eman behar duzu\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URLak ez du barra batean amaitu behar\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube URLa\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"YouTube bideoen oinarrizko URLa, auto-ostatutako YouTube instantzia bat erabiltzen bada.\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNS cachea\",\n  \"components.Settings.chooseProvider\": \"Aukeratu metadatu hornitzaileak eduki mota desberdinetarako\",\n  \"components.Settings.connectionTestFailed\": \"Konexio-probak huts egin du\",\n  \"components.Settings.failed\": \"Ez du funtzionatzen\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} ez da TMDB gako-hitz bat.\",\n  \"components.Settings.metadataProviderSettings\": \"Metadatu hornitzaileak\",\n  \"components.Settings.metadataSettings\": \"Metadatuen hornitzailearen ezarpenak\",\n  \"components.Settings.noSpecialCharacters\": \"Konfigurazioa TMDB gako-hitz IDen komaz bereizitako zerrenda bat izan behar da, eta ezin da komaz hasi edo amaitu.\",\n  \"components.Settings.nooptions\": \"Emaitzarik ez.\",\n  \"components.Settings.notTested\": \"Ez da probatu\",\n  \"components.Settings.operational\": \"Operatiboa\",\n  \"components.Settings.providerStatus\": \"Metadatuen hornitzailearen egoera\",\n  \"components.Settings.settings\": \"Ezarpenak\",\n  \"components.Settings.starttyping\": \"Hasi idazten bilatzeko.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Desgaitu web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Zerbait gaizki joan da web push-a desgaitzean.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Gaitu web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Motorra\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Kudeatu gailuak\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Ez duzu web push harpidetzarik erakusteko.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Sistema eragilea\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Harpidetza ezabatuta.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Zerbait gaizki joan da erabiltzailearen harpidetza ezabatzean.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"mota\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Ezezaguna\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Web push-a desgaitu da.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Web push-a gaitu da.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Web push jakinarazpenen ezarpenak gordetzeak huts egin du.\",\n  \"i18n.deleted\": \"Ezabatuta\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Hautatu metadatu hornitzaile bat\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Balorazio maximoa\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Ntfy jakinarazpenen ezarpenak ezin izan dira gorde.\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Txertatutako kartela\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Txertatutako kartela\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"DNS cachearen estatistika globalak\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Hutsegiteak\",\n  \"components.Settings.SettingsJobsCache.size\": \"Tamaina\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"API gakoa arbelera kopiatu da.\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"DNS cachearen gehienezko TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"EZ gaitu hau DNS bilaketekin arazoak badituzu\",\n  \"components.Settings.animeMetadataProvider\": \"Anime metadatuen hornitzailea\",\n  \"components.Settings.general\": \"Orokorra\",\n  \"components.Settings.no\": \"Ez\",\n  \"components.Settings.searchKeywords\": \"Bilatu gako hitzak…\",\n  \"components.Settings.valueRequired\": \"Balio bat eman behar duzu.\",\n  \"components.Settings.yes\": \"Bai\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Ezabatu harpidetza\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Gailua\",\n  \"i18n.completed\": \"Osatuta\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Seerr-i buruz\",\n  \"components.Settings.SettingsAbout.contribute\": \"Egin ekarpen bat\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Lagundu Seerr-i\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Gehienezko baliozko TTLa eman behar duzu\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Gutxieneko baliozko TTLa eman behar duzu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Harpidetza aktiboa\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Ezin izan da {services}-(e)ra konektatu. Baliteke informazioa eskuragarri ez egotea.\",\n  \"components.RequestList.unableToConnect\": \"Ezin izan da {services}-(e)ra konektatu. Baliteke informazioa eskuragarri ez egotea.\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"\\\"Prozesatu blokeatutako etiketak\\\" lanak orrialde kopuru hori blokeatutako zerrendan sartuko du ordenatze bakoitzean. Kopuru handiagoek blokeatutako zerrenda zehatzagoa sortuko dute, baina leku gehiago erabiliko dute.\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Bidali irteerako HTTP/HTTPS eskaera GUZTIAK proxy zerbitzari baten bidez (ostalaria/ataka). EZ du HTTPS, SSL edo ziurtagiri konfigurazioa gaitzen.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Gehitu automatikoki etiketak dituen edukia blokeo-zerrendan \\\"Prozesatu blokeo-zerrendako etiketak\\\" lana erabiliz\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Ezkutatu blokeatutako elementuak aurkikuntza-orrialdeetatik \\\"Blokeo-zerrenda kudeatu\\\" baimena duten erabiltzaile guztientzat\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Ziur zaude blokeatutako etiketak garbitu nahi dituzula?\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Ez da DNS bilaketarik cachean gorde oraindik.\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> blokeatuen zerrendatik kendu da.\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Eman baimena blokeatutako multimedia-zerrendan kudeatzeko.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Eman baimena blokeatutako multimedia ikusteko.\",\n  \"i18n.blocklistError\": \"Zerbait gaizki joan da. Saiatu berriro.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Eman baimena multimedia blokeo-zerrendan sartzeko.\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Mugatu blokeatutako edukia etiketa bakoitzeko\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Itsatsi blokeo-zerrendaren etiketaren konfigurazioa behean.\",\n  \"components.Settings.copyBlocklistedTags\": \"Blokeatutako zerrendako etiketak arbelean kopiatu dira.\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> dagoeneko blokeo-zerrendan sartu da.\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> ez dago blokeo-zerrendan.\",\n  \"components.Blocklist.showAllBlocklisted\": \"Blokeatutako multimedia guztia erakutsi\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Blokeatu edukia etiketekin\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Inportatu blokeatutako etiketa konfigurazioa\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Kopiatu blokeo-zerrendaren etiketen konfigurazioa\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Inportatu blokeo-zerrendako etiketa konfigurazioa\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> blokeo-zerrendan sartu da.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Kudeatu blokeatutako multimedia zerrenda.\",\n  \"components.Blocklist.blocklistedby\": \"{data} {erabiltzailea}-(r)engatik\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Ikusi blokeatutako multimedia.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Prozesatu blokeatutako etiketak\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Ezkutatu blokeatutako elementuak\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Ezer ez kopiatzeko\",\n  \"i18n.addToBlocklist\": \"Gehitu blokeo-zerrendan\",\n  \"i18n.removefromBlocklist\": \"Kendu blokeo-zerrendatik\",\n  \"component.BlocklistBlock.blocklistdate\": \"Noiz blokeatuta\",\n  \"component.BlocklistBlock.blocklistedby\": \"Honek blokeatuta\",\n  \"components.Blocklist.blocklistsettings\": \"Blokeo-zerrendaren ezarpenak\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Blokeatutako etiketak\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb Id-a\",\n  \"components.PermissionEdit.blocklistedItems\": \"Blokeatu multimedia.\",\n  \"components.PermissionEdit.manageblocklist\": \"Kudeatu blokeo-zerrenda\",\n  \"components.Settings.blocklistedTagsText\": \"Blokeatutako etiketak\",\n  \"component.BlocklistModal.blocklisting\": \"Blokeo-zerrendatzea\",\n  \"components.Blocklist.blocklistdate\": \"data\",\n  \"components.Blocklist.filterManual\": \"Eskuz\",\n  \"components.Blocklist.mediaName\": \"Izena\",\n  \"components.Blocklist.mediaType\": \"Mota\",\n  \"components.Layout.Sidebar.blocklist\": \"Blokeo-zerrenda\",\n  \"i18n.blocklist\": \"Blokeo-zerrenda\",\n  \"i18n.blocklisted\": \"Blokeatuta\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"API eskaeraren denbora-muga\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Gehienezko denbora (segundotan) kanpoko zerbitzuen erantzunak itxaroteko, hala nola Radarr/Sonarr. Ezarri 0 balioarekin denbora-mugarik gabe.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Baliozko denbora-muga eman behar duzu\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Monitorizatu denboraldi berriak\",\n  \"components.Discover.timeWindowDay\": \"Egunero\",\n  \"components.Discover.timeWindowWeek\": \"Astero\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Lehentasuna\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"1 eta 5 arteko lehentasuna eman behar duzu\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Goiburu pertsonalizatuak\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Gehitu goiburua\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Ezin dira baimen-goiburua eta baimen-goiburu pertsonalizatua aldi berean erabili. Kendu bat, mesedez.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Goiburu guztiek izena eta balioa izan behar dituzte\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Goiburuaren izena\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Kendu\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Gehitu HTTP goiburu pertsonalizatuak webhook eskaeretan sartzeko\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Goiburuaren balioa\"\n}\n"
  },
  {
    "path": "src/i18n/locale/fi.json",
    "content": "{\n  \"components.Discover.CreateSlider.editsuccess\": \"Liukusäädintä muokattu ja löytömuokkausasetukset tallennettu.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} elokuvaa\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Liukusäätimen nimi\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code> -levyn liittäminen ei onnistunut oikein. Kaikki tiedot poistetaan, kun säilö pysäytetään tai käynnistetään uudelleen.\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Suosio laskevassa järjestyksessä\",\n  \"components.AirDateBadge.airsrelative\": \"Esitys {relativeTime}\",\n  \"components.CollectionDetails.overview\": \"Yleiskatsaus\",\n  \"components.AirDateBadge.airedrelative\": \"Esitetty {relativeTime}\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Etsi studioita…\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Anna TMDB Network ID\",\n  \"components.Discover.CreateSlider.addfail\": \"Uuden liukusäätimen luominen epäonnistui.\",\n  \"components.CollectionDetails.requestcollection\": \"Pyydä kokoelma\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Lajityypin {genre} elokuvat\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Elokuvat kielellä {language}\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Suosio nousevassa järjestyksessä\",\n  \"components.Discover.CreateSlider.needresults\": \"Tarvitaan vähintään 1 tulos.\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Luo mukautettu liukusäädin\",\n  \"components.Discover.CreateSlider.editSlider\": \"Muokkaa liukusäädintä\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Sinun täytyy antaa datan arvo.\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Anna TMDB Studio ID\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Etsi tyylilajeja…\",\n  \"components.Discover.CreateSlider.editfail\": \"Liukusäätimen muokkaus epäonnistui.\",\n  \"components.Discover.CreateSlider.starttyping\": \"Aloita kirjoittaminen etsiäksesi.\",\n  \"components.Discover.CreateSlider.addSlider\": \"Lisää liukusäädin\",\n  \"components.CollectionDetails.requestcollection4k\": \"Pyydä kokoelma 4K-laadulla\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Anna hakukysely\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Anna TMDB Keyword ID\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} elokuvat\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Sinun tulee antaa nimi.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Ei tuloksia.\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Etsi avainsanoja…\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Elokuvat\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Anna TMDB Genre ID\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Julkaisupäivä laskevassa järjestyksessä\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Sarjat\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex katselulistalle</PlexWatchlistSupportLink> lisätty media näkyy täällä.\",\n  \"components.Discover.updatesuccess\": \"Päivitettiin tutustumisen mukautusasetukset.\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Jokin meni pieleen muokatessa ongelman kuvausta.\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Jokin meni pieleen lähettäessä ongelmaa.\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Arvostelut välillä {minValue} ja {maxValue}\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Pisteytys välillä {minValue} ja {maxValue}\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB Elokuvan Avainsana\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Lähetetty {relativeTime} käyttäjältä {username} (Muokattu)\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Haluatko varmasti poistaa ongelman?\",\n  \"components.IssueDetails.problemepisode\": \"Liittyvä jakso\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Liittyvä jakso\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Tuntematon\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Luotiin uusi liukusäädin ja tallennettiin ehdotusten kustomointiasetus.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Liukusäätimen poisto onnistui.\",\n  \"components.IssueDetails.IssueComment.edit\": \"Muokkaa kommenttia\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Jakso {episodeNumber}\",\n  \"components.Layout.Sidebar.requests\": \"Pyynnöt\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Sähköpostiosoite on pakollinen.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Salasana on pakollinen.\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Otsikko (A-Z) nousevassa järjestyksessä\",\n  \"components.Discover.resetfailed\": \"Jokin meni pieleen tutustumisen mukautusasetusten tyhjentämisessä.\",\n  \"components.Discover.upcoming\": \"Tulevat Elokuvat\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Sähköpostiosoite ei kelpaa.\",\n  \"components.Login.back\": \"Palaa takaisin\",\n  \"components.Login.credentialerror\": \"Käyttäjätunnus tai salasana on väärin.\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Julkaisupäivä nousevassa järjestyksessä\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Otsikko (A-Z) nousevassa järjestyksessä\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Otsikko (A-Z) laskevassa järjestyksessä\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB Rating nousevassa järjestyksessä\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB Rating laskevassa järjestyksessä\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} Sarjat\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Liukusäätimen poisto epäonnistui.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Vaihda näkyvyys\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Poista\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} Elokuvat\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Sarjat\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Ensiesitys nousevassa järjestyksessä\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Ensiesitys laskevassa järjestyksessä\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Suosio nousevassa järjestyksessä\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Suosio laskevassa järjestyksessä\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Otsikko (A-Z) laskevassa järjestyksessä\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB Rating nousevassa järjestyksessä\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB Rating laskevassa järjestyksessä\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Sarjat\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Sarjat\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Katselulistasi\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex Katselulista\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Tyhjennä aktiiviset suodattimet\",\n  \"components.Discover.FilterSlideover.filters\": \"Suodattimet\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Ensiesitys\",\n  \"components.Discover.FilterSlideover.from\": \"Alkaen\",\n  \"components.Discover.FilterSlideover.genres\": \"Tyylilaji\",\n  \"components.Discover.FilterSlideover.keywords\": \"Avainsanat\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Alkuperäinen kieli\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Julkaisupäivä\",\n  \"components.Discover.FilterSlideover.runtime\": \"Kesto\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minuutin kesto\",\n  \"components.Discover.FilterSlideover.status\": \"Tila\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Suoratoistopalvelut\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB Käyttäjien pisteytys\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB Pisteytystä\",\n  \"components.Discover.FilterSlideover.to\": \"Saakka\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Elokuvien tyylilajit\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Elokuvien tyylilajit\",\n  \"components.Discover.NetworkSlider.networks\": \"Kanavat\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Katselulistasi\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Viimeksi lisätty\",\n  \"components.Discover.StudioSlider.studios\": \"Studiot\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Sarjojen tyylilajit\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Sarjojen tyylilajit\",\n  \"components.Discover.createnewslider\": \"Luo uusi liukusäädin\",\n  \"components.Discover.customizediscover\": \"Mukauta Tutustumista\",\n  \"components.Discover.discover\": \"Tutustu\",\n  \"components.Discover.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex Katselulistalle</PlexWatchlistSupportLink> lisätty media näkyy täällä.\",\n  \"components.Discover.moviegenres\": \"Elokuvien tyylilajit\",\n  \"components.Discover.networks\": \"Kanavat\",\n  \"components.Discover.plexwatchlist\": \"Katselulistasi\",\n  \"components.Discover.popularmovies\": \"Suositut Elokuvat\",\n  \"components.Discover.populartv\": \"Suositut Sarjat\",\n  \"components.Discover.recentlyAdded\": \"Viimeksi Lisätty\",\n  \"components.Discover.recentrequests\": \"Viimeaikaiset pyynnöt\",\n  \"components.Discover.resetsuccess\": \"Tutustumisen mukautusasetukset tyhjennetty.\",\n  \"components.Discover.resettodefault\": \"Palauta Oletusasetukset\",\n  \"components.Discover.resetwarning\": \"Palauta liukusäätimet. Tämä poistaa myös mukautetut säätimet!\",\n  \"components.Discover.stopediting\": \"Lopeta Muokkaaminen\",\n  \"components.Discover.studios\": \"Studiot\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB Elokuvan tyylilaji\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB Elokuvan suoratoistopalvelu\",\n  \"components.Discover.tmdbnetwork\": \"TMDB Kanava\",\n  \"components.Discover.tmdbsearch\": \"TMDB Haku\",\n  \"components.Discover.tmdbstudio\": \"TMDB Studio\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB Sarjan tyylilaji\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB Sarjan Avainsana\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TV Suoratoistopalvelut\",\n  \"components.Discover.trending\": \"Trendaava\",\n  \"components.Discover.tvgenres\": \"Sarjojen Tyylilajit\",\n  \"components.Discover.upcomingmovies\": \"Tulevat Elokuvat\",\n  \"components.Discover.upcomingtv\": \"Tulevat Sarjat\",\n  \"components.Discover.updatefailed\": \"Jokin meni pieleen tutustumisen mukautusasetusten päivityksessä.\",\n  \"components.DownloadBlock.estimatedtime\": \"Arvioitu {time}\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Kausi {seasonNumber} Jakso {episodeNumber}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Haluatko varmasti poistaa kommentin?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Poista kommentti\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Lähetetty {relativeTime} käyttäjältä {username}\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Viesti on pakollinen\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Poista ongelma\",\n  \"components.IssueDetails.IssueDescription.description\": \"Kuvaus\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Muokkaa Kuvausta\",\n  \"components.IssueDetails.allepisodes\": \"Kaikki jaksot\",\n  \"components.IssueDetails.allseasons\": \"Kaikki Kaudet\",\n  \"components.IssueDetails.closeissue\": \"Sulje Ongelma\",\n  \"components.IssueDetails.closeissueandcomment\": \"Sulje Kommentilla\",\n  \"components.IssueDetails.commentplaceholder\": \"Lisää kommentti…\",\n  \"components.IssueDetails.comments\": \"Kommentit\",\n  \"components.IssueDetails.deleteissue\": \"Poista Ongelma\",\n  \"components.IssueDetails.episode\": \"Jakso {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Ongelma\",\n  \"components.IssueDetails.issuetype\": \"Tyyppi\",\n  \"components.IssueDetails.lastupdated\": \"Viimeksi Päivitetty\",\n  \"components.IssueDetails.leavecomment\": \"Kommentti\",\n  \"components.IssueDetails.nocomments\": \"Ei kommentteja.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} avattiin{relativeTime} käyttäjältä {username}\",\n  \"components.IssueDetails.openin4karr\": \"Avaa 4K:na {arr}\",\n  \"components.IssueDetails.openinarr\": \"Avaa {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Toista 4K:na kohteessa {mediaServerName}\",\n  \"components.IssueDetails.playonplex\": \"Toista kohteessa {mediaServerName}\",\n  \"components.IssueDetails.problemseason\": \"Liittyvä kausi\",\n  \"components.IssueDetails.reopenissue\": \"Avaa ongelma uudelleen\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Avaa uudelleen kommentilla\",\n  \"components.IssueDetails.season\": \"Kausi {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Ongelman kuvauksen muokkaus onnistui!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Ongelma poistaminen onnistui!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Jokin meni pieleen ongelmaa poistaessa.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Ongelman tila päivitetty onnistuneesti!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Jokin meni pieleen päivittäessä ongelman tilaa.\",\n  \"components.IssueDetails.unknownissuetype\": \"Tuntematon\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Tila\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tyyppi\",\n  \"components.IssueList.IssueItem.opened\": \"Avattu\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} käyttäjältä {user}\",\n  \"components.IssueList.IssueItem.viewissue\": \"Näytä ongelma\",\n  \"components.IssueList.issues\": \"Ongelmat\",\n  \"components.IssueList.showallissues\": \"Näytä kaikki ongelmat\",\n  \"components.IssueList.sortAdded\": \"Uusin\",\n  \"components.IssueList.sortModified\": \"Viimeksi muokattu\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Kaikki jaksot\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Kaikki kaudet\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Ekstrat\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Liittyvä jakso\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Liittyvä kausi\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Selitä ongelma yksityiskohtaisesti.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Ilmoita ongelma\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Kausi {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Lähetä ongelma\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Ongelma <strong>{title}</strong> lähetetty onnistuneesti!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Näytä ongelma\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Kuvaus on pakollinen\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Mikä vikana?\",\n  \"components.IssueModal.issueAudio\": \"Ääni\",\n  \"components.IssueModal.issueOther\": \"Muu\",\n  \"components.IssueModal.issueSubtitles\": \"Tekstitys\",\n  \"components.IssueModal.issueVideo\": \"Kuva\",\n  \"components.LanguageSelector.languageServerDefault\": \"Oletus ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Kaikki kielet\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Näyttökieli\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Etsi Elokuvia & Sarjoja\",\n  \"components.Layout.Sidebar.browsemovies\": \"Elokuvat\",\n  \"components.Layout.Sidebar.browsetv\": \"Sarjat\",\n  \"components.Layout.Sidebar.dashboard\": \"Tutustu\",\n  \"components.Layout.Sidebar.issues\": \"Ongelmat\",\n  \"components.Layout.Sidebar.settings\": \"Asetukset\",\n  \"components.Layout.Sidebar.users\": \"Käyttäjät\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Elokuvien Pyynnöt\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Sarjojen Pyynnöt\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profiili\",\n  \"components.Layout.UserDropdown.requests\": \"Pyynnöt\",\n  \"components.Layout.UserDropdown.settings\": \"Asetukset\",\n  \"components.Layout.UserDropdown.signout\": \"Kirjaudu ulos\",\n  \"components.Layout.VersionStatus.outofdate\": \"Vanhentunut\",\n  \"components.Login.adminerror\": \"Sinun täytyy käyttää admin-tunnusta kirjautuaksesi sisään.\",\n  \"pages.somethingwentwrong\": \"Jokin meni pieleen\",\n  \"pages.serviceunavailable\": \"Palvelu ei saatavilla\",\n  \"pages.returnHome\": \"Palaa etusivulle\",\n  \"pages.pagenotfound\": \"Sivua ei löydy\",\n  \"pages.oops\": \"Hups\",\n  \"pages.internalservererror\": \"Sisäinen palvelimen virhe\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"i18n.retry\": \"Yritä uudelleen\",\n  \"i18n.resultsperpage\": \"Näytä {pageSize} tulosta per sivu\",\n  \"i18n.restartRequired\": \"Uudelleenkäynnistys vaaditaan\",\n  \"i18n.resolved\": \"Ratkaistu\",\n  \"i18n.requesting\": \"Pyydetään…\",\n  \"i18n.requested\": \"Pyydetty\",\n  \"i18n.request4k\": \"Pyydä 4K:na\",\n  \"i18n.request\": \"Pyydä\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Tulossa olevat sarjat\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Pyynnöt\",\n  \"i18n.usersettings\": \"Käyttäjäasetukset\",\n  \"i18n.view\": \"Näytä\",\n  \"i18n.save\": \"Tallenna muutokset\",\n  \"i18n.unavailable\": \"Ei saatavilla\",\n  \"i18n.tvshows\": \"Sarjat\",\n  \"i18n.tvshow\": \"Sarja\",\n  \"i18n.testing\": \"Kokeillaan…\",\n  \"i18n.test\": \"Kokeile\",\n  \"i18n.status\": \"Tila\",\n  \"i18n.specials\": \"Erikoisjaksot\",\n  \"i18n.settings\": \"Asetukset\",\n  \"i18n.saving\": \"Tallennetaan…\",\n  \"i18n.movies\": \"Elokuvat\",\n  \"components.MovieDetails.addtowatchlist\": \"Lisää katselulistalle\",\n  \"i18n.loading\": \"Ladataan…\",\n  \"i18n.available\": \"Saatavilla\",\n  \"components.UserProfile.recentrequests\": \"Viimeaikaiset pyynnöt\",\n  \"i18n.cancel\": \"Peruuta\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Aktiivinen suodatin} other {# Aktiivista suodatinta}}\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Aktiivinen suodatin} other {# Aktiivista suodatinta}}\",\n  \"components.MovieDetails.overviewunavailable\": \"Yhteenveto ei saatavilla.\",\n  \"components.Login.signingin\": \"Kirjaudutaan sisään…\",\n  \"components.MovieDetails.digitalrelease\": \"Digitaalinen julkaisu\",\n  \"components.Login.description\": \"Koska tämä on ensimmäinen kirjautumisesi sovellukseen {applicationName}, sinun täytyy lisätä toimiva sähköpostiosoite.\",\n  \"components.Login.noadminerror\": \"Ylläpitäjän käyttäjää ei löytynyt palvelimelta.\",\n  \"components.Login.username\": \"Käyttäjänimi\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Tämä poistaa peruuttamattomasti kaikki tämän {mediaType}-kohteen tiedot, mukaan lukien kaikki pyynnöt. Jos tämä kohde on {mediaServerName}-kirjastossasi, mediatiedot luodaan uudelleen seuraavan skannauksen aikana.\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Lisäasetukset\",\n  \"components.Login.password\": \"Salasana\",\n  \"components.Login.port\": \"Portti\",\n  \"components.Login.save\": \"Lisää\",\n  \"components.Login.saving\": \"Lisätään…\",\n  \"components.Login.servertype\": \"Palvelimen tyyppi\",\n  \"components.Login.signin\": \"Kirjaudu sisään\",\n  \"components.Login.signinheader\": \"Kirjaudu sisään jatkaaksesi\",\n  \"components.Login.email\": \"Sähköpostiosoite\",\n  \"components.Login.emailtooltip\": \"Osoitteen ei tarvitse olla liitettynä {mediaServerName}-instanssiisi.\",\n  \"components.Login.enablessl\": \"Käytä SSL\",\n  \"components.Login.forgotpassword\": \"Unohtuiko salasana?\",\n  \"components.Login.hostname\": \"{mediaServerName} URL-osoite\",\n  \"components.Login.initialsignin\": \"Yhdistä\",\n  \"components.Login.initialsigningin\": \"Yhdistetään…\",\n  \"components.Login.invalidurlerror\": \"Yhdistäminen palvelimeen {mediaServerName} ei onnistunut.\",\n  \"components.Login.loginerror\": \"Jotain meni pieleen kirjautumisessa.\",\n  \"components.Login.loginwithapp\": \"Kirjaudu sisään sovelluksella {appName}\",\n  \"components.Login.orsigninwith\": \"Tai kirjaudu sisään käyttäen\",\n  \"components.Login.signinwithjellyfin\": \"Käytä palvelimesi {mediaServerName} tiliä\",\n  \"components.Login.signinwithoverseerr\": \"Käytä {applicationTitle}-tiliä\",\n  \"components.Login.signinwithplex\": \"Käytä Plex-tiliäsi\",\n  \"components.Login.title\": \"Lisää sähköposti\",\n  \"components.ManageSlideOver.downloadstatus\": \"Lataukset\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Media\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Ei pyyntöjä.\",\n  \"components.ManageSlideOver.markavailable\": \"Merkitse saatavilla olevaksi\",\n  \"components.ManageSlideOver.openarr\": \"Avaa ohjelmassa {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Avaa ohjelmassa 4K {arr}\",\n  \"components.ManageSlideOver.opentautulli\": \"Avaa Tautullissa\",\n  \"components.ManageSlideOver.playedby\": \"Toistanut\",\n  \"components.ManageSlideOver.tvshow\": \"sarja\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Näytä lisää\",\n  \"components.Login.urlBase\": \"URL-osoitteen pohja\",\n  \"components.Login.validationEmailFormat\": \"Virheellinen sähköposti\",\n  \"components.Login.validationEmailRequired\": \"Sinun täytyy antaa sähköposti\",\n  \"components.Login.validationPortRequired\": \"Sinun täytyy antaa toimiva portin numero\",\n  \"components.Login.validationemailformat\": \"Toimiva sähköposti vaaditaan\",\n  \"components.Login.validationemailrequired\": \"Sinun täytyy antaa toimiva sähköpostiosoite\",\n  \"components.Login.validationhostformat\": \"Toimiva URL-osoite vaaditaan\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL vaaditaan\",\n  \"components.Login.validationpasswordrequired\": \"Sinun täytyy antaa salasana\",\n  \"components.Login.validationservertyperequired\": \"Valitse palvelimen tyyppi\",\n  \"components.Login.validationusernamerequired\": \"Käyttäjänimi vaaditaan\",\n  \"components.ManageSlideOver.alltime\": \"Koko ajalta\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Tyhjennä data\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Avoimet ongelmat\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K Media\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Tämä poistaa tämän {mediaType}-tiedoston peruuttamattomasti ohjelmasta {arr}, kaikki tiedostot mukaan lukien.\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Hallinnoi {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Merkitse saatavilla olevaksi 4K-laadulla\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Merkitse kaikki tuotantokaudet saatavilla olevaksi 4K-laadulla\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Merkitse kaikki tuotantokaudet saatavilla olevaksi\",\n  \"components.ManageSlideOver.removearr\": \"Poista ohjelmasta {arr}\",\n  \"components.MovieDetails.budget\": \"Budjetti\",\n  \"components.MovieDetails.cast\": \"Näyttelijät\",\n  \"components.MovieDetails.downloadstatus\": \"Latauksen tila\",\n  \"components.MovieDetails.markavailable\": \"Merkitse saatavilla\",\n  \"components.MovieDetails.openradarr\": \"Avaa elokuva ohjelmassa Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"Avaa elokuva ohjelmassa 4K Radarr\",\n  \"components.MovieDetails.originallanguage\": \"Alkuperäinen kieli\",\n  \"components.MovieDetails.originaltitle\": \"Alkuperäinen nimi\",\n  \"components.MovieDetails.overview\": \"Yhteenveto\",\n  \"components.MovieDetails.physicalrelease\": \"Fyysinen julkaisu\",\n  \"i18n.areyousure\": \"Oletko varma?\",\n  \"i18n.back\": \"Takaisin\",\n  \"i18n.approve\": \"Hyväksy\",\n  \"i18n.all\": \"Kaikki\",\n  \"i18n.advanced\": \"Lisäasetukset\",\n  \"i18n.approved\": \"Hyväksytty\",\n  \"components.UserProfile.requestsperdays\": \"{limit} jäljellä\",\n  \"i18n.movie\": \"Elokuva\",\n  \"i18n.importing\": \"Tuodaan…\",\n  \"i18n.import\": \"Tuo\",\n  \"i18n.failed\": \"Epäonnistui\",\n  \"i18n.experimental\": \"Kokeellinen\",\n  \"i18n.edit\": \"Muokkaa\",\n  \"i18n.deleting\": \"Poistetaan…\",\n  \"i18n.delete\": \"Poista\",\n  \"i18n.next\": \"Seuraava\",\n  \"i18n.decline\": \"Hylkää\",\n  \"i18n.collection\": \"Kokoelma\",\n  \"i18n.close\": \"Sulje\",\n  \"i18n.canceling\": \"Perutaan…\",\n  \"i18n.declined\": \"Hylätty\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Aktiivinen suodatin} other {# Aktiivista suodatinta}}\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Jakso} other {Jaksoja}}\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Tuotantokausi} other {Tuotantokausia}}\",\n  \"components.ManageSlideOver.movie\": \"elokuva\",\n  \"components.UserProfile.recentlywatched\": \"Viimeaikaiset katselut\",\n  \"components.UserProfile.plexwatchlist\": \"Plex-katselulista\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Lähetä ilmoituksia, kun mediapyyntöjä hyväksytään manuaalisesti.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Pyyntö hyväksytty\",\n  \"i18n.pending\": \"Odottaa\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Kehitys\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Vakaa\",\n  \"i18n.partiallyavailable\": \"Osittain saatavilla\",\n  \"i18n.previous\": \"Edellinen\",\n  \"i18n.processing\": \"Käsitellään\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL-osoite ei saa päättyä kauttaviivaan\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Saat ilmoituksen, kun seurantalistallasi oleville kohteille lähetetään automaattisesti uusia mediapyyntöjä.\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {päivä} other {päivää}}\",\n  \"components.Settings.mediaTypeMovie\": \"elokuva\",\n  \"components.TvDetails.recommendations\": \"Suositukset\",\n  \"components.Selector.showmore\": \"Näytä lisää\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"URL-osoitteen pohja ei saa päättyä kauttaviivaan\",\n  \"components.PersonDetails.alsoknownas\": \"Tunnetaan myös nimeltä: {names}\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL-osoitteen pohjassa on oltava alussa kauttaviiva\",\n  \"components.RequestCard.approverequest\": \"Hyväksy pyyntö\",\n  \"components.RequestModal.cancel\": \"Peruuta pyyntö\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL-osoitteen pohjassa on oltava alussa kauttaviiva\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL-osoite ei saa päättyä kauttaviivaan\",\n  \"components.QuotaSelector.unlimited\": \"Rajoittamaton\",\n  \"components.RequestBlock.decline\": \"Hylkää pyyntö\",\n  \"components.RequestModal.errorediting\": \"Pyyntöä muokattaessa tapahtui virhe.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL-osoite ei saa päättyä kauttaviivaan\",\n  \"components.RequestList.RequestItem.failedretry\": \"Jotain meni pieleen, kun pyyntöä yritettiin uudelleen.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Pyyntö hyväksytään automaattisesti\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Tuotantokausi} other {Tuotantokausia}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Tuotantokausi} other {Tuotantokausia}}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Tuotantokausi} other {Tuotantokausia}}\",\n  \"components.RequestButton.approve4krequests\": \"Hyväksy {requestCount, plural, one {4K Pyyntö} other {{requestCount} 4K Pyyntöä}}\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PermissionEdit.request\": \"Pyydä\",\n  \"components.ManageSlideOver.removearr4k\": \"Poista ohjelmasta 4K {arr}\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"URL-pohjan alussa on oltava kauttaviiva\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"URL-pohja ei saa päättyä kauttaviivaan\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL-osoite ei saa päättyä kauttaviivaan\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {toisto} other {toistoa}}\",\n  \"components.MovieDetails.recommendations\": \"Suositukset\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Kaikki näyttelijät\",\n  \"components.MovieDetails.managemovie\": \"Hallinnoi elokuvaa\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB-käyttäjän pisteet\",\n  \"components.MovieDetails.mark4kavailable\": \"Merkitse saatavilla olevaksi 4K-laadulla\",\n  \"components.MovieDetails.play\": \"Toista kohteessa {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Toista 4K kohteessa {mediaServerName}\",\n  \"components.MovieDetails.productioncountries\": \"Tuotanto{countryCount, plural, one {maa} other {maat}}\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Julkaisupäivä} other {Julkaisupäivää}}\",\n  \"components.MovieDetails.removefromwatchlist\": \"Poista katselulistalta\",\n  \"components.MovieDetails.reportissue\": \"Ilmoita ongelmasta\",\n  \"components.MovieDetails.revenue\": \"Tulot\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoesin yleisöpisteet\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes -tomaattimittari\",\n  \"components.MovieDetails.runtime\": \"{minutes} minuuttia\",\n  \"components.MovieDetails.showless\": \"Näytä vähemmän\",\n  \"components.MovieDetails.showmore\": \"Näytä lisää\",\n  \"components.MovieDetails.similar\": \"Samankaltaisia nimikkeitä\",\n  \"components.MovieDetails.streamingproviders\": \"Katsottavissa palveluissa\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studiot}}\",\n  \"components.MovieDetails.theatricalrelease\": \"Teatterijulkaisu\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB-käyttäjän pisteet\",\n  \"components.MovieDetails.viewfullcrew\": \"Näytä koko tuotantoryhmä\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Koko tuotantoryhmä\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> Poistettiin katselulistalta onnistuneesti!\",\n  \"components.MovieDetails.watchlistError\": \"Jotain meni pieleen. Yritä uudelleen.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> lisättiin katselulistalle onnistuneesti!\",\n  \"components.MovieDetails.watchtrailer\": \"Katso traileri\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Saat ilmoituksen, kun muut käyttäjät kommentoivat ongelmia.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Saat ilmoituksen, kun muut käyttäjät avaavat ongelmia uudelleen.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Saat ilmoituksen, kun muut käyttäjät ovat ratkaisseet ongelmia.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Ongelman kommentti\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Lähetä ilmoituksia, kun ongelmiin tulee uusia kommentteja.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Ongelma ilmoitettu\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Lähetä ilmoituksia, kun ongelmista ilmoitetaan.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Ongelma avattu uudelleen\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Lähetä ilmoituksia, kun ongelmia avataan uudelleen.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Ongelma ratkaistu\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Lähetä ilmoituksia, kun ongelmat on ratkaistu.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Lähetä ilmoituksia, kun käyttäjät lähettävät uusia mediapyyntöjä, jotka hyväksytään automaattisesti.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Pyyntö lähetetty automaattisesti\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Pyyntö saatavilla\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Lähetä ilmoituksia, kun mediapyyntöjä tulee saataville.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Pyyntö hylätty\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Lähetä ilmoituksia, kun mediapyyntöjä hylätään.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Ilmoitustyypit\",\n  \"components.PersonDetails.appearsin\": \"Esiintymiset\",\n  \"components.PersonDetails.ascharacter\": \"hahmona {character}\",\n  \"components.PersonDetails.birthdate\": \"Syntynyt {birthdate}\",\n  \"components.PermissionEdit.request4k\": \"Pyydä 4K-laadulla\",\n  \"components.RegionSelector.regionDefault\": \"Kaikki alueet\",\n  \"components.RegionSelector.regionServerDefault\": \"Oletus ({region})\",\n  \"components.RequestBlock.approve\": \"Hyväksy pyyntö\",\n  \"components.RequestBlock.delete\": \"Poista pyyntö\",\n  \"components.RequestBlock.edit\": \"Muokkaa pyyntöä\",\n  \"components.RequestBlock.languageprofile\": \"Kieliprofiili\",\n  \"components.RequestBlock.lastmodifiedby\": \"Viimeksi muokannut\",\n  \"components.RequestBlock.profilechanged\": \"Laatuprofiili\",\n  \"components.RequestBlock.requestdate\": \"Pyyntöpäivämäärä\",\n  \"components.RequestBlock.requestedby\": \"Pyytäjä\",\n  \"components.RequestBlock.requestoverrides\": \"Pyyntöjen ohitukset\",\n  \"components.RequestBlock.rootfolder\": \"Juurikansio\",\n  \"components.RequestBlock.server\": \"Kohdepalvelin\",\n  \"components.RequestButton.approverequest\": \"Hyväksy pyyntö\",\n  \"components.RequestButton.approverequest4k\": \"Hyväksy 4K Pyyntö\",\n  \"components.RequestButton.declinerequest\": \"Hylkää pyyntö\",\n  \"components.RequestButton.declinerequest4k\": \"Hylkää 4K Pyyntö\",\n  \"components.RequestButton.requestmore\": \"Pyydä lisää\",\n  \"components.RequestButton.requestmore4k\": \"Pyydä lisää 4K-laadulla\",\n  \"components.RequestButton.viewrequest\": \"Näytä pyyntö\",\n  \"components.RequestButton.viewrequest4k\": \"Näytä 4K Pyyntö\",\n  \"components.RequestCard.cancelrequest\": \"Peruuta pyyntö\",\n  \"components.RequestCard.declinerequest\": \"Hylkää pyyntö\",\n  \"components.RequestCard.deleterequest\": \"Poista pyyntö\",\n  \"components.RequestCard.editrequest\": \"Muokkaa pyyntöä\",\n  \"components.RequestCard.failedretry\": \"Jotain meni pieleen uudelleenpyytäessä.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} Ei löydy\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestCard.unknowntitle\": \"Tuntematon nimike\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Peruuta pyyntö\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Poista pyyntö\",\n  \"components.RequestList.RequestItem.editrequest\": \"Muokkaa pyyntöä\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} Ei löydy\",\n  \"components.RequestList.RequestItem.modified\": \"Muokattu\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} käyttäjältä {user}\",\n  \"components.RequestList.RequestItem.profileName\": \"Profiili\",\n  \"components.RequestList.RequestItem.removearr\": \"Poista ohjelmasta {arr}\",\n  \"components.RequestList.RequestItem.requested\": \"Pyydetty\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Pyydetty\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Tuntematon nimike\",\n  \"components.RequestList.requests\": \"Pyynnöt\",\n  \"components.RequestList.showallrequests\": \"Näytä kaikki pyynnöt\",\n  \"components.RequestList.sortAdded\": \"Uusin\",\n  \"components.RequestList.sortModified\": \"Viimeksi muokattu\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Lisäasetukset\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"elokuva\",\n  \"components.RequestModal.edit\": \"Muokkaa pyyntöä\",\n  \"components.RequestModal.requestcollectiontitle\": \"Pyydä kokoelma\",\n  \"components.RequestModal.pendingrequest\": \"Odottava pyyntö\",\n  \"components.RequestModal.approve\": \"Hyväksy pyyntö\",\n  \"components.RequestModal.autoapproval\": \"Automaattinen hyväksyntä\",\n  \"components.RequestModal.alreadyrequested\": \"Pyydetty jo\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL-osoitteen pohja ei saa päättyä kauttaviivaan\",\n  \"components.Settings.SettingsAbout.about\": \"Tietoja\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"URL-osoitteen alussa on oltava kauttaviiva\",\n  \"components.Settings.mediaTypeSeries\": \"sarja\",\n  \"components.Settings.menuAbout\": \"Tietoja\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Ongelman kuvaus\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.PermissionEdit.autorequestMovies\": \"Automaattiset elokuvapyynnöt\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Anna oikeus automaattisille ei-4K elokuvapyynnöille Plex katsomislistan kautta.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Automaattiset sarjapyynnöt\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Anna oikeus automaattisille ei-4K sarjapyynnöille Plex katsomislistan kautta.\",\n  \"components.PermissionEdit.request4kDescription\": \"Anna oikeus jättää pyyntöjä 4K medialle.\",\n  \"components.PermissionEdit.request4kMovies\": \"Pyydä 4K elokuvia\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Anna oikeus pyytää 4K elokuvia.\",\n  \"components.PermissionEdit.request4kTv\": \"Pyydä 4K sarjoja\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Anna oikeus pyytää 4K sarjoja.\",\n  \"components.PermissionEdit.requestDescription\": \"Anna oikeus pyytää ei-4K mediaa.\",\n  \"components.PermissionEdit.requestMovies\": \"Pyydä elokuvia\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Anna oikeus pyytää ei-4K elokuvia.\",\n  \"components.PermissionEdit.requestTv\": \"Pyydä sarjoja\",\n  \"components.PermissionEdit.requestTvDescription\": \"Anna oikeus pyytää ei-4K sarjoja.\",\n  \"components.PermissionEdit.users\": \"Hallinnoi käyttäjiä\",\n  \"components.PermissionEdit.usersDescription\": \"Anna oikeus hallinnoida käyttäjiä. Käyttäjät joilla on tämä oikeus, eivät voi muokata admin käyttäjiä, tai antaa admin oikeuksia.\",\n  \"components.PermissionEdit.viewissues\": \"Näytä ongelmat\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Anna oikeus tarkastella muiden käyttäjien raportoimia ongelmia.\",\n  \"components.PermissionEdit.viewrecent\": \"Näytä viimeksi lisätyt\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Anna oikeus tarkastella viimeksi lisättyä mediaa.\",\n  \"components.PermissionEdit.viewrequests\": \"Näytä pyynnöt\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Anna oikeus tarkastella muiden käyttäjien jättämiä pyyntöjä.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Tarkastele {mediaServerName} katsomislistoja\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Anna oikeus tarkastella muiden käyttäjien {mediaServerName} katsomislistoja.\",\n  \"components.QuotaSelector.movieRequests\": \"\",\n  \"components.QuotaSelector.movies\": \"\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Ei tarpeeksi pyyntöjä jäljellä kausille\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"\",\n  \"components.RequestModal.pending4krequest\": \"\",\n  \"components.RequestModal.pendingapproval\": \"Pyyntösi odottaa hyväksymistä.\",\n  \"components.RequestModal.requestApproved\": \"\",\n  \"components.RequestModal.requestCancel\": \"\",\n  \"components.RequestModal.requestcancelled\": \"\",\n  \"components.RequestModal.requestcollection4ktitle\": \"\",\n  \"components.RequestModal.requestedited\": \"\",\n  \"components.RequestModal.requesterror\": \"Jotain meni vikaan pyynnön jättämisessä.\",\n  \"components.RequestModal.requestfrom\": \"\",\n  \"components.RequestModal.requestmovie4ktitle\": \"\",\n  \"components.RequestModal.requestmovies\": \"\",\n  \"components.RequestModal.requestmovies4k\": \"\",\n  \"components.RequestModal.requestseasons\": \"\",\n  \"components.RequestModal.requestseasons4k\": \"\",\n  \"components.RequestModal.requestseries4ktitle\": \"\",\n  \"components.RequestModal.selectmovies\": \"\",\n  \"components.ResetPassword.emailresetlink\": \"\",\n  \"components.Search.searchresults\": \"Haun tulokset\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Valitse maa\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Aloita kirjoittamaan hakeaksesi.\",\n  \"components.Selector.inProduction\": \"Tuotannossa\",\n  \"components.Selector.nooptions\": \"Ei tuloksia.\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"Suunnitteilla\",\n  \"components.Selector.searchGenres\": \"\",\n  \"components.Selector.searchKeywords\": \"Etsi avainsanoja…\",\n  \"components.Selector.searchStatus\": \"Valitse tila...\",\n  \"components.Selector.searchStudios\": \"Etsi studioita…\",\n  \"components.Selector.searchUsers\": \"Valitse käyttäjät…\",\n  \"components.Selector.showless\": \"Näytä vähemmän\",\n  \"components.Selector.starttyping\": \"Aloita kirjoittamaan hakeaksesi.\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Prioriteetti\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Salasana\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Käyttäjänimi\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.Settings.Notifications.agentenabled\": \"\",\n  \"components.Settings.Notifications.allowselfsigned\": \"\",\n  \"components.Settings.Notifications.authPass\": \"\",\n  \"components.Settings.Notifications.authUser\": \"\",\n  \"components.Settings.Notifications.botAPI\": \"\",\n  \"components.Settings.Notifications.botApiTip\": \"\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"\",\n  \"components.Settings.Notifications.botUsername\": \"\",\n  \"components.Settings.Notifications.botUsernameTip\": \"\",\n  \"components.Settings.Notifications.chatId\": \"\",\n  \"components.Settings.Notifications.chatIdTip\": \"\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"\",\n  \"components.Settings.Notifications.emailsender\": \"\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.enableMentions\": \"\",\n  \"components.Settings.Notifications.encryption\": \"\",\n  \"components.Settings.Notifications.encryptionDefault\": \"\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"\",\n  \"components.Settings.Notifications.encryptionNone\": \"\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"\",\n  \"components.Settings.Notifications.encryptionTip\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.pgpPassword\": \"\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"\",\n  \"components.Settings.Notifications.sendSilently\": \"\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"\",\n  \"components.Settings.Notifications.senderName\": \"\",\n  \"components.Settings.Notifications.smtpHost\": \"\",\n  \"components.Settings.Notifications.smtpPort\": \"\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"\",\n  \"components.Settings.Notifications.validationEmail\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"\",\n  \"components.Settings.Notifications.validationTypes\": \"\",\n  \"components.Settings.Notifications.validationUrl\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.Notifications.webhookUrl\": \"\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Laatuprofiili\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Juurikansio\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Valitse laatuprofiili\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Valitse juurikansio\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.add\": \"\",\n  \"components.Settings.RadarrModal.announced\": \"\",\n  \"components.Settings.RadarrModal.apiKey\": \"\",\n  \"components.Settings.RadarrModal.baseUrl\": \"\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"\",\n  \"components.Settings.RadarrModal.createradarr\": \"\",\n  \"components.Settings.RadarrModal.default4kserver\": \"\",\n  \"components.Settings.RadarrModal.defaultserver\": \"\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"\",\n  \"components.Settings.RadarrModal.editradarr\": \"\",\n  \"components.Settings.RadarrModal.enableSearch\": \"\",\n  \"components.Settings.RadarrModal.externalUrl\": \"\",\n  \"components.Settings.RadarrModal.hostname\": \"\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Elokuvateattereissa\",\n  \"components.Settings.RadarrModal.loadingTags\": \"\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"\",\n  \"components.Settings.RadarrModal.notagoptions\": \"\",\n  \"components.Settings.RadarrModal.port\": \"\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Laatuprofiili\",\n  \"components.Settings.RadarrModal.released\": \"Julkaistu\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Juurikansio\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Valitse laatuprofiili\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Valitse juurikansio\",\n  \"components.Settings.RadarrModal.selecttags\": \"\",\n  \"components.Settings.RadarrModal.server4k\": \"\",\n  \"components.Settings.RadarrModal.servername\": \"\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"\",\n  \"components.Settings.RadarrModal.tagRequests\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.RadarrModal.tags\": \"\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Viimeisin\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Julkaisupäivämäärää ei tiedossa.\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Muutosloki\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Näytä muutosloki\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Näytä GitHub:issa\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"\",\n  \"components.Settings.SettingsJobsCache.command\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.process\": \"\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"\",\n  \"components.Settings.SettingsLogs.extraData\": \"\",\n  \"components.Settings.SettingsLogs.filterError\": \"\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"\",\n  \"components.Settings.SettingsLogs.label\": \"\",\n  \"components.Settings.SettingsLogs.level\": \"\",\n  \"components.Settings.SettingsLogs.logDetails\": \"\",\n  \"components.Settings.SettingsLogs.logs\": \"\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"\",\n  \"components.Settings.SettingsLogs.message\": \"\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"\",\n  \"components.Settings.SettingsLogs.showall\": \"\",\n  \"components.Settings.SettingsLogs.time\": \"\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"\",\n  \"components.Settings.SettingsMain.apikey\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"\",\n  \"components.Settings.SettingsMain.applicationurl\": \"\",\n  \"components.Settings.SettingsMain.cacheImages\": \"\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.general\": \"Yleiset\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Yleiset asetukset\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Muuta yleisiä- ja oletusasetuksia.\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.locale\": \"\",\n  \"components.Settings.SettingsMain.originallanguage\": \"\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"\",\n  \"components.Settings.SettingsUsers.localLogin\": \"\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.userSettings\": \"\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"\",\n  \"components.Settings.SettingsUsers.users\": \"\",\n  \"components.Settings.SonarrModal.add\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.animeTags\": \"\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"\",\n  \"components.Settings.SonarrModal.apiKey\": \"\",\n  \"components.Settings.SonarrModal.baseUrl\": \"\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.createsonarr\": \"\",\n  \"components.Settings.SonarrModal.default4kserver\": \"\",\n  \"components.Settings.SonarrModal.defaultserver\": \"\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.editsonarr\": \"\",\n  \"components.Settings.SonarrModal.enableSearch\": \"\",\n  \"components.Settings.SonarrModal.externalUrl\": \"\",\n  \"components.Settings.SonarrModal.hostname\": \"\",\n  \"components.Settings.SonarrModal.languageprofile\": \"\",\n  \"components.Settings.SonarrModal.loadingTags\": \"\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"\",\n  \"components.Settings.SonarrModal.notagoptions\": \"\",\n  \"components.Settings.SonarrModal.port\": \"\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"\",\n  \"components.Settings.SonarrModal.rootfolder\": \"\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"\",\n  \"components.Settings.SonarrModal.selecttags\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.server4k\": \"\",\n  \"components.Settings.SonarrModal.servername\": \"\",\n  \"components.Settings.SonarrModal.ssl\": \"\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SonarrModal.tags\": \"\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.activeProfile\": \"\",\n  \"components.Settings.addradarr\": \"\",\n  \"components.Settings.address\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.addsonarr\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.currentlibrary\": \"\",\n  \"components.Settings.default\": \"\",\n  \"components.Settings.default4k\": \"\",\n  \"components.Settings.deleteServer\": \"\",\n  \"components.Settings.deleteserverconfirm\": \"\",\n  \"components.Settings.email\": \"\",\n  \"components.Settings.experimentalTooltip\": \"\",\n  \"components.Settings.externalUrl\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.hostname\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.librariesRemaining\": \"\",\n  \"components.Settings.manualscan\": \"\",\n  \"components.Settings.manualscanDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuGeneralSettings\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuJobs\": \"\",\n  \"components.Settings.menuLogs\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.menuNotifications\": \"\",\n  \"components.Settings.menuPlexSettings\": \"\",\n  \"components.Settings.menuServices\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noDefault4kServer\": \"\",\n  \"components.Settings.noDefaultNon4kServer\": \"\",\n  \"components.Settings.noDefaultServer\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"\",\n  \"components.Settings.notifications\": \"\",\n  \"components.Settings.notificationsettings\": \"\",\n  \"components.Settings.notrunning\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.plex\": \"\",\n  \"components.Settings.plexlibraries\": \"\",\n  \"components.Settings.plexlibrariesDescription\": \"\",\n  \"components.Settings.plexsettings\": \"\",\n  \"components.Settings.plexsettingsDescription\": \"\",\n  \"components.Settings.port\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.radarrsettings\": \"\",\n  \"components.Settings.restartrequiredTooltip\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scan\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.scanning\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.serverLocal\": \"\",\n  \"components.Settings.serverRemote\": \"\",\n  \"components.Settings.serverSecure\": \"\",\n  \"components.Settings.serverpreset\": \"\",\n  \"components.Settings.serverpresetLoad\": \"\",\n  \"components.Settings.serverpresetManualMessage\": \"\",\n  \"components.Settings.serverpresetRefreshing\": \"\",\n  \"components.Settings.serviceSettingsDescription\": \"\",\n  \"components.Settings.services\": \"\",\n  \"components.Settings.settingUpPlexDescription\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.sonarrsettings\": \"\",\n  \"components.Settings.ssl\": \"\",\n  \"components.Settings.startscan\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.tautulliApiKey\": \"\",\n  \"components.Settings.tautulliSettings\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.toastPlexConnecting\": \"\",\n  \"components.Settings.toastPlexConnectingFailure\": \"\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"\",\n  \"components.Settings.toastPlexRefresh\": \"\",\n  \"components.Settings.toastPlexRefreshFailure\": \"\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.urlBase\": \"\",\n  \"components.Settings.validationApiKey\": \"\",\n  \"components.Settings.validationHostnameRequired\": \"\",\n  \"components.Settings.validationPortRequired\": \"\",\n  \"components.Settings.validationUrl\": \"\",\n  \"components.Settings.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.webAppUrl\": \"\",\n  \"components.Settings.webAppUrlTip\": \"\",\n  \"components.Settings.webhook\": \"\",\n  \"components.Settings.webpush\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.configureservices\": \"\",\n  \"components.Setup.continue\": \"\",\n  \"components.Setup.finish\": \"\",\n  \"components.Setup.finishing\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.setup\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinMessage\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.Setup.welcome\": \"\",\n  \"components.StatusBadge.managemedia\": \"Hallinnoi {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"\",\n  \"components.StatusBadge.playonplex\": \"\",\n  \"components.StatusBadge.seasonepisodenumber\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.StatusBadge.status\": \"\",\n  \"components.StatusBadge.status4k\": \"\",\n  \"components.StatusChecker.appUpdated\": \"\",\n  \"components.StatusChecker.appUpdatedDescription\": \"\",\n  \"components.StatusChecker.reloadApp\": \"\",\n  \"components.StatusChecker.restartRequired\": \"\",\n  \"components.StatusChecker.restartRequiredDescription\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.cleardata\": \"\",\n  \"components.TitleCard.mediaerror\": \"\",\n  \"components.TitleCard.tvdbid\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.Season.noepisodes\": \"\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.anime\": \"\",\n  \"components.TvDetails.cast\": \"\",\n  \"components.TvDetails.episodeCount\": \"\",\n  \"components.TvDetails.episodeRuntime\": \"\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"\",\n  \"components.TvDetails.firstAirDate\": \"\",\n  \"components.TvDetails.manageseries\": \"Hallinnoi sarjoja\",\n  \"components.TvDetails.network\": \"\",\n  \"components.TvDetails.nextAirDate\": \"\",\n  \"components.TvDetails.originallanguage\": \"\",\n  \"components.TvDetails.originaltitle\": \"\",\n  \"components.TvDetails.overview\": \"\",\n  \"components.TvDetails.overviewunavailable\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.productioncountries\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.reportissue\": \"\",\n  \"components.TvDetails.rtaudiencescore\": \"\",\n  \"components.TvDetails.rtcriticsscore\": \"\",\n  \"components.TvDetails.seasonnumber\": \"\",\n  \"components.TvDetails.seasons\": \"\",\n  \"components.TvDetails.seasonstitle\": \"\",\n  \"components.TvDetails.showtype\": \"\",\n  \"components.TvDetails.similar\": \"\",\n  \"components.TvDetails.status4k\": \"\",\n  \"components.TvDetails.streamingproviders\": \"\",\n  \"components.TvDetails.tmdbuserscore\": \"\",\n  \"components.TvDetails.viewfullcrew\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.TvDetails.watchtrailer\": \"\",\n  \"components.UserList.accounttype\": \"\",\n  \"components.UserList.admin\": \"\",\n  \"components.UserList.autogeneratepassword\": \"\",\n  \"components.UserList.autogeneratepasswordTip\": \"\",\n  \"components.UserList.bulkedit\": \"\",\n  \"components.UserList.create\": \"\",\n  \"components.UserList.created\": \"\",\n  \"components.UserList.createlocaluser\": \"\",\n  \"components.UserList.creating\": \"\",\n  \"components.UserList.deleteconfirm\": \"\",\n  \"components.UserList.deleteuser\": \"\",\n  \"components.UserList.edituser\": \"\",\n  \"components.UserList.email\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importedfromplex\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.importfromplex\": \"\",\n  \"components.UserList.importfromplexerror\": \"\",\n  \"components.UserList.localLoginDisabled\": \"\",\n  \"components.UserList.localuser\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.newplexsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.nouserstoimport\": \"\",\n  \"components.UserList.owner\": \"\",\n  \"components.UserList.password\": \"\",\n  \"components.UserList.passwordinfodescription\": \"\",\n  \"components.UserList.plexuser\": \"\",\n  \"components.UserList.role\": \"\",\n  \"components.UserList.sortCreated\": \"\",\n  \"components.UserList.sortDisplayName\": \"\",\n  \"components.UserList.sortRequests\": \"\",\n  \"components.UserList.totalrequests\": \"\",\n  \"components.UserList.user\": \"\",\n  \"components.UserList.usercreatedfailed\": \"\",\n  \"components.UserList.usercreatedfailedexisting\": \"\",\n  \"components.UserList.usercreatedsuccess\": \"\",\n  \"components.UserList.userdeleted\": \"\",\n  \"components.UserList.userdeleteerror\": \"\",\n  \"components.UserList.userfail\": \"\",\n  \"components.UserList.userlist\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.users\": \"\",\n  \"components.UserList.userssaved\": \"\",\n  \"components.UserList.validationEmail\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserList.validationpasswordminchars\": \"\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"\",\n  \"components.UserProfile.ProfileHeader.profile\": \"\",\n  \"components.UserProfile.ProfileHeader.settings\": \"\",\n  \"components.UserProfile.ProfileHeader.userid\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Tilin tyyppi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Ylläpitäjä\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Näyttökieli\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord käyttäjä-ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Tutustu-osion alue\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Suodata sisältöä alueellisen saatavuuden perusteella\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Näyttökieli\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"Sähköposti\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Ohita yleinen rajoitus\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Yleiset\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Yleiset asetukset\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Oletus\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Paikallinen käyttäjä\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Käyttäjä\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Elokuvapyyntöjen rajoitus\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Tutustu-osion kieli\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Suodata sisältöä alkuperäisen kielen perusteella\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Omistaja\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex käyttäjä\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Tutustu-osion alue\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Suodata sisältöä alueellisen saatavuuden perusteella\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rooli\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Tallenna muutokset\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Tallennetaan…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Sarjapyyntöjen rajoitus\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Striimauspalveluiden alue\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Näytä striimauspalvelut alueellisen saatavuuden perusteella\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Jotain meni vikaan tallennettaessa asetuksia.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Tämä sähköposti on jo käytetty!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Toinen käyttäjä on jo valinnut tämän käyttäjänimen. Sinun täytyy asettaa sähköpostiosoite\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Asetukset tallennettu!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Käyttäjä\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Anna paikkansapitävä Discord käyttäjä-ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Anna paikkansapitävä sähköpostiosoite\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Sähköposti vaaditaan\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Hallinnoi laitteita\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Yleiset\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"\",\n  \"components.UserProfile.emptywatchlist\": \"\",\n  \"components.UserProfile.limit\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"components.UserProfile.seriesrequest\": \"\",\n  \"components.UserProfile.totalrequests\": \"\",\n  \"components.UserProfile.unlimited\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.delimitedlist\": \"\",\n  \"i18n.noresults\": \"\",\n  \"i18n.notrequested\": \"\",\n  \"i18n.open\": \"\",\n  \"i18n.retrying\": \"\",\n  \"i18n.showingresults\": \"\",\n  \"components.PermissionEdit.createissuesDescription\": \"Anna oikeus raportoida ongelmia mediassa.\",\n  \"components.PermissionEdit.manageissues\": \"Hallinnoi ongelmia\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Anna oikeus hallita median ongelmia.\",\n  \"components.PermissionEdit.managerequests\": \"Hallinnoi pyyntöjä\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Anna oikeus hallinnoida pyyntöjä. Kaikki pyynnöt käyttäjältä jolla on tämä oikeus, hyväksytään automaattisesti.\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"\",\n  \"components.Settings.RadarrModal.ssl\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"\",\n  \"components.Settings.enablessl\": \"\",\n  \"components.QuotaSelector.seasons\": \"\",\n  \"components.QuotaSelector.tvRequests\": \"\",\n  \"components.RequestButton.approverequests\": \"\",\n  \"components.RequestButton.decline4krequests\": \"\",\n  \"components.RequestButton.declinerequests\": \"\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"\",\n  \"components.RequestModal.AdvancedRequester.default\": \"\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Voit pyytää <strong>{limit}</strong> {type} joka<strong>{days}</strong> päivä.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Tämä käyttäjä voi pyytää <strong>{limit}</strong> {type} joka <strong>{days}</strong> päivä.\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"\",\n  \"components.ResetPassword.resetpassword\": \"\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"\",\n  \"components.ResetPassword.validationemailrequired\": \"\",\n  \"components.ResetPassword.validationpasswordmatch\": \"\",\n  \"components.ResetPassword.validationpasswordminchars\": \"\",\n  \"components.ResetPassword.validationpasswordrequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Nykyinen\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"\",\n  \"components.Settings.advancedTooltip\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.cancelscan\": \"\",\n  \"components.Settings.menuUsers\": \"\",\n  \"components.Settings.tautulliSettingsDescription\": \"\",\n  \"components.TitleCard.tmdbid\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"\",\n  \"components.ResetPassword.email\": \"\",\n  \"components.Settings.is4k\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"\",\n  \"components.UserProfile.movierequests\": \"\",\n  \"components.UserProfile.pastdays\": \"\",\n  \"components.RequestModal.requestadmin\": \"Tämä pyyntö hyväksytään automaattisesti.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Pyyntö odottaa hyväksymistä\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Hyväksy automaattisesti ei-4K elokuvien pyynnöt.\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"4K pyynnöt hyväksytään automaattisesti.\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Mediaa yhteensä\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> pyydetty onnistuneesti!\",\n  \"components.Selector.returningSeries\": \"Jatkuu\",\n  \"components.Discover.FilterSlideover.certification\": \"Ikäraja\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Lähetä ilmoitus uusista hyväksymisen vaativista pyynnöistä.\",\n  \"components.Selector.canceled\": \"Peruttu\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Kielet\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Ei ajan tasalla\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Jätä pois avainsanat\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Auto-hyväksy sarjat\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Hyväksy automaattisesti ei-4K sarjojen pyynnöt.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Hyväksy automaattisesti kaikki ei-4K pyynnöt.\",\n  \"components.PermissionEdit.autorequest\": \"Auto-pyydä\",\n  \"components.PermissionEdit.autorequestDescription\": \"Jätä pyyntöjä automaattisesti Plex watchlist:in kautta.\",\n  \"components.RequestModal.requestseriestitle\": \"Pyydä sarjaa\",\n  \"components.RequestModal.seasonnumber\": \"Kausi {number}\",\n  \"components.RequestModal.requestmovietitle\": \"Pyydä elokuvaa\",\n  \"components.ResetPassword.gobacklogin\": \"Palaa kirjautumissivulle\",\n  \"components.RequestModal.selectseason\": \"Valitse kaudet\",\n  \"components.ResetPassword.confirmpassword\": \"Vahvista salasana\",\n  \"components.ResetPassword.password\": \"Salasana\",\n  \"components.ResetPassword.passwordreset\": \"Salasanan resetointi\",\n  \"components.Search.search\": \"Etsi\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Avainsanat\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Ajan tasalla\",\n  \"components.Settings.SettingsAbout.version\": \"Versio\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Median saatavuuden synkronointi\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Välimuisti\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Osumia\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentaatio\",\n  \"components.Settings.SettingsAbout.timezone\": \"Aikavyöhyke\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Ilmoita kun pyyntö on hyväksytty.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Ilmoita kun pyydetty media on katsottavissa.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Ilmoita kun pyyntö on hylätty.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Ilmoita muiden käyttäjien pyynnöistä jotka vaativat hyväksymisen.\",\n  \"components.PermissionEdit.adminDescription\": \"Täydet ylläpitäjän oikeudet. Ohittaa kaikki muut oikeudet.\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Oikeus muokata pyyntöjen lisäasetuksia.\",\n  \"components.PermissionEdit.autoapprove\": \"Auto-hyväksy\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Ilmoita kun median lisäys Radarr:iin tai Sonarr:iin epäonnistuu.\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Valitse metatietojen lähde\",\n  \"components.PermissionEdit.autoapprove4k\": \"Auto-hyväksy 4K\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Auto-hyväksy elokuvat\",\n  \"components.RequestModal.season\": \"Kausi\",\n  \"components.Selector.ended\": \"Päättynyt\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Tyylilajit\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Pyyntöjä yhteensä\",\n  \"components.PermissionEdit.admin\": \"Ylläpitäjä\",\n  \"components.PermissionEdit.advancedrequest\": \"Pyynnön lisäaseetukset\",\n  \"components.PermissionEdit.createissues\": \"Raportoi ongelmista\",\n  \"components.PersonDetails.crewmember\": \"Henkilökunta\",\n  \"components.ManageSlideOver.pastdays\": \"Edelliset {days, number} päivää\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Pyynnön suorittaminen epäonnistui\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Lähetä ilmoitus jos pyynnön lisäys Radarr:iin tai Sonarr:iin epäonnistuu.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Ilmoita uusista ongelmien kommenteista.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Ilmoita uusista ongelmista.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Ilmoita uudelleenavatuista ongelmista.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Ilmoita kun ongelma on selvitetty.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Ilmoita muiden käyttäjien automaattisesti hyväksytyistä pyynnöistä.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Auto-hyväksy 4K elokuvat\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Hyväksy automaattisesti 4K elokuvien pyynnöt.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Auto-hyväksy 4K sarjat\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Hyväksy automaattisesti 4K sarjojen pyynnöt.\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Pyydä käyttäjänä\",\n  \"components.RequestList.sortDirection\": \"Vaihda lajittelun suunta\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Kohdepalvelin\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Tägit\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Kieliprofiili\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Kohdekansio\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Laatuprofiili\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Ei tägejä\",\n  \"components.RequestModal.QuotaDisplay.season\": \"kausi\",\n  \"components.RequestModal.numberofepisodes\": \"Jaksoja\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Tietoa Seerr:istä\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\",\n  \"components.Blocklist.blocklistsettings\": \"Estolistan asetukset\",\n  \"components.Blocklist.showAllBlocklisted\": \"Näytä kaikki estetty media\",\n  \"components.PermissionEdit.blocklistedItems\": \"Estä media.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Anna oikeus estää media.\",\n  \"components.PermissionEdit.manageblocklist\": \"Hallinnoi estolistaa\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Anna oikeus hallinnoida estettyä mediaa.\",\n  \"components.Layout.Sidebar.blocklist\": \"Estolista\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Estetyt tägit\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Hallinnoi estettyä mediaa.\",\n  \"component.BlocklistModal.blocklisting\": \"Estolistaus\",\n  \"component.BlocklistBlock.blocklistedby\": \"Estänyt\",\n  \"component.BlocklistBlock.blocklistdate\": \"Estopäivämäärä\",\n  \"components.Blocklist.mediaType\": \"Tyyppi\",\n  \"components.Blocklist.mediaName\": \"Nimi\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Näytä estetty media.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Anna oikeus tarkastella estettyä mediaa.\",\n  \"components.Blocklist.blocklistdate\": \"päivämäärä\",\n  \"components.Blocklist.blocklistedby\": \"{date} käyttäjän {user} toimesta\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> ei ole estolistalla.\",\n  \"components.Blocklist.filterManual\": \"Manuaalinen\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Piilota estolistatut kohteet Tutustu-osiosta kaikilta käyttäjiltä ilman \\\"Hallinnoi estolistaa\\\" oikeutta\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb id\"\n}\n"
  },
  {
    "path": "src/i18n/locale/fr.json",
    "content": "{\n  \"components.AirDateBadge.airedrelative\": \"Diffusé {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Diffusion {relativeTime}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Le montage du volume <code>{appDataPath}</code> n'a pas été configuré correctement. Toutes les données seront effacées lorsque le conteneur sera arrêté ou redémarré.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Films\",\n  \"components.CollectionDetails.overview\": \"Résumé\",\n  \"components.CollectionDetails.requestcollection\": \"Demander la collection\",\n  \"components.CollectionDetails.requestcollection4k\": \"Demander la collection en 4K\",\n  \"components.Discover.CreateSlider.addSlider\": \"Ajouter une rangée\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Créer une rangée personnalisée\",\n  \"components.Discover.CreateSlider.addfail\": \"Échec de la création de la nouvelle rangée.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Nouvelle rangée créée et paramètres de la page Découvrir enregistrés.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Modifier la rangée\",\n  \"components.Discover.CreateSlider.editfail\": \"Échec de la modification de la rangée.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Rangée modifiée et paramètres de la page Découvrir enregistrés.\",\n  \"components.Discover.CreateSlider.needresults\": \"Vous devez avoir au moins 1 résultat.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Aucun résultat.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Fournissez un ID de genre TMBD\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Fournissez un ID de mot-clé TMBD\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Fournissez un ID de diffuseur TMDB\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Fournissez une requête de recherche\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Fournissez un ID de studio TMDB\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Recherche par genres…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Recherche par mots-clés…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Recherche par studios…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Nom de la rangée\",\n  \"components.Discover.CreateSlider.starttyping\": \"Commencez à taper pour rechercher.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Vous devez fournir une valeur de données.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Vous devez fournir un titre.\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} Films\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Films\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Films en {language}\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# filtre actif} other {# filtres actifs}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Films\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularité croissante\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularité décroissante\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Date de sortie croissante\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Date de sortie décroissante\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Titre (A-Z) croissant\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Titre (Z-A) décroissant\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Note TMDB croissante\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Note TMDB décroissante\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Séries {network}\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Échec de la suppression de la rangée.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Rangée supprimé avec succès.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Basculer la visibilité\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Retirer\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Films {studio}\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# filtre actif} other {# filtres actifs}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Séries\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Première diffusion croissante\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Première diffusion décroissante\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularité croissante\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularité décroissante\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Titre (A-Z) croissant\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Titre (Z-A) décroissant\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Note TMDB croissante\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Note TMDB décroissante\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Séries {genre}\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Séries\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Séries en {language}\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Votre liste de suivi\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Liste de suivi Plex\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# filtre actif} other {# filtres actifs}}\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Effacer les filtres actifs\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtres\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Première diffusion\",\n  \"components.Discover.FilterSlideover.from\": \"De\",\n  \"components.Discover.FilterSlideover.genres\": \"Genre\",\n  \"components.Discover.FilterSlideover.keywords\": \"Mots-clés\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Langue originale\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Notes entre {minValue} et {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Date de sortie\",\n  \"components.Discover.FilterSlideover.runtime\": \"Durée\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"Durée : {minValue} à {maxValue} minutes\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Plateformes de streaming\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Note des utilisateurs TMDB\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Nombre de votes utilisateur TMDB\",\n  \"components.Discover.FilterSlideover.to\": \"À\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Nombre de votes entre {minValue} et {maxValue}\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Films par genres\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Films par genres\",\n  \"components.Discover.NetworkSlider.networks\": \"Diffuseurs\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Les médias ajoutés à votre <PlexWatchlistSupportLink>liste de suivi Plex</PlexWatchlistSupportLink> apparaîtront ici.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Votre liste de suivi\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Récemment ajoutés\",\n  \"components.Discover.StudioSlider.studios\": \"Studios\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Séries par genres\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Séries par genres\",\n  \"components.Discover.createnewslider\": \"Créer une nouvelle rangée\",\n  \"components.Discover.customizediscover\": \"Personnaliser Découvrir\",\n  \"components.Discover.discover\": \"Découvrir\",\n  \"components.Discover.emptywatchlist\": \"Les médias ajoutés à votre <PlexWatchlistSupportLink>liste de suivi Plex</PlexWatchlistSupportLink> apparaîtront ici.\",\n  \"components.Discover.moviegenres\": \"Films par genres\",\n  \"components.Discover.networks\": \"Diffuseurs\",\n  \"components.Discover.plexwatchlist\": \"Votre liste de suivi\",\n  \"components.Discover.popularmovies\": \"Films populaires\",\n  \"components.Discover.populartv\": \"Séries populaires\",\n  \"components.Discover.recentlyAdded\": \"Ajouts récents\",\n  \"components.Discover.recentrequests\": \"Demandes récentes\",\n  \"components.Discover.resetfailed\": \"Une erreur s'est produite lors de la réinitialisation des paramètres de Découvrir.\",\n  \"components.Discover.resetsuccess\": \"Réinitialisation réussie des paramètres de Découvrir.\",\n  \"components.Discover.resettodefault\": \"Réinitialiser par défaut\",\n  \"components.Discover.resetwarning\": \"Réinitialiser toutes les rangées par défaut. Cela supprimera également toutes les rangées personnalisées !\",\n  \"components.Discover.stopediting\": \"Arrêter l'édition\",\n  \"components.Discover.studios\": \"Studios\",\n  \"components.Discover.tmdbmoviegenre\": \"Genre de film TMDB\",\n  \"components.Discover.tmdbmoviekeyword\": \"Mot-clé de film TMDB\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Services de streaming de films TMDB\",\n  \"components.Discover.tmdbnetwork\": \"Diffuseur TMDB\",\n  \"components.Discover.tmdbsearch\": \"Recherche TMDB\",\n  \"components.Discover.tmdbstudio\": \"Studio TMDB\",\n  \"components.Discover.tmdbtvgenre\": \"Genre de la série TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Mot-clé de la série TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Services de streaming TMDB TV\",\n  \"components.Discover.trending\": \"Tendances\",\n  \"components.Discover.tvgenres\": \"Séries par genres\",\n  \"components.Discover.upcoming\": \"Films à venir\",\n  \"components.Discover.upcomingmovies\": \"Films à venir\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Rechercher un film ou une série\",\n  \"components.Layout.Sidebar.dashboard\": \"Découvrir\",\n  \"components.Layout.Sidebar.requests\": \"Demandes\",\n  \"components.Layout.Sidebar.settings\": \"Paramètres\",\n  \"components.Layout.Sidebar.users\": \"Utilisateurs\",\n  \"components.Layout.UserDropdown.signout\": \"Se déconnecter\",\n  \"components.MovieDetails.budget\": \"Budget\",\n  \"components.MovieDetails.cast\": \"Casting\",\n  \"components.MovieDetails.originallanguage\": \"Langue originale\",\n  \"components.MovieDetails.overview\": \"Résumé\",\n  \"components.MovieDetails.overviewunavailable\": \"Résumé indisponible.\",\n  \"components.MovieDetails.recommendations\": \"Recommandations\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Date de sortie} other {Date de sorties}}\",\n  \"components.MovieDetails.revenue\": \"Revenu\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutes\",\n  \"components.MovieDetails.similar\": \"Titres similaires\",\n  \"components.PersonDetails.appearsin\": \"Apparitions\",\n  \"components.PersonDetails.ascharacter\": \"Rôle : {character}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Saison} other {Saisons}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Saison} other {Saisons}}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Saison} other {Saisons}}\",\n  \"components.RequestList.requests\": \"Demandes\",\n  \"components.RequestModal.cancel\": \"Annuler la demande\",\n  \"components.RequestModal.numberofepisodes\": \"Nombre d'épisodes\",\n  \"components.RequestModal.pendingrequest\": \"Demande en attente\",\n  \"components.RequestModal.requestCancel\": \"Demande pour <strong>{title}</strong> refusée.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> demandé avec succès !\",\n  \"components.RequestModal.requestadmin\": \"Cette demande sera validée automatiquement.\",\n  \"components.RequestModal.requestfrom\": \"La demande de {username} est en attente de validation.\",\n  \"components.RequestModal.requestseasons\": \"Demander {seasonCount} {seasonCount, plural, one {saison} other {saisons}}\",\n  \"components.RequestModal.season\": \"Saison\",\n  \"components.RequestModal.seasonnumber\": \"Saison {number}\",\n  \"components.RequestModal.selectseason\": \"Sélectionner la/les saison(s)\",\n  \"components.Search.searchresults\": \"Résultats de la recherche\",\n  \"components.Settings.Notifications.agentenabled\": \"Activer l'agent\",\n  \"components.Settings.Notifications.authPass\": \"Mot de passe SMTP\",\n  \"components.Settings.Notifications.authUser\": \"Nom d'utilisateur SMTP\",\n  \"components.Settings.Notifications.emailsender\": \"Adresse de l'expéditeur\",\n  \"components.Settings.Notifications.smtpHost\": \"Hôte SMTP\",\n  \"components.Settings.Notifications.smtpPort\": \"Port SMTP\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Vous devez fournir un nom d'hôte ou une adresse IP valide\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Vous devez fournir un numéro de port valide\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL du webhook\",\n  \"components.Settings.RadarrModal.add\": \"Ajouter un serveur\",\n  \"components.Settings.RadarrModal.apiKey\": \"Clé d'API\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL de base\",\n  \"components.Settings.RadarrModal.createradarr\": \"Ajouter un nouveau serveur Radarr\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Serveur par défaut\",\n  \"components.Settings.RadarrModal.editradarr\": \"Modifier le serveur Radarr\",\n  \"components.Settings.RadarrModal.hostname\": \"Nom d'hôte ou adresse IP\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Disponibilité minimale\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Profil de qualité\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Dossier racine\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Sélectionner une disponibilté minimale\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Sélectionner un profil de qualité\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Sélectionner un dossier racine\",\n  \"components.Settings.RadarrModal.server4k\": \"Serveur 4K\",\n  \"components.Settings.RadarrModal.servername\": \"Nom du serveur\",\n  \"components.Settings.RadarrModal.ssl\": \"Utiliser SSL\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Échec de la connexion à Radarr.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Connexion avec le Serveur Radarr établie avec succès !\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Vous devez fournir une clé d'API\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Vous devez fournir un nom d'hôte ou une adresse IP valide\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Vous devez fournir un numéro de port valide\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Vous devez sélectionner un profil de qualité\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Vous devez sélectionner un dossier racine\",\n  \"components.Settings.SonarrModal.add\": \"Ajouter un serveur\",\n  \"components.Settings.SonarrModal.apiKey\": \"Clé API\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL de base\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Ajouter un nouveau serveur Sonarr\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Serveur par défaut\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Modifier le serveur Sonarr\",\n  \"components.Settings.SonarrModal.hostname\": \"Nom d'hôte ou adresse IP\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Profil de qualité\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Dossier racine\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Dossiers de saison\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Sélectionner un profil de qualité\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Sélectionner un dossier racine\",\n  \"components.Settings.SonarrModal.server4k\": \"Serveur 4K\",\n  \"components.Settings.SonarrModal.servername\": \"Nom du serveur\",\n  \"components.Settings.SonarrModal.ssl\": \"Utiliser SSL\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Vous devez fournir une clé d'API\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Vous devez fournir un nom d'hôte ou une adresse IP valide\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Vous devez fournir un numéro de port valide\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Vous devez sélectionner un profil de qualité\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Vous devez sélectionner un dossier racine\",\n  \"components.Settings.activeProfile\": \"Profil actif\",\n  \"components.Settings.addradarr\": \"Ajouter un serveur Radarr\",\n  \"components.Settings.address\": \"Adresse\",\n  \"components.Settings.addsonarr\": \"Ajouter un serveur Sonarr\",\n  \"components.Settings.cancelscan\": \"Annuler le scan\",\n  \"components.Settings.currentlibrary\": \"Bibliothèque actuelle : {name}\",\n  \"components.Settings.default\": \"Par défaut\",\n  \"components.Settings.default4k\": \"4K par défaut\",\n  \"components.Settings.deleteserverconfirm\": \"Êtes-vous sûr(e) de vouloir supprimer ce serveur ?\",\n  \"components.Settings.hostname\": \"Nom d'hôte ou adresse IP\",\n  \"components.Settings.librariesRemaining\": \"Bibliothèques restantes : {count}\",\n  \"components.Settings.manualscan\": \"Scan manuel des bibliothèques\",\n  \"components.Settings.manualscanDescription\": \"Normalement, le scan sera effectué une fois toutes les 24 heures seulement. Seerr vérifiera les ajouts récents de votre serveur Plex de façon proactive. Si c'est la première fois que vous configurez Plex, un scan complet de la bibliothèque est recommandé !\",\n  \"components.Settings.menuAbout\": \"À propos\",\n  \"components.Settings.menuGeneralSettings\": \"Général\",\n  \"components.Settings.menuJobs\": \"Tâches et cache\",\n  \"components.Settings.menuLogs\": \"Journaux\",\n  \"components.Settings.menuNotifications\": \"Notifications\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Services\",\n  \"components.Settings.notificationsettings\": \"Paramètres de notification\",\n  \"components.Settings.notrunning\": \"Pas en exécution\",\n  \"components.Settings.plexlibraries\": \"Bibliothèques Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"Les bibliothèques que Seerr analyse pour trouver des titres. Configurez et enregistrez vos paramètres de connexion Plex, puis cliquez sur le bouton ci-dessous si aucune bibliothèque n'est affichée.\",\n  \"components.Settings.plexsettings\": \"Paramètres Plex\",\n  \"components.Settings.plexsettingsDescription\": \"Configurez les paramètres de votre serveur Plex. Seerr analyse vos bibliothèques Plex pour déterminer la disponibilité des contenus.\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.radarrsettings\": \"Paramètres Radarr\",\n  \"components.Settings.sonarrsettings\": \"Paramètres Sonarr\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Commencer le scan\",\n  \"components.Setup.configureservices\": \"Configurer les services\",\n  \"components.Setup.continue\": \"Continuer\",\n  \"components.Setup.finish\": \"Finir la configuration\",\n  \"components.Setup.finishing\": \"Finalisation…\",\n  \"components.Setup.signinMessage\": \"Commencez en vous connectant avec votre compte Plex\",\n  \"components.Setup.welcome\": \"Bienvenue sur Seerr\",\n  \"components.TvDetails.cast\": \"Casting\",\n  \"components.TvDetails.originallanguage\": \"Langue d'origine\",\n  \"components.TvDetails.overview\": \"Résumé\",\n  \"components.TvDetails.overviewunavailable\": \"Résumé indisponible.\",\n  \"components.TvDetails.recommendations\": \"Recommandations\",\n  \"components.TvDetails.similar\": \"Séries similaires\",\n  \"components.UserList.admin\": \"Admin\",\n  \"components.UserList.created\": \"A rejoint\",\n  \"components.UserList.plexuser\": \"Utilisateur Plex\",\n  \"components.UserList.role\": \"Rôle\",\n  \"components.UserList.totalrequests\": \"Demandes\",\n  \"components.UserList.user\": \"Utilisateur\",\n  \"components.UserList.userlist\": \"Utilisateurs\",\n  \"i18n.approve\": \"Valider\",\n  \"i18n.approved\": \"Validé\",\n  \"i18n.available\": \"Disponible\",\n  \"i18n.cancel\": \"Annuler\",\n  \"i18n.decline\": \"Refuser\",\n  \"i18n.declined\": \"Refusé\",\n  \"i18n.delete\": \"Supprimer\",\n  \"i18n.movies\": \"Films\",\n  \"i18n.partiallyavailable\": \"Partiellement disponible\",\n  \"i18n.pending\": \"En attente\",\n  \"i18n.processing\": \"En cours de traitement\",\n  \"i18n.tvshows\": \"Séries\",\n  \"i18n.unavailable\": \"Indisponible\",\n  \"pages.oops\": \"Oups\",\n  \"pages.returnHome\": \"Retourner à l'accueil\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Casting complet de la série\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Casting complet\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Paramètres de notification par E-mail enregistrés avec succès !\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Les paramètres de notification par e-mail n'ont pas pu être enregistrés.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Paramètres de notification Discord enregistrés avec succès !\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Les paramètres de notification Discord n'ont pas pu être enregistrés.\",\n  \"components.Settings.validationPortRequired\": \"Vous devez fournir un numéro de port valide\",\n  \"components.Settings.validationHostnameRequired\": \"Vous devez fournir un nom d'hôte valide ou une adresse IP\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Vous devez fournir un nom de serveur\",\n  \"components.Settings.SettingsAbout.version\": \"Version\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Total des demandes\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Total des médias\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Discussions GitHub\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Obtenir de l'aide\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Vous devez fournir un nom de serveur\",\n  \"i18n.deleting\": \"Suppression…\",\n  \"components.UserList.userdeleteerror\": \"Une erreur s'est produite lors de la suppression de l'utilisateur.\",\n  \"components.UserList.userdeleted\": \"Utilisateur supprimé avec succès !\",\n  \"components.UserList.deleteuser\": \"Supprimer l'utilisateur\",\n  \"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.\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Tester la connexion pour charger les dossiers racine\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Tester la connexion pour charger les profils de qualité\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Chargement des dossiers racine…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Chargement des profils de qualité…\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Vous devez sélectionner une disponibilité minimale\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Tester la connexion pour charger les dossiers racine\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Tester la connexion pour charger les profils de qualité\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Chargement des dossiers racine…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Chargement des profils de qualité…\",\n  \"components.TvDetails.showtype\": \"Type de séries\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Diffuseur} other {Diffuseurs}}\",\n  \"components.TvDetails.anime\": \"Animé\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Dossier racine pour les animés\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Profil de qualité pour les animés\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studios}}\",\n  \"i18n.close\": \"Fermer\",\n  \"components.Settings.SettingsAbout.timezone\": \"Fuseau horaire\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Voir sur GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Voir le journal des modifications\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Journal des modifications de la version {version}\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Versions\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Les données de version sont actuellement indisponibles.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Dernière version\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Actuelle\",\n  \"components.UserList.importfromplexerror\": \"Une erreur s'est produite durant l'importation des utilisateurs de Plex.\",\n  \"components.UserList.importfromplex\": \"Importer les utilisateurs Plex\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> {userCount, plural, one {utilisateur importé} other {utilisateurs importés}} depuis Plex avec succès !\",\n  \"components.TvDetails.viewfullcrew\": \"Voir l'équipe complète\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Équipe complète de la série\",\n  \"components.PersonDetails.crewmember\": \"Équipe\",\n  \"components.MovieDetails.viewfullcrew\": \"Voir l'équipe complète\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Équipe complète\",\n  \"components.TvDetails.firstAirDate\": \"Date de première diffusion\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Autoriser les certificats autosignés\",\n  \"components.TvDetails.watchtrailer\": \"Regarder la bande-annonce\",\n  \"components.MovieDetails.watchtrailer\": \"Regarder la bande-annonce\",\n  \"i18n.requested\": \"Demandé\",\n  \"i18n.retry\": \"Réessayer\",\n  \"i18n.failed\": \"Échec\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL de webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Paramètres de notification de Slack sauvegardés avec succès !\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Les paramètres de notification Slack n'ont pas pu être enregistrés.\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Activer l'agent\",\n  \"components.RequestList.RequestItem.failedretry\": \"Une erreur s'est produite lors du renvoi de la demande.\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Vous devez fournir un identifiant de discussion valide\",\n  \"components.Settings.Notifications.botAPI\": \"Jeton d'autorisation du bot\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Vous devez fournir le token d'autorisation du bot\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Paramètres de notification Telegram enregistrés avec succès !\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Les paramètres de notification Telegram n'ont pas pu être enregistrés.\",\n  \"components.Settings.Notifications.senderName\": \"Nom de l'expéditeur\",\n  \"components.Settings.Notifications.chatId\": \"ID discussion\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentation\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Envoyer des notifications lorsque des utilisateurs soumettent une demande de média qui nécessite une validation.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Demande en attente de validation\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Envoyer des notifications lorsqu'une demande de média n'a pas pu être ajoutée à Radarr ou Sonarr.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Échec d’ajout de la demande\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Envoyer des notifications lorsque le média demandé devient disponible.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Demande disponible\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Envoyer des notifications lorsqu'une demande de média est validée manuellement.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Demande validée\",\n  \"i18n.request\": \"Demander\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Vous devez fournir une clé d'utilisateur ou de groupe valide\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Vous devez fournir un jeton d'application valide\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Clé d'utilisateur ou de groupe\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Paramètres de notification Pushover enregistrés avec succès !\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Les paramètres de notification Pushover n'ont pas pu être enregistrés.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Activer l'agent\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Jeton API d'application\",\n  \"components.RequestList.sortModified\": \"Dernière modification\",\n  \"components.RequestList.sortAdded\": \"Plus récentes\",\n  \"components.RequestList.showallrequests\": \"Afficher toutes les demandes\",\n  \"components.StatusBadge.status4k\": \"{status} en 4K\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Paramètres de notification Webhook enregistrés avec succès !\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Échec de l'enregistrement des paramètres de notification du webhook.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL de webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Aide sur les variables de modèle\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"En-tête d'autorisation\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Activer l'agent\",\n  \"components.RequestModal.pending4krequest\": \"Demande 4K en attente\",\n  \"components.RequestButton.viewrequest4k\": \"Voir la demande 4K\",\n  \"components.RequestButton.viewrequest\": \"Voir la demande\",\n  \"components.RequestButton.requestmore4k\": \"Demander d'autres ajouts en 4K\",\n  \"components.RequestButton.requestmore\": \"Demander d'autres ajouts\",\n  \"components.RequestButton.declinerequests\": \"Refuser {requestCount, plural, one {la demande} other {{requestCount} demandes}}\",\n  \"components.RequestButton.declinerequest4k\": \"Refuser la demande 4K\",\n  \"components.RequestButton.declinerequest\": \"Refuser la demande\",\n  \"components.RequestButton.decline4krequests\": \"Refuser {requestCount, plural, one {la demande en 4K} other {{requestCount} demandes en 4K}}\",\n  \"components.RequestButton.approverequests\": \"Valider {requestCount, plural, one {la demande} other {{requestCount} demandes}}\",\n  \"components.RequestButton.approverequest4k\": \"Valider la demande 4K\",\n  \"components.RequestButton.approverequest\": \"Valider la demande\",\n  \"components.RequestButton.approve4krequests\": \"{requestCount, plural, one {Valider la demande en 4k} other {Valider {requestCount} demandes en 4K}}\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Données utiles JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"Les données utiles JSON par défaut ont été réinitialisées avec succès !\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Réinitialiser les données par défaut\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Vous devez fournir un JSON payload valide\",\n  \"components.UserList.validationpasswordminchars\": \"Le mot de passe est trop court ; il doit contenir au moins 8 caractères\",\n  \"components.UserList.usercreatedsuccess\": \"L'utilisateur a bien été créé !\",\n  \"components.UserList.usercreatedfailed\": \"Une erreur s'est produite lors de la création de l'utilisateur.\",\n  \"components.UserList.password\": \"Mot de passe\",\n  \"components.UserList.localuser\": \"Utilisateur local\",\n  \"components.UserList.creating\": \"Création…\",\n  \"components.UserList.createlocaluser\": \"Créer un utilisateur local\",\n  \"components.UserList.create\": \"Créer\",\n  \"components.UserList.autogeneratepassword\": \"Générer automatiquement le mot de passe\",\n  \"components.UserList.passwordinfodescription\": \"Configurez l'URL de l'application ainsi que les notifications par e-mail pour permettre la génération automatique de mots de passe.\",\n  \"components.UserList.email\": \"Adresse e-mail\",\n  \"components.Login.validationpasswordrequired\": \"Vous devez renseigner un mot de passe\",\n  \"components.Login.validationemailrequired\": \"Vous devez fournir un e-mail valide\",\n  \"components.Login.signinwithoverseerr\": \"Utilisez votre compte {applicationTitle}\",\n  \"components.Login.password\": \"Mot de passe\",\n  \"components.Login.loginerror\": \"Une erreur s'est produite lors de la tentative de connexion.\",\n  \"components.Login.email\": \"Adresse e-mail\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Voir plus\",\n  \"i18n.edit\": \"Modifier\",\n  \"components.RequestModal.requestedited\": \"Demande pour <strong>{title}</strong> modifiée avec succès !\",\n  \"components.RequestModal.requestcancelled\": \"Demande pour <strong>{title}</strong> refusée.\",\n  \"components.RequestModal.errorediting\": \"Une erreur s'est produite lors de la modification de la demande.\",\n  \"components.RequestModal.autoapproval\": \"Validation automatique\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Dossier racine\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Profil de qualité\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Serveur de destination\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Défaut)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Cette série est un animé.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Options Avancées\",\n  \"components.RequestBlock.requestoverrides\": \"Modifications de la demande\",\n  \"components.RequestBlock.server\": \"Serveur de destination\",\n  \"components.RequestBlock.rootfolder\": \"Dossier racine\",\n  \"components.RequestBlock.profilechanged\": \"Profil de qualité\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Demande refusée\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Envoyer des notifications lorsqu'une demande de média est refusée.\",\n  \"i18n.experimental\": \"Expérimental\",\n  \"components.RequestModal.requesterror\": \"Une erreur s'est produite lors de la demande.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Nous n'avons pas pu associer cette série automatiquement. Veuillez sélectionner l'association correcte dans la liste ci-dessous.\",\n  \"components.Login.signinwithplex\": \"Utilisez votre compte Plex\",\n  \"components.Login.signin\": \"Connexion\",\n  \"components.Login.signinheader\": \"Connectez-vous pour continuer\",\n  \"components.Login.signingin\": \"Connexion en cours…\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Configurer et activer les agents de notification.\",\n  \"components.UserList.userssaved\": \"Les permissions d'utilisateur ont été enregistrées avec succès !\",\n  \"components.UserList.bulkedit\": \"Modification en masse\",\n  \"components.PermissionEdit.usersDescription\": \"Autorise à gérer les utilisateurs. Les utilisateurs avec cette autorisation ne peuvent pas modifier les utilisateurs dotés de privilèges d'administrateur ni les accorder.\",\n  \"components.PermissionEdit.users\": \"Gérer les utilisateurs\",\n  \"components.PermissionEdit.requestDescription\": \"Autorise à demander des médias non-4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Autorise à demander des séries en 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"Demander des séries en 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Autorise à demander des films en 4K.\",\n  \"components.PermissionEdit.request4kMovies\": \"Demander des films en 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Autorise à demander des médias en 4K.\",\n  \"components.PermissionEdit.request4k\": \"Demander en 4K\",\n  \"components.PermissionEdit.request\": \"Demander\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Autorise à gérer les demandes de média. Toutes les demandes faites par un utilisateur avec cette autorisation seront validées automatiquement.\",\n  \"components.PermissionEdit.managerequests\": \"Gérer les demandes\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Valider automatiquement les demandes de séries non-4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Valider automatiquement les séries\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Valide automatiquement les demandes de films non-4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Valider automatiquement les films\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Valide automatiquement toutes les demandes de média non-4K.\",\n  \"components.PermissionEdit.autoapprove\": \"Valider automatiquement\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Permet de modifier les options de demande de média avancées.\",\n  \"components.PermissionEdit.advancedrequest\": \"Demandes avancées\",\n  \"components.PermissionEdit.adminDescription\": \"Accès administrateur complet. Contourne toutes les autres permissions (sélectionnées ou non).\",\n  \"components.PermissionEdit.admin\": \"Administateur\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Liste des serveurs Plex récupérée avec succès !\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Échec de la récupération de la liste des serveurs Plex.\",\n  \"components.Settings.toastPlexRefresh\": \"Récupération de la liste des serveurs depuis Plex…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Connexion Plex établie avec succès !\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Échec de connexion à Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"Tentative de connexion à Plex…\",\n  \"components.Settings.settingUpPlexDescription\": \"Pour configurer Plex, vous pouvez soit entrer les paramètres manuellement, soit choisir parmi l’un des serveurs récupérés sur <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Appuyez sur le bouton à droite de la liste déroulante pour actualiser la liste des serveurs disponibles.\",\n  \"components.Settings.serverpresetRefreshing\": \"Récupération des serveurs…\",\n  \"components.Settings.serverpresetManualMessage\": \"Configuration manuelle\",\n  \"components.Settings.serverpresetLoad\": \"Appuyez sur le bouton pour charger les serveurs disponibles\",\n  \"components.Settings.serverpreset\": \"Serveur\",\n  \"components.Settings.serverRemote\": \"distant\",\n  \"components.Settings.serverLocal\": \"local\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Connexion à Sonarr établie avec succès !\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Échec de la connexion à Sonarr.\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Activer les scans\",\n  \"components.Settings.SonarrModal.externalUrl\": \"URL externe\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Activer les scans\",\n  \"components.Settings.RadarrModal.externalUrl\": \"URL externe\",\n  \"components.MovieDetails.markavailable\": \"Marquer comme disponible\",\n  \"components.MovieDetails.mark4kavailable\": \"Marquer comme disponible en 4K\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr effectue régulièrement certaines des tâches de maintenance de manière planifiée, mais elles peuvent également être déclenchées manuellement ci-dessous. L'exécution manuelle d'une tâche ne modifiera pas sa planification.\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Manquées\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Exécuter\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Prochaine exécution\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Type\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} a commencé.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Tâches\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Nom de la tâche\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} annulé.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Vider le cache\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Annuler la tâche\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Taille de la valeur\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Nom du cache\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Taille de la clé\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Total des clés\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Abouties\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Cache de {cachename} vidé.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr met en cache les requêtes vers les API externes pour optimiser les performances et éviter de faire des appels API inutiles.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"i18n.advanced\": \"Avancé\",\n  \"components.UserList.users\": \"Utilisateurs\",\n  \"components.Setup.setup\": \"Configuration\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"L'URL ne doit pas se terminer par un slash (/)\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Vous devez fournir une URL valide\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"L'URL ne doit pas se terminer par un slash (/)\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Vous devez fournir une URL valide\",\n  \"components.Search.search\": \"Rechercher\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Demander en tant que\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Autorise à afficher les demandes des autres utilisateurs.\",\n  \"components.PermissionEdit.viewrequests\": \"Voir les demandes\",\n  \"components.UserList.validationEmail\": \"Email requis\",\n  \"components.TvDetails.nextAirDate\": \"Prochaine diffusion\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"L'URL de base ne doit pas se terminer par un slash (/)\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"L'URL de base doit commencer par un slash (/)\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"L'URL de base ne doit pas se terminer par un slash (/)\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"L'URL de base doit commencer par un slash (/)\",\n  \"components.Settings.Notifications.validationEmail\": \"Vous devez fournir un e-mail valide\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Vous devez fournir une URL valide\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Vous devez fournir une URL valide\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Vous devez renseigner un mot de passe\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Le mot de passe est trop court ; il doit comporter au moins 8 caractères\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Les mots de passe doivent être les mêmes\",\n  \"components.ResetPassword.validationemailrequired\": \"Vous devez fournir un e-mail valide\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Le mot de passe a été réinitialisé avec succès !\",\n  \"components.ResetPassword.resetpassword\": \"Réinitialiser votre mot de passe\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Un lien de réinitialisation du mot de passe sera envoyé à l'e-mail fourni si il est associé à un utilisateur valide.\",\n  \"components.ResetPassword.password\": \"Mot de passe\",\n  \"components.ResetPassword.gobacklogin\": \"Retourner à la page de connexion\",\n  \"components.ResetPassword.emailresetlink\": \"Envoyer un lien de récupération par e-mail\",\n  \"components.ResetPassword.email\": \"Adresse e-mail\",\n  \"components.ResetPassword.confirmpassword\": \"Confirmation du mot de passe\",\n  \"components.Login.forgotpassword\": \"Mot de passe oublié ?\",\n  \"components.Settings.SettingsJobsCache.process\": \"Processus\",\n  \"components.Settings.SettingsJobsCache.command\": \"Commande\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Vous devez sélectionner un profil de langue\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Tester la connexion pour charger les profils de langue\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Sélectionnez le profil de langue\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Chargement des profils de langue…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Profil de langue\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Profil de langue pour les animés\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Profil de langue\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Envoyer des notifications sans son\",\n  \"components.Settings.Notifications.sendSilently\": \"Envoyer silencieusement\",\n  \"components.UserList.sortRequests\": \"Nombre de demandes\",\n  \"components.UserList.sortDisplayName\": \"Nom d'utilisateur affiché\",\n  \"components.UserList.sortCreated\": \"Date d'inscription\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Valide automatiquement les demandes de séries en 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Validation automatique des séries 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Valide automatiquement les demandes de films en 4K.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Validation automatique des films 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Valide automatiquement toutes les demandes de média en 4K.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Validation automatique 4K\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Identifiant\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Paramètres de notification\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nouveau mot de passe\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Mot de passe actuel\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Mot de passe\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Paramètres enregistrés avec succès !\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Une erreur s'est produite lors de l'enregistrement des paramètres.\",\n  \"components.UserProfile.recentrequests\": \"Demandes récentes\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Permissions\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notifications\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Général\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Mot de passe\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Vous devez fournir un jeton d'accès\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Les paramètres de notification Pushbullet n'ont pas pu être enregistrés.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Activer l'agent\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Jeton d'accès\",\n  \"components.Layout.UserDropdown.settings\": \"Paramètres\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Permissions\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Le mot de passe est trop court, il doit contenir un minimum de 8 caractères\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Vous devez fournir un nouveau mot de passe\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Vous devez fournir votre mot de passe actuel\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Les mots de passe doivent correspondre\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Vous devez confirmer le nouveau mot de passe\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Mot de passe enregistré avec succès !\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Un problème est survenu lors de l'enregistrement du mot de passe.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Vous devez fournir un identifiant valide\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"L' <FindDiscordIdLink>ID</FindDiscordIdLink>associé à votre compte utilisateur\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Les paramètres ont été enregistrés avec succès !\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Un problème est survenu pendant l'enregistrement des paramètres.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Utilisateur Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Utilisateur local\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Paramètres généraux\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Nom affiché\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Modifier les paramètres\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Afficher le profil\",\n  \"components.UserList.userfail\": \"Un problème est survenu lors de l'enregistrement des permissions de l'utilisateur.\",\n  \"components.UserList.edituser\": \"Modifier les permissions de l'utilisateur\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Paramètres de notification Pushbullet enregistrés avec succès !\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Confirmez le mot de passe\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtrer le contenu selon la disponibilité par pays\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Pays dans Découvrir\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtrer le contenu par langue d’origine\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Langue dans Découvrir\",\n  \"components.Discover.upcomingtv\": \"Séries à venir\",\n  \"components.RegionSelector.regionDefault\": \"Tous les pays\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.email\": \"E-mail\",\n  \"components.RegionSelector.regionServerDefault\": \"Par défaut ({region})\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Vous n'avez l'autorisation de modifier le mot de passe de cet utilisateur.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Utilisateur\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rôle\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Administrateur\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Admin\",\n  \"components.UserList.owner\": \"Administrateur\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Type de compte\",\n  \"components.UserList.accounttype\": \"Type\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Tâche inconnue\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Synchronisation des téléchargements\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Reset de la synchronisation des téléchargements\",\n  \"i18n.loading\": \"Chargement…\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Saison} other {# Saisons}}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Envoyer des notifications sans son\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Démarre une discussion</TelegramBotLink>, ajoute <GetIdBotLink>@get_id_bot</GetIdBotLink>, et utilise la commande <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID de discussion\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Envoie les messages silencieusement\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Vous devez fournir un identifiant de chat valide\",\n  \"components.Settings.Notifications.botUsername\": \"Pseudonyme du Bot\",\n  \"components.RequestList.RequestItem.modified\": \"Modifiée\",\n  \"components.RequestList.RequestItem.requested\": \"Demandé\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} par {user}\",\n  \"components.Settings.scanning\": \"Synchronisation en cours…\",\n  \"components.Settings.scan\": \"Synchroniser les bibliothèques\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Scan de Sonarr\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Scan de Radarr\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Scan des ajouts récents Plex\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Scan complet des bibliothèques Plex\",\n  \"components.Settings.Notifications.validationUrl\": \"Vous devez fournir une URL valide\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"L'URL de l'avatar de votre Bot\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Configurer les paramètres généraux et par défaut de l'utilisateur.\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Un problème est survenu lors de l'enregistrement des paramètres.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Activer la connexion locale\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Permissions par défaut\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID utilisateur : {userid}\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Membre depuis le {joindate}\",\n  \"components.Settings.menuUsers\": \"Utilisateurs\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Paramètres utilisateur\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Les paramètres utilisateur ont été enregistrés avec succès !\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Demande validée automatiquement\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Envoyer des notifications lorsque des utilisateurs soumettent une demande pour un nouveau média qui est validée automatiquement.\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Vous n'avez pas l'autorisation de modifier les paramètres de cet utilisateur.\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Vous ne pouvez pas modifier vos propres permissions.\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Signer des emails chiffrés en utilisant <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Signer des emails chiffrés en utilisant <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Clé privée PGP\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutes\",\n  \"components.TvDetails.episodeRuntime\": \"Durée d'un épisode\",\n  \"components.Settings.Notifications.pgpPassword\": \"Mot de passe PGP\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.alreadyrequested\": \"Déjà demandé\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.pagenotfound\": \"La page n'a pas été trouvée\",\n  \"pages.serviceunavailable\": \"Service indisponible\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pause\",\n  \"components.Settings.SettingsLogs.logs\": \"Journaux\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Attention\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Infos\",\n  \"components.Settings.SettingsLogs.filterError\": \"Erreur\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Débogage\",\n  \"components.Settings.SettingsAbout.about\": \"À propos\",\n  \"pages.somethingwentwrong\": \"Un problème est survenu\",\n  \"i18n.usersettings\": \"Paramètres utilisateur\",\n  \"i18n.settings\": \"Paramètres\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notifications\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Message journal copié dans le presse-papiers.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Général\",\n  \"components.Settings.services\": \"Services\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Notifications\",\n  \"components.Settings.enablessl\": \"Utiliser SSL\",\n  \"components.Settings.SettingsUsers.users\": \"Utilisateurs\",\n  \"components.Settings.SettingsLogs.showall\": \"Afficher tous les journaux\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Journal détaillé\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Copier dans le presse-papiers\",\n  \"components.ResetPassword.passwordreset\": \"Réinitialiser le mot de passe\",\n  \"pages.internalservererror\": \"Erreur interne du serveur\",\n  \"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 ?\",\n  \"components.Settings.SettingsLogs.time\": \"Horodatage\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Reprendre\",\n  \"components.Settings.SettingsLogs.message\": \"Message\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Vous pouvez également afficher ces journaux directement via <code>stdout</code>, ou dans <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.level\": \"Gravité\",\n  \"components.Settings.SettingsLogs.label\": \"Étiquette\",\n  \"components.Settings.SettingsLogs.extraData\": \"Données supplémentaires\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Tâches et cache\",\n  \"components.UserList.nouserstoimport\": \"Aucun nouvel utilisateur de Plex à importer.\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Né(e) le {birthdate}\",\n  \"components.PersonDetails.alsoknownas\": \"Aussi connu sous le(s) nom(s) : {names}\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"saison\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Aucune} other {<strong>#</strong>}} {remaining, plural, one {demande} other {demandes}} de {type} {remaining, plural, one {restante} other {restantes}}\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Vous pouvez voir un résumé des limites de demandes de cet utilisateur sur sa <ProfileLink>page de profil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Vous pouvez voir un résumé de vos limites de demandes sur votre <ProfileLink>page de profil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Pas assez de demandes de saisons restantes\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {films}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Cet utilisateur est autorisé à demander <strong>{limit}</strong> {type} tous les <strong>{days}</strong> jour(s).\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Vous êtes autorisé à demander <strong>{limit}</strong> {type} tous les <strong>{days}</strong> jour(s).\",\n  \"components.QuotaSelector.unlimited\": \"Illimité\",\n  \"components.UserProfile.unlimited\": \"Illimité\",\n  \"components.TvDetails.originaltitle\": \"Titre original\",\n  \"components.MovieDetails.originaltitle\": \"Titre original\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {saison} other {saisons}}\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Toutes les langues\",\n  \"components.LanguageSelector.languageServerDefault\": \"Par défaut ({language})\",\n  \"i18n.tvshow\": \"Série\",\n  \"i18n.test\": \"Tester\",\n  \"i18n.save\": \"Sauvegarder les changements\",\n  \"i18n.request4k\": \"Demander en 4K\",\n  \"i18n.movie\": \"Film\",\n  \"components.UserProfile.totalrequests\": \"Total des demandes\",\n  \"components.UserProfile.requestsperdays\": \"{limit} restantes\",\n  \"components.UserProfile.limit\": \"{remaining} sur {limit}\",\n  \"i18n.view\": \"Voir\",\n  \"i18n.testing\": \"Test en cours…\",\n  \"i18n.status\": \"Statut\",\n  \"i18n.saving\": \"Sauvegarde en cours…\",\n  \"i18n.resultsperpage\": \"Afficher {pageSize} résultats par page\",\n  \"i18n.requesting\": \"Demande en cours…\",\n  \"i18n.previous\": \"Précédent\",\n  \"i18n.notrequested\": \"Non demandé\",\n  \"i18n.noresults\": \"Aucun résultat.\",\n  \"i18n.next\": \"Suivant\",\n  \"i18n.canceling\": \"Annulation…\",\n  \"i18n.back\": \"Retour\",\n  \"i18n.areyousure\": \"Êtes-vous sûr ?\",\n  \"i18n.all\": \"Toutes\",\n  \"components.UserProfile.seriesrequest\": \"Demandes de séries\",\n  \"components.UserProfile.pastdays\": \"{type} (derniers {days} jours)\",\n  \"components.UserProfile.movierequests\": \"Demandes de films\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Limite de demandes de films\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Limite de demandes de séries\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Contourner la limite globale\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Chargement des tags en cours…\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Modifier le serveur Sonarr 4K\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Serveur 4K par défaut\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Ajouter un nouveau serveur Sonarr 4K\",\n  \"components.Settings.SonarrModal.animeTags\": \"Tags pour les animés\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Limite globale de demandes de séries\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Limite globale de demandes de films\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Tester la connexion pour charger les tags\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Tester la connexion pour charger les tags\",\n  \"components.Settings.SonarrModal.tags\": \"Tags\",\n  \"components.Settings.RadarrModal.tags\": \"Tags\",\n  \"components.Settings.SonarrModal.selecttags\": \"Sélectionner les tags\",\n  \"components.Settings.RadarrModal.selecttags\": \"Sélectionner les tags\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Aucun tag.\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Aucun tag.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Chargement des tags en cours…\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Modifier le serveur Radarr 4K\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Serveur 4K par défaut\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Ajouter un nouveau serveur Radarr 4K\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Tags\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Sélectionner les tags\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Aucun tag.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Chiffrer les emails en utilisant <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Votre compte n'a actuellement aucun mot de passe défini. Définissez un mot de passe ci-dessous pour activer la connexion en tant qu'« utilisateur local » avec votre adresse e-mail.\",\n  \"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.\\\"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Vous devez fournir une clé publique PGP valide\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Paramètres de notification Telegram enregistrés avec succès !\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Impossible d’enregistrer les paramètres de notification de Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Clé Publique PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Les paramètres de notification Discord n’ont pas pu être enregistrés.\",\n  \"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 modifier le serveur utilisé pour traiter les nouvelles demandes avant la validation.\",\n  \"components.Settings.mediaTypeSeries\": \"séries\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.SettingsAbout.uptodate\": \"À jour\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Obsolète\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Vous devez fournir une clé privée PGP valide\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Vous devez fournir un mot de passe PGP\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Permet aux utilisateurs de démarrer également une conversation avec votre bot et de configurer leurs propres notifications personnelles\",\n  \"components.RequestModal.pendingapproval\": \"Votre demande est en attente de validation.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} non trouvé\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Supprimer la demande\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Annuler la demande\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} non trouvé\",\n  \"components.RequestCard.deleterequest\": \"Supprimer la demande\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Types de Notification\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr stable\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Développement de Seerr\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} en retard\",\n  \"components.Layout.VersionStatus.outofdate\": \"Obsolète\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Vous devez avoir au moins <strong>{seasons}</strong> {seasons, plural, one {demande de saison} other {demandes de saisons}} afin de soumettre une demande pour cette série.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Cet utilisateur doit avoir au moins <strong>{seasons}</strong> {seasons, plural, one {demande de saison} other {demandes de saisons}} afin de soumettre une demande pour cette série.\",\n  \"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 <strong>PAS</strong> être désigné comme serveur 4K.\",\n  \"components.Settings.noDefaultServer\": \"Au moins un serveur {serverType} doit être marqué par défaut pour que les demandes {mediaType} puissent être envoyées.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Paramètres de notification Discord enregistrés avec succès !\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Impossible d’enregistrer les paramètres de notification par E-mail.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Paramètres de notification par E-mail enregistrés avec succès !\",\n  \"i18n.showingresults\": \"Affichage de <strong>{from}</strong> à <strong>{to}</strong> pour <strong>{total}</strong> résultats\",\n  \"components.UserList.autogeneratepasswordTip\": \"Envoyer par email un mot de passe généré par le serveur à l’utilisateur\",\n  \"i18n.retrying\": \"Nouvelle tentative…\",\n  \"components.Settings.serverSecure\": \"sécurisée\",\n  \"components.RequestModal.edit\": \"Modifier la demande\",\n  \"components.RequestList.RequestItem.editrequest\": \"Modifier la demande\",\n  \"components.UserList.usercreatedfailedexisting\": \"L'adresse électronique fournie est déjà utilisée par un autre utilisateur.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Langue d'affichage\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Activer la recherche automatique\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Activer la recherche automatique\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Les paramètres de la notification Web push ont été enregistrés avec succès !\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Les paramètres de la notification Web push n'ont pas été enregistrés.\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Activer l'agent\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Autorise à demander des films non-4K.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"La notification de test Web Push n’a pas été envoyée.\",\n  \"components.PermissionEdit.requestMovies\": \"Demander des films\",\n  \"components.PermissionEdit.requestTv\": \"Demander des séries\",\n  \"components.PermissionEdit.requestTvDescription\": \"Autorise à demander des séries non-4K.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Envoi de la notification test Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"L'envoi de la notification test Pushbullet a échoué.\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"L'envoi de la notification test à Telegram a échoué.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Notification test Pushbullet envoyée !\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Envoi de la notification test Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"L'envoi de la notification test Pushover a échoué.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Notification test Pushover envoyée !\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Utiliser TLS implicite\",\n  \"components.Settings.Notifications.encryptionTip\": \"Dans la majorité des cas, TLS implicite utilise le port 465 et STARTTLS utilise le port 587\",\n  \"components.Settings.Notifications.encryptionNone\": \"Aucune\",\n  \"components.Settings.Notifications.encryption\": \"Méthode de chiffrement\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Utiliser STARTTLS si disponible\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Toujours utiliser STARTTLS\",\n  \"components.DownloadBlock.estimatedtime\": \"Estimation {time}\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Votre <UsersGroupsLink>identifiant d'utilisateur ou de groupe</UsersGroupsLink> de 30 caractères\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Enregistrer une application</ApplicationRegistrationLink> à utiliser avec Seerr\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Demandé\",\n  \"components.RequestCard.failedretry\": \"Une erreur s'est produite lors du renvoi de la demande.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Notification de test web push envoyée !\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Envoi d'une notification de test web push…\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Afin de recevoir des notifications push web, Seerr doit fonctionner en HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Notification de test Webhook envoyée !\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Envoi de notification de test webhook…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"L'envoi de la notification de test Web push a échoué.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Notification test Slack envoyée !\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Envoi de la notification test Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"L'envoi de la notification test Slack a échoué.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Créer un jeton à partir de vos <PushbulletSettingsLink>paramètres de compte</PushbulletSettingsLink>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {saison} other {saisons}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {films}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} tous les {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {jour} other {jours}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Par défaut ({language})\",\n  \"components.Settings.webAppUrlTip\": \"Dirigez éventuellement les utilisateurs vers l'application Web sur votre serveur au lieu de l'application Web « hébergée »\",\n  \"components.Settings.webAppUrl\": \"URL <WebAppLink>Application Web</WebAppLink>\",\n  \"components.Settings.noDefault4kServer\": \"Un serveur 4K {serverType} doit être marqué par défaut afin de permettre aux utilisateurs de soumettre des requêtes 4K {mediaType}.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Autoriser les utilisateurs {mediaServerName} à se connecter sans avoir été importés\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Autoriser l'inscription via {mediaServerName}\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Permettre aux utilisateurs de se connecter en utilisant leur adresse e-mail et leur mot de passe\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Autorisations par défaut attribuées aux nouveaux utilisateurs\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Créez une <DiscordWebhookLink>intégration de webhook</DiscordWebhookLink> dans votre serveur\",\n  \"components.Settings.Notifications.validationTypes\": \"Vous devez sélectionner au moins un type de notification\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Notification de test Telegram envoyée !\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Envoi de la notification de test à Telegram…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Notification de test par e-mail envoyée !\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Envoi d'une notification de test par e-mail…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Échec de l'envoi de la notification de test par e-mail.\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Notification de test Discord envoyée !\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Envoi de la notification de test Discord…\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Échec de l'envoi de la notification de test Discord.\",\n  \"components.Settings.Notifications.chatIdTip\": \"Démarrez une discussion avec votre bot, ajoutez <GetIdBotLink>@get_id_bot</GetIdBotLink> et exécutez la commande <code>/my_id</code>\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Créer un bot</CreateBotLink> à utiliser avec Seerr\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Vous devez sélectionner au moins un type de notification\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Vous devez sélectionner au moins un type de notification\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Vous devez sélectionner au moins un type de notification\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Vous devez sélectionner au moins un type de notification\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} tous les {quotaDays} {days}</quotaUnits>\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Être averti(e) lorsque d'autres utilisateurs soumettent une demande de média qui nécessite une validation.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Être averti(e) lorsqu'une demande de média n'a pas pu être ajoutée à Radarr ou Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Être averti(e) lorsque vos demandes de médias sont refusées.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Être averti(e) lorsque vos demandes de médias deviennent disponibles.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Être averti(e) lorsque vos demandes de médias sont validées.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Être averti(e) lorsque des utilisateurs soumettent une demande de média qui est validée automatiquement.\",\n  \"components.MovieDetails.showmore\": \"Montrer plus\",\n  \"components.MovieDetails.showless\": \"Montrer moins\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Langue d'affichage\",\n  \"components.UserList.localLoginDisabled\": \"Le paramètre <strong>Activer la connexion locale</strong> est actuellement désactivé.\",\n  \"components.TvDetails.streamingproviders\": \"Disponible en streaming sur\",\n  \"components.MovieDetails.streamingproviders\": \"Disponible en streaming sur\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Créer une intégration <WebhookLink>Webhook entrante</WebhookLink>\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"{jobScheduleHours, plural, one {Une fois par heure} other {Toutes les {jobScheduleHours} heures}}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Êtes-vous sûr de vouloir supprimer ce commentaire ?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Supprimer le commentaire\",\n  \"components.IssueDetails.IssueComment.edit\": \"Éditer le commentaire\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Ajouté {relativeTime} par {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Ajouté {relativeTime} par {username} (Édité)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Vous devez écrire un message\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Supprimer le problème\",\n  \"components.IssueDetails.IssueDescription.description\": \"Description\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Éditer la description\",\n  \"components.IssueDetails.allepisodes\": \"Tous les épisodes\",\n  \"components.IssueDetails.allseasons\": \"Toutes les saisons\",\n  \"components.IssueDetails.closeissue\": \"Clore le problème\",\n  \"components.IssueDetails.closeissueandcomment\": \"Clore avec un commentaire\",\n  \"components.IssueDetails.commentplaceholder\": \"Ajouter un commentaire…\",\n  \"components.IssueDetails.comments\": \"Commentaires\",\n  \"components.IssueDetails.deleteissue\": \"Supprimer le problème\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Êtes-vous sûr de vouloir supprimer ce problème ?\",\n  \"components.IssueDetails.episode\": \"Épisode {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Problème\",\n  \"components.IssueDetails.issuetype\": \"Type\",\n  \"components.IssueDetails.lastupdated\": \"Dernière mise à jour\",\n  \"components.IssueDetails.leavecomment\": \"Commenter\",\n  \"components.IssueDetails.nocomments\": \"Aucun commentaire.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} ouvert {relativeTime} par {username}\",\n  \"components.IssueDetails.openin4karr\": \"Ouvrir dans {arr} 4K\",\n  \"components.IssueDetails.openinarr\": \"Ouvrir dans {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Lire en 4K sur {mediaServerName}\",\n  \"components.IssueDetails.playonplex\": \"Lire sur {mediaServerName}\",\n  \"components.IssueDetails.problemepisode\": \"Épisode concerné\",\n  \"components.IssueDetails.problemseason\": \"Saison concernée\",\n  \"components.IssueDetails.reopenissue\": \"Rouvrir le problème\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Rouvrir avec un commentaire\",\n  \"components.IssueDetails.season\": \"Saison {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Un problème est survenu lors de l'édition de la description du problème.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"La description du problème a été éditée avec succès !\",\n  \"components.IssueDetails.toastissuedeleted\": \"Le problème a été supprimé avec succès !\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Un problème est survenu lors de la suppression du problème.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Le statut du problème a été mis à jour avec succès !\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Un problème est survenu lors de la mise à jour du statut du problème.\",\n  \"components.IssueDetails.unknownissuetype\": \"Inconnu\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Épisode} other {Épisodes}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Statut\",\n  \"components.IssueList.IssueItem.issuetype\": \"Type\",\n  \"components.IssueList.IssueItem.opened\": \"Ouvert\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} par {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Épisode concerné\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Saison} other {Saisons}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Inconnu\",\n  \"components.IssueList.IssueItem.viewissue\": \"Afficher le problème\",\n  \"components.IssueList.issues\": \"Problèmes\",\n  \"components.IssueList.showallissues\": \"Afficher tous les problèmes\",\n  \"components.IssueList.sortAdded\": \"Plus récents\",\n  \"components.IssueList.sortModified\": \"Dernière modification\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Tous les épisodes\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Toutes les saisons\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Épisode {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extras\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Épisode concerné\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Saison concernée\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Fournissez une explication détaillée du problème.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Être averti(e) lorsqu'un problème que vous avez signalé est résolu.\",\n  \"components.PermissionEdit.manageissues\": \"Gérer les problèmes\",\n  \"components.PermissionEdit.viewissues\": \"Afficher les problèmes\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Autorise à consulter les problèmes liés aux médias signalés par d'autres utilisateurs.\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Un problème est survenu lors de la soumission du problème.\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Afficher le problème\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Le signalement du problème pour <strong>{title}</strong> a été soumis avec succès !\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Qu’est-ce qui ne va pas ?\",\n  \"components.Layout.Sidebar.issues\": \"Problèmes\",\n  \"components.ManageSlideOver.downloadstatus\": \"Téléchargement(s)\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Aucune demande.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Demandes\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Gérer {mediaType}\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Ceci supprimera de manière irréversible toutes les données de ce(tte) {mediaType}, y compris les demandes éventuelles. Si cet élément existe dans votre bibliothèque {mediaServerName}, les informations sur le média seront recréées lors de la prochaine analyse.\",\n  \"components.ManageSlideOver.tvshow\": \"série\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Commentaires du problème\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Envoyer des notifications lorsqu'un problème est signalé.\",\n  \"components.PermissionEdit.createissues\": \"Signaler des problèmes\",\n  \"components.PermissionEdit.createissuesDescription\": \"Autorise à signaler les problèmes liés aux médias.\",\n  \"i18n.resolved\": \"Résolu\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Être averti(e) lorsqu'un problème que vous avez signalé reçoit de nouveaux commentaires.\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Effacer les données\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Saison {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Vous devez fournir une description\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Signaler un problème\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Soumettre le problème\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueModal.issueOther\": \"Autre\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Marquer comme disponible en 4K\",\n  \"components.ManageSlideOver.markavailable\": \"Marquer comme disponible\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Vous utilisez la branche <code>develop</code> de Seerr, qui n'est recommandée que pour ceux qui contribuent au développement ou qui aident aux tests et correctifs.\",\n  \"components.ManageSlideOver.openarr\": \"Ouvrir dans {arr}\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Être averti(e) lorsque d'autres utilisateurs commentent sur un problème.\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Envoyer des notifications lorsqu'un problème reçoit de nouveaux commentaires.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problème résolu\",\n  \"components.ManageSlideOver.openarr4k\": \"Ouvrir dans {arr} 4K\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problème signalé\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Envoyer des notifications lorsqu'un problème est résolu.\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Nouvelle fréquence\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Tâche modifiée avec succès !\",\n  \"i18n.open\": \"Ouvert\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modifier la tâche\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Être averti(e) lorsque d’autres utilisateurs signalent des problèmes.\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Autorise à gérer les problèmes liés aux médias.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Un problème est survenu lors de l'enregistrement de la tâche.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Toutes les {jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Jeton d'accès\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Être averti(e) lorsqu'un problème est ré-ouvert par d'autres utilisateurs.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Être averti(e) lorsqu'un problème est résolu par d'autres utilisateurs.\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Envoyer des notifications lorsqu'un problème est rouvert.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Être averti(e) lorsqu'un problème que vous avez signalé a été rouvert.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Les paramètres de notification Pushbullet n'ont pas été sauvegardés correctement.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Les paramètres de notification Pushbullet ont été sauvegardés correctement !\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Jeton API d'application\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Enregistrer une application</ApplicationRegistrationLink> à utiliser avec {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Vous devez fournir un jeton d'application valide\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Les paramètres de notification Pushover n'ont pas pu être enregistrés.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Paramètres de notification Pushover enregistrés avec succès !\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Créer un jeton depuis les <PushbulletSettingsLink>paramètres de votre compte</PushbulletSettingsLink>\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Problèmes ouverts\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Vous devez fournir une clé d'utilisateur ou de groupe valide\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problème rouvert\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Vous devez fournir un jeton d'accès\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Clé d'utilisateur ou de groupe\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Votre <UsersGroupsLink>identifiant d'utilisateur ou de groupe</UsersGroupsLink> à 30 caractères\",\n  \"components.RequestModal.requestmovies4k\": \"Demander {count} {count, plural, one {film} other {films}} en 4K\",\n  \"components.RequestModal.selectmovies\": \"Sélectionner le(s) film(s)\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {Pays} other {Pays}} de production\",\n  \"components.Settings.RadarrModal.announced\": \"Annoncé\",\n  \"components.RequestModal.approve\": \"Valider la demande\",\n  \"components.RequestModal.requestseasons4k\": \"Demander {seasonCount} {seasonCount, plural, one {saison} other {saisons}} en 4K\",\n  \"components.RequestModal.requestmovies\": \"Demander {count} {count, plural, one {film} other {films}}\",\n  \"components.RequestModal.requestApproved\": \"Demande pour <strong>{title}</strong> validée !\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Au cinéma\",\n  \"components.Settings.RadarrModal.released\": \"Publié\",\n  \"components.TvDetails.productioncountries\": \"Pays de production\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Activer l'agent\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Les paramètres de notification Gotify n'ont pas pu être enregistrés.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Paramètres de notification de Gotify sauvegardés avec succès !\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Envoi de la notification test Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Notification test Gotify envoyée !\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Jeton d'application\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL du serveur\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Vous devez sélectionner au moins un type de notification\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Vous devez fournir une URL valide\",\n  \"components.Settings.Notifications.enableMentions\": \"Activer les mentions\",\n  \"i18n.import\": \"Importer\",\n  \"i18n.importing\": \"Importation…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"L'envoi de la notification test Gotify a échoué.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Vous devez fournir un jeton d'application\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"L'URL ne doit pas se terminer par un slash (/)\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avancé\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Média(s) 4K\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Marquer toutes les saisons comme disponibles en 4K\",\n  \"components.ManageSlideOver.playedby\": \"Joué par\",\n  \"components.Settings.validationUrlTrailingSlash\": \"L'URL ne doit pas se terminer par un slash (/)\",\n  \"components.Settings.externalUrl\": \"URL externe\",\n  \"components.Settings.tautulliApiKey\": \"Clé API\",\n  \"components.Settings.tautulliSettings\": \"Paramètres Tautulli\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Un problème est survenu lors de l'enregistrement des paramètres Tautulli.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Paramètres Tautulli enregistrés avec succès !\",\n  \"components.Settings.urlBase\": \"URL de base\",\n  \"components.Settings.validationApiKey\": \"Vous devez fournir une clé API\",\n  \"components.Settings.validationUrl\": \"Vous devez fournir une URL valide\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"L'URL de base doit commencer par un slash (/)\",\n  \"components.UserProfile.recentlywatched\": \"Vu récemment\",\n  \"components.ManageSlideOver.opentautulli\": \"Ouvrir dans Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"{days, number} derniers jours\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {lecture} other {lectures}}\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Étiquette de canal\",\n  \"components.ManageSlideOver.alltime\": \"Tout le temps\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Média(s)\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Marquer toutes les saisons comme disponibles\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"L'URL de base ne doit pas se terminer par un slash (/)\",\n  \"components.Settings.tautulliSettingsDescription\": \"Configuration optionnelle pour votre serveur Tautulli. Seerr va récupérer l'historique de visionnage de votre Plex depuis Tautulli.\",\n  \"components.UserList.newplexsigninenabled\": \"L'option <strong>Autoriser nouvelle connexion Plex</strong> est actuellement activée. Les utilisateurs Plex disposant d'un accès à la librairie n'ont pas besoin d'être importés pour pouvoir ce connecter.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID utilisateur Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Le <FindDiscordIdLink>numéro d'identification à plusieurs chiffres</FindDiscordIdLink> associé à votre compte Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Vous devez fournir un ID utilisateur Discord valide\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Répertoire de données\",\n  \"components.MovieDetails.digitalrelease\": \"Sortie numérique\",\n  \"components.MovieDetails.physicalrelease\": \"Sortie physique\",\n  \"components.PermissionEdit.autorequest\": \"Demande automatique\",\n  \"components.MovieDetails.theatricalrelease\": \"Sortie en salles\",\n  \"components.StatusChecker.reloadApp\": \"Recharger {applicationTitle}\",\n  \"components.PermissionEdit.viewrecent\": \"Voir les ajouts récents\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Autorise à voir la liste des médias ajoutés récemment.\",\n  \"i18n.restartRequired\": \"Redémarrage nécessaire\",\n  \"components.RequestCard.tmdbid\": \"ID TMDB\",\n  \"components.RequestCard.tvdbid\": \"ID TheTVDB\",\n  \"components.RequestList.RequestItem.tmdbid\": \"ID TMDB\",\n  \"components.RequestList.RequestItem.tvdbid\": \"ID TheTVDB\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Demande soumise automatiquement\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Autorise l'envoi de demande automatique pour les vidéos non-4K via la liste de suivi Plex.\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Autorise l'envoi de demande automatique pour les séries non-4K via la liste de suivi Plex.\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Veuillez cliquer sur le bouton ci-dessous pour recharger l'application.\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Veuillez redémarrer le serveur pour appliquer les paramètres mis à jour.\",\n  \"components.TitleCard.cleardata\": \"Effacer les données\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} non trouvé\",\n  \"components.TitleCard.tmdbid\": \"ID TMDB\",\n  \"components.TitleCard.tvdbid\": \"ID TheTVDB\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Demander automatiquement les films\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Demander automatiquement les Séries\",\n  \"components.PermissionEdit.autorequestDescription\": \"Autorise l'envoi de demande automatique pour les médias non-4K via la liste de suivi Plex.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Demander automatiquement les Films\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Demande automatiquement les séries de votre <PlexWatchlistSupportLink>liste de suivi Plex</PlexWatchlistSupportLink>\",\n  \"components.PermissionEdit.autorequestSeries\": \"Demander automatiquement les Séries\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Synchronisation de la liste de suivi Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Demande automatiquement les films de votre <PlexWatchlistSupportLink>liste de suivi Plex</PlexWatchlistSupportLink>\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Recevez une notification lorsque de nouvelles demandes de médias sont automatiquement soumises pour des éléments de votre liste de suivi.\",\n  \"components.StatusChecker.restartRequired\": \"Redémarrage du serveur requis\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} mis à jour\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Voir les détails\",\n  \"components.Settings.advancedTooltip\": \"Une configuration incorrecte de ce paramètre peut entraîner un dysfonctionnement\",\n  \"components.Settings.experimentalTooltip\": \"L'activation de ce paramètre peut entraîner un comportement inattendu de l'application\",\n  \"components.PermissionEdit.viewwatchlists\": \"Voir les listes de suivi {mediaServerName}\",\n  \"components.TvDetails.reportissue\": \"Signaler un problème\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Demandes de films\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Demandes de séries\",\n  \"components.Layout.UserDropdown.requests\": \"Demandes\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"L'adresse e-mail est invalide.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Une adresse e-mail est requise.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Un mot de passe est requis.\",\n  \"components.Login.credentialerror\": \"Le nom d’utilisateur ou le mot de passe est incorrect.\",\n  \"components.Login.description\": \"Comme il s’agit de votre première connexion à {applicationName}, vous devez ajouter une adresse E-mail valide.\",\n  \"components.Login.initialsignin\": \"Connexion\",\n  \"components.Login.initialsigningin\": \"Connexion en cours…\",\n  \"components.Login.save\": \"Ajouter\",\n  \"components.Login.saving\": \"Ajout…\",\n  \"components.Login.signinwithjellyfin\": \"Utilisez votre compte {mediaServerName}\",\n  \"components.Login.title\": \"Ajouter un e-mail\",\n  \"components.Login.username\": \"Nom d'utilisateur\",\n  \"components.Login.validationEmailFormat\": \"E-mail invalide\",\n  \"components.Login.validationEmailRequired\": \"Vous devez fournir un e-mail\",\n  \"components.Login.validationemailformat\": \"Vous devez fournir un e-mail valide\",\n  \"components.Login.validationhostformat\": \"URL valide requise\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL requise\",\n  \"components.Login.validationusernamerequired\": \"Nom d'utilisateur requis\",\n  \"components.MovieDetails.imdbuserscore\": \"Note des utilisateurs IMDB – votes : {formattedCount}\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Cela supprimera irréversiblement ce(tte) {mediaType} de {arr}, y compris tous les fichiers.\",\n  \"components.ManageSlideOver.removearr\": \"Supprimer de {arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"Supprimer de {arr} 4K\",\n  \"components.MovieDetails.downloadstatus\": \"Statut du téléchargement\",\n  \"components.MovieDetails.managemovie\": \"Gérer le film\",\n  \"components.MovieDetails.openradarr\": \"Ouvrir le film dans Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"Ouvrir le film dans Radarr 4K\",\n  \"components.MovieDetails.play\": \"Lire sur {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Lire en 4K sur {mediaServerName}\",\n  \"components.MovieDetails.reportissue\": \"Signaler un problème\",\n  \"components.MovieDetails.rtaudiencescore\": \"Score d’audience Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatomètre Rotten Tomatoes\",\n  \"components.MovieDetails.tmdbuserscore\": \"Note des utilisateurs TMDB\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Autorise à voir les listes de suivi {mediaServerName} des autres utilisateurs.\",\n  \"components.RequestBlock.approve\": \"Approuver la demande\",\n  \"components.RequestBlock.decline\": \"Refuser la demande\",\n  \"components.RequestBlock.delete\": \"Supprimer la demande\",\n  \"components.RequestBlock.edit\": \"Modifier la demande\",\n  \"components.RequestBlock.languageprofile\": \"Profil de langue\",\n  \"components.RequestBlock.lastmodifiedby\": \"Dernière modification par\",\n  \"components.RequestBlock.requestdate\": \"Date de la demande\",\n  \"components.RequestBlock.requestedby\": \"Demandé par\",\n  \"components.RequestCard.approverequest\": \"Approuver la demande\",\n  \"components.RequestCard.cancelrequest\": \"Annuler la demande\",\n  \"components.RequestCard.declinerequest\": \"Refuser la demande\",\n  \"components.RequestCard.editrequest\": \"Modifier la demande\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr doit être redémarré pour que les modifications de ce paramètre prennent effet\",\n  \"components.Settings.deleteServer\": \"Supprimer le serveur {serverType}\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Demander la collection en 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Demander la collection\",\n  \"components.UserProfile.emptywatchlist\": \"Les médias ajoutés à votre <PlexWatchlistSupportLink>liste de suivi Plex</PlexWatchlistSupportLink> apparaîtront ici.\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Nous n'avons pas pu trouver de correspondance pour cette série.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Demander le film en 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Demander le film\",\n  \"components.RequestModal.requestseries4ktitle\": \"Demander la série en 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Demander la série\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Fréquence actuelle\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Titre inconnu\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Un problème est survenu lors de l'enregistrement des paramètres.\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Vous devez fournir une URL valide\",\n  \"components.TvDetails.Season.noepisodes\": \"Liste des épisodes non disponibles.\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.RequestCard.unknowntitle\": \"Titre inconnu\",\n  \"components.Settings.SettingsMain.locale\": \"Langue d'affichage\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Nouvelle clé d'API générée avec succès !\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Un problème est survenu lors de la génération de la nouvelle clé d'API.\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"L'URL ne doit pas se terminer par un slash (/)\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Taille totale du cache\",\n  \"components.Settings.SettingsMain.apikey\": \"Clé d'API\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Nom de l'application\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL de l'application\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Activer la mise en cache d'images\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Met en cache localement et utilise des images optimisées (nécessite un espace disque important)\",\n  \"components.Settings.SettingsMain.general\": \"Général\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Paramètres généraux\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Paramètres sauvegardés avec succès !\",\n  \"components.DownloadBlock.formattedTitle\": \"{title} : Saison {seasonNumber} épisode {episodeNumber}\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Images mises en cache\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Cache d'images\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Une fois activé dans les paramètres, Seerr va récupérer et mettre en cache les images provenant de sources externes pré-configurées. Les images mises en cache sont enregistrées dans votre dossier de configuration. Vous pouvez trouver les fichiers dans le répertoire <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Nettoyage du cache d'images\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Masquer les médias disponibles\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrer le contenu par langue d’origine\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Vous devez fournir un nom d'application\",\n  \"components.Discover.updatefailed\": \"Une erreur s'est produite lors de la mise à jour des paramètres de Découvrir.\",\n  \"components.Discover.updatesuccess\": \"Mise à jour des paramètres de Découvrir.\",\n  \"components.Layout.Sidebar.browsemovies\": \"Films\",\n  \"components.Selector.searchGenres\": \"Sélectionnez un ou plusieurs genres…\",\n  \"components.Selector.searchKeywords\": \"Recherchez un ou plusieurs mots-clés…\",\n  \"components.Selector.searchStudios\": \"Recherchez un ou plusieurs studios…\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Configurer les paramètres généraux et par défaut pour Seerr.\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Langue dans Découvrir\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Permettre les demandes partielles de séries\",\n  \"components.Selector.nooptions\": \"Aucun résultat.\",\n  \"components.Layout.Sidebar.browsetv\": \"Séries\",\n  \"components.Selector.showmore\": \"En voir plus\",\n  \"components.Selector.showless\": \"En voir moins\",\n  \"components.Selector.starttyping\": \"Commencez à taper pour rechercher.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"{jobScheduleSeconds, plural, one {Une fois par seconde} other {Toutes les {jobScheduleSeconds} secondes}}\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Synchronisation de la disponibilité des médias\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Tager les demandes\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Tager les demandes\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Ajouter automatiquement un tag supplémentaire avec l'identifiant et le nom du demandeur\",\n  \"i18n.collection\": \"Collection\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Ajouter automatiquement un tag supplémentaire avec l'identifiant et le nom du demandeur\",\n  \"components.IssueModal.issueVideo\": \"Vidéo\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Son de notification\",\n  \"components.Settings.jellyfinSettings\": \"Paramètres {mediaServerName}\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Une erreur s'est produite lors de la sauvegarde des paramètres de {mediaServerName}.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"Paramètres de {mediaServerName} sauvegardés avec succès !\",\n  \"components.Settings.jellyfinlibraries\": \"Bibliothèques {mediaServerName}\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"Les bibliothèques de {mediaServerName} sont en cours d'analyse. Cliquez sur le bouton ci-dessous si aucune bibliothèque n'est répertoriée.\",\n  \"components.Settings.jellyfinsettings\": \"Paramètres {mediaServerName}\",\n  \"components.Settings.manualscanJellyfin\": \"Scan manuel de la bibliothèque\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.save\": \"Enregistrer les modifications\",\n  \"components.Settings.saving\": \"Enregistrement en cours…\",\n  \"components.Settings.syncing\": \"Synchronisation en cours\",\n  \"components.Setup.signin\": \"Se connecter\",\n  \"components.Setup.signinWithPlex\": \"Entrez vos identifiants Plex\",\n  \"components.StatusBadge.managemedia\": \"Gérer {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Ouvrir dans {arr}\",\n  \"components.StatusBadge.playonplex\": \"Lire sur {mediaServerName}\",\n  \"components.TitleCard.addToWatchList\": \"Ajouter à la liste de suivi\",\n  \"components.TitleCard.watchlistCancel\": \"List de suivi pour <strong>{title}</strong> annulée.\",\n  \"components.TitleCard.watchlistError\": \"Un problème est survenu. Veuillez réessayer.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> a été ajouté à votre liste de suivi avec succès !\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Une erreur est survenue lors de la récupération des données de la saison.\",\n  \"components.TvDetails.manageseries\": \"Gérer les séries\",\n  \"components.TvDetails.play\": \"Lire sur {mediaServerName}\",\n  \"components.TvDetails.play4k\": \"Lire en 4K sur {mediaServerName}\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomatometer sur Rotten Tomatoes\",\n  \"components.TvDetails.seasonnumber\": \"Saison {seasonNumber}\",\n  \"components.TvDetails.seasonstitle\": \"Saisons\",\n  \"components.TvDetails.status4k\": \"{status} 4K\",\n  \"components.TvDetails.tmdbuserscore\": \"Score utilisateur sur TMDB\",\n  \"components.UserList.importfromJellyfin\": \"Importer les utilisateurs de {mediaServerName}\",\n  \"components.UserList.importfromJellyfinerror\": \"Une erreur est survenue lors de l'importation des utilisateurs de {mediaServerName}.\",\n  \"components.UserList.importfrommediaserver\": \"Importer les utilisateurs de {mediaServerName}\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Il n'y a aucun utilisateur à importer pour {mediaServerName}.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Sauvegarde en cours…\",\n  \"components.UserProfile.plexwatchlist\": \"Liste de suivi Plex\",\n  \"components.Settings.syncJellyfin\": \"Synchroniser les bibliothèques\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> a été retiré de votre liste de suivi avec succès !\",\n  \"components.IssueModal.issueSubtitles\": \"Sous-titre\",\n  \"components.Login.emailtooltip\": \"L'adresse ne nécessite pas d'être associée avec votre instance {mediaServerName}.\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Appareil par défaut\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Email utilisateur requis\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Scan complet des bibliothèques Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Scan des ajouts récents aux bibliothèques Jellyfin\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Type d'animés\",\n  \"components.Settings.SonarrModal.seriesType\": \"Type de série\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Configure les paramètres de votre serveur {mediaServerName}. {mediaServerName} parcourt vos bibliothèques {mediaServerName} à la recherche de contenus disponibles.\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Configurez facultativement les URL internes et externes pour votre serveur {mediaServerName}. Dans la plupart des cas, l'URL externe est différente de l'URL interne. Vous pouvez également définir une URL de réinitialisation de mot de passe personnalisée pour la connexion à {mediaServerName}, au cas où vous souhaiteriez rediriger vers une page de réinitialisation de mot de passe différente.\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalement, cette tâche n'est executée qu'une fois toutes les 24 heures. Seerr vérifiera plus agressivement les éléments récemment ajoutés à votre serveur {mediaServerName}. Si c'est la première fois que vous configurez Seerr, une analyse complète manuelle de la bibliothèque est recommandée !\",\n  \"components.Settings.timeout\": \"Temps écoulé\",\n  \"components.Setup.configuremediaserver\": \"Configurer le serveur multimédia\",\n  \"components.TvDetails.rtaudiencescore\": \"Score de l'audience sur Rotten Tomatoes\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Utilisateur {mediaServerName}\",\n  \"components.Setup.signinWithJellyfin\": \"Entrez vos identifiants Jellyfin\",\n  \"components.UserList.mediaServerUser\": \"Utilisateur {mediaServerName}\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Épisode} other {# Épisodes}}\",\n  \"components.UserList.newJellyfinsigninenabled\": \"Le paramètre <strong>Activer la nouvelle connexion à {mediaServerName}</strong> est actuellement activé. Les utilisateurs de {mediaServerName} avec accès à la bibliothèque n'ont pas besoin d'être importés pour se connecter.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Enregistrer les modifications\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Appareil par défaut\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {utilisateur importé} other {utilisateurs importés}} avec succès !\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Son de notification\",\n  \"components.UserProfile.localWatchlist\": \"Liste de suivi de {username}\",\n  \"components.Login.invalidurlerror\": \"Impossible de se connecter au serveur {mediaServerName}.\",\n  \"components.MovieDetails.removefromwatchlist\": \"Supprimer de la liste de suivi\",\n  \"components.Login.adminerror\": \"Vous devez utiliser un compte administrateur pour vous connecter.\",\n  \"components.MovieDetails.addtowatchlist\": \"Ajouter à la liste de suivi\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> a bien été supprimé de la liste de suivi !\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"L'URL de base ne doit pas se terminer par un slash (/)\",\n  \"components.RequestList.RequestItem.profileName\": \"Profil\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Email valide requis\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> a bien été supprimé de la liste de suivi !\",\n  \"components.TvDetails.addtowatchlist\": \"Ajouter à la liste de suivi\",\n  \"components.Login.enablessl\": \"Utilise SSL\",\n  \"components.Login.hostname\": \"URL de {mediaServerName}\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.urlBase\": \"URL de base\",\n  \"components.Login.validationPortRequired\": \"Vous devez fournir un numéro de port valide\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"L'URL de base doit commencer par un slash (/)\",\n  \"components.Login.validationUrlTrailingSlash\": \"L'URL ne doit pas se terminer par un slash (/)\",\n  \"components.MovieDetails.watchlistError\": \"Une erreur s'est produite. Merci de réessayez.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> a bien été ajouté à la liste de suivi !\",\n  \"components.Settings.invalidurlerror\": \"Impossible de se connecter au serveur {mediaServerName}.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"URL de mot de passe oublié\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"L'authentification personnalisée avec le regroupement automatique de bibliothèques n'est pas prise en charge\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Une erreur s'est produite lors de la synchronisation des bibliothèques\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Aucune bibliothèque n'a été trouvée\",\n  \"components.TvDetails.removefromwatchlist\": \"Supprimer de la liste de suivi\",\n  \"components.TvDetails.watchlistError\": \"Un problème est survenu. Veuillez réessayer.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> a bien été ajouté à la liste de suivi !\",\n  \"components.UserList.username\": \"Nom d'utilisateur\",\n  \"components.UserList.validationUsername\": \"Vous devez fournir un nom d'utilisateur\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Email requis\",\n  \"components.Login.validationservertyperequired\": \"Merci de sélectionner un type de serveur\",\n  \"components.Setup.servertype\": \"Choisir le type de serveur\",\n  \"components.Login.back\": \"Retourner en arrière\",\n  \"components.Login.servertype\": \"Type de serveur\",\n  \"components.Selector.canceled\": \"Annulé(e)\",\n  \"components.Selector.ended\": \"Terminé(e)\",\n  \"components.Selector.inProduction\": \"En production\",\n  \"components.Selector.pilot\": \"Pilote\",\n  \"components.Selector.planned\": \"Planifié(e)\",\n  \"components.Selector.returningSeries\": \"Série de retour\",\n  \"components.Selector.searchStatus\": \"Sélectionnez un ou plusieurs statuts...\",\n  \"components.Setup.back\": \"Retourner en arrière\",\n  \"components.Setup.configemby\": \"Configurer Emby\",\n  \"components.Setup.configjellyfin\": \"Configurer Jellyfin\",\n  \"components.Setup.configplex\": \"Configurer Plex\",\n  \"components.Setup.signinWithEmby\": \"Entrez vos identifiants Emby\",\n  \"components.Setup.subtitle\": \"Commencez par choisir votre serveur multimédia\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.Discover.FilterSlideover.status\": \"Statut\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Vous devez fournir un identifiant Discord valide\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Pays dans Découvrir\",\n  \"components.RequestList.RequestItem.removearr\": \"Supprimer de {arr}\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Afficher les plateformes de streaming selon la disponibilité par pays\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Afficher les plateformes de streaming selon la disponibilité par pays\",\n  \"components.RequestList.sortDirection\": \"Inverser la direction du tri\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Avatars des utilisateurs\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filtrer le contenu selon la disponibilité par pays\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Pays de streaming\",\n  \"components.Settings.apiKey\": \"Clé API\",\n  \"components.Settings.scanbackground\": \"L'analyse s'exécutera en arrière-plan. Vous pouvez poursuivre la configuration en attendant.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Pays dans Découvrir\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Filtrer le contenu selon la disponibilité par pays\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Pays de streaming\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Cet email est déjà pris !\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Quelqu'un d'autre possède déjà ce nom d'utilisateur. Vous devez utiliser une adresse e-mail\",\n  \"i18n.specials\": \"Hors-série\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"Identifiant du rôle à mentionner dans le message du webhook. Laissez ce champ vide pour désactiver les mentions\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Identifiant de rôle de notification\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Rafraîchir le token Plex\",\n  \"components.Settings.tip\": \"Conseil\",\n  \"components.Login.loginwithapp\": \"Se connecter avec {appName}\",\n  \"components.Settings.SettingsNetwork.network\": \"Réseau\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Genres\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"N'activez pas ce paramètre à moins que vous ne compreniez ce que vous faites !\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Choisir le profil de qualité\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Choisir le dossier racine\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Paramètres réseau\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Séries à venir\",\n  \"components.Login.noadminerror\": \"Aucun compte administrateur trouvé sur ce serveur.\",\n  \"components.Login.orsigninwith\": \"Ou se connecter avec\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Mots clés\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Profil de qualité\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Dossier racine\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Choisir le service\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Paramètres\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Sélectionner les tags\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleModal.users\": \"Utilisateurs\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Genre\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Mots clés\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Profil de qualité\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Dossier racine\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Paramètres\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleTile.users\": \"Utilisateurs\",\n  \"components.Settings.SettingsNetwork.docs\": \"documentation\",\n  \"components.Selector.searchUsers\": \"Sélectionner un utilisateur…\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Les paramètres réseau de votre conteneur/système doivent être utilisés à la place de ces paramètres. Consultez la documentation pour plus d'informations.\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Autoriser les demandes d'épisodes spéciaux\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Méthodes de connexion\",\n  \"components.Settings.menuNetwork\": \"Réseau\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Autoriser les utilisateurs à se connecter en utilisant leur compte {mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Saisissez vos informations de connexion à {mediaServerName} pour lier votre compte à {applicationName}.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"ID du fil de discussion\",\n  \"components.Setup.librarieserror\": \"La validation a échoué. Veuillez réactiver les bibliothèques pour continuer.\",\n  \"components.Settings.Notifications.messageThreadId\": \"ID du fil de discussion\",\n  \"components.Settings.overrideRulesDescription\": \"Les règles de contournement vous permettent de spécifier les propriétés qui seront remplacées si une demande correspond à la règle.\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Si votre discussion de groupe prend en charge les fils de discussion, vous pouvez spécifier son identifiant ici\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Au moins une méthode d'authentification doit être sélectionnée.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Ces comptes externes sont liés à votre compte {applicationName}.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Si votre discussion de groupe prend en charge les fils de discussion, vous pouvez spécifier son identifiant ici\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Spécifie les conditions avant d'appliquer les modifications des paramètres. Chaque champ doit être validé pour que les règles s'appliquent (opération ET). Un champ est considéré comme vérifié si l'une de ses propriétés correspond (opération OU).\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Un problème est survenu lors de l'enregistrement des paramètres.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Impossible de se connecter à {mediaServerName} en utilisant vos informations de connexion\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Vous devez fournir un mot de passe\",\n  \"components.Settings.addrule\": \"Nouvelle règle de contournement\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"L'identifiant du fil de discussion doit être un nombre entier positif\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Conditions\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Langues\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Pas de tag.\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Modifier la règle de contournement\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"La règle de contournement a été créée avec succès !\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"La règle de contournement a été mise à jour avec succès !\",\n  \"components.Settings.OverrideRuleModal.service\": \"Service\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Appliquer cette règle au service sélectionné.\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Spécifie les paramètres qui seront modifiés lorsque les conditions ci-dessus sont remplies.\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Conditions\",\n  \"components.Settings.OverrideRuleTile.language\": \"Langue\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Activer la protection CSRF\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Définir l'accès à l'API externe en lecture seule (nécessite HTTPS)\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Forcer la résolution IPv4 en premier\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Forcer Seerr à résoudre d'abord les adresses IPv4 au lieu d'IPv6\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Configurez les paramètres réseau de votre instance Seerr.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Adresses ignorées par le proxy\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Utilisez ',' comme séparateur et '*' comme wildcard pour les sous-domaines\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Contourner le proxy pour les adresses locales\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"Proxy HTTP(S)\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Nom d'hôte du proxy\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Mot de passe du proxy\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Port du proxy\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Utiliser SSL pour le proxy\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Nom d'utilisateur du proxy\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Les paramètres ont été enregistrés avec succès !\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Activer la prise en charge du proxy\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Permettre à Seerr d'enregistrer correctement les adresses IP des clients derrière un proxy\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Vous devez fournir un port valide\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Configurer les méthodes de connexion pour les utilisateurs.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Activer la connexion {mediaServerName}\",\n  \"components.Settings.overrideRules\": \"Règles de contournement\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Ce compte est déjà lié à un utilisateur {applicationName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Une erreur inconnue est survenue\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Mot de passe\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Lien\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Ajout en cours…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Lier le compte {mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Nom d'utilisateur\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Vous devez fournir un nom d'utilisateur\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Impossible de supprimer le compte associé.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Une erreur inconnue est survenue\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"L'identifiant du fil de discussion doit être un nombre entier positif\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Comptes liés\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Vous n'avez pas de comptes externes liés à votre compte.\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Comptes liés\",\n  \"components.Settings.OverrideRuleModal.create\": \"Créer une règle\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Nouvelle règle de contournement\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Vous n'avez pas la permission de modifier les comptes liés de cet utilisateur.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Ce compte est déjà lié à un utilisateur Plex\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Impossible de se connecter à Plex en utilisant vos identifiants\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Sélectionner un fournisseur de métadonnées\",\n  \"components.Discover.FilterSlideover.certification\": \"Classification du contenu\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Aucune option disponible\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"Cache DNS\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"URL de base pour les vidéos YouTube si une instance YouTube auto-hébergée est utilisée.\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Description du problème\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Impossible de lire les certifications\",\n  \"components.Settings.Notifications.embedPoster\": \"Intégrer l'affiche\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Tous les fournisseurs de métadonnées sélectionnés sont opérationnels\",\n  \"components.Settings.providerStatus\": \"Statut du fournisseur de métadonnées\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Erreur lors de la sauvegarde des paramètres de notification Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Vous devez sélectionner au moins un type de notification\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Gérer les variables URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Les variables disponibles sont documentées dans la section \\\"Template variables\\\" des webhooks\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Système d'exploitation\",\n  \"i18n.completed\": \"Terminé\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Vous devez fournir une URL valide\",\n  \"components.Settings.operational\": \"Opérationnel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Supprimer l'abonnement\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Les notifications push Web ont été activées.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Une erreur s'est produite lors de l'activation des notifications push Web.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Abonnement supprimé.\",\n  \"components.Settings.menuMetadataProviders\": \"Métadonnées\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"Le fournisseur TVDB ne fonctionne pas, veuillez sélectionner un autre fournisseur de métadonnées\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Navigateur\",\n  \"components.Settings.clickTest\": \"Cliquez sur le bouton « Test » pour vérifier la connectivité avec les fournisseurs de métadonnées\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"Le fournisseur TMDB ne fonctionne pas, veuillez sélectionner un autre fournisseur de métadonnées\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Notification de test Ntfy envoyée !\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"Recours à IPv4\",\n  \"components.Settings.chooseProvider\": \"Choisissez des fournisseurs de métadonnées pour différents types de contenu\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Classification maximale\",\n  \"components.Selector.CertificationSelector.minRating\": \"Classification minimale\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Sélectionner une certification\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Sélectionner un pays\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Commencez à taper pour rechercher.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Vous devez définir un numéro de priorité\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Activer l'agent\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Intégrer l'affiche\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Mot de passe\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"La notification de test Ntfy n'a pas pu être envoyée.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Envoi de la notification de test Ntfy…\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Authentification par token\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Sujet\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"URL racine du serveur\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Nom d'utilisateur\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Authentification par nom d'utilisateur + mot de passe\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Vous devez fournir un sujet\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Vous devez fournir une URL valide\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Intégrer l'affiche\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Intégrer l'affiche\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Intégrer l'affiche\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Statistiques de cache DNS global\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Ces statistiques sont agrégées à partir de toutes les entrées du cache DNS.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Adresse active\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Âge\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"Cache DNS {hostname} vidé.\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Nom d'hôte\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Échecs\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Vider le cache DNS\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Taux de succès\",\n  \"components.Settings.SettingsJobsCache.size\": \"Taille\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"Cache DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"TTL maximum du cache DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"TTL minimum du cache DNS\",\n  \"components.Settings.connectionTestFailed\": \"Échec du test de connexion\",\n  \"components.Settings.failed\": \"Ne fonctionne pas\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Échec de l'enregistrement des paramètres du fournisseur de métadonnées\",\n  \"components.Settings.general\": \"Général\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} n'est pas un mot-clé TMDB.\",\n  \"components.Settings.metadataProviderSettings\": \"Fournisseurs de métadonnées\",\n  \"components.Settings.metadataSettings\": \"Paramètres du fournisseur de métadonnées\",\n  \"components.Settings.no\": \"Non\",\n  \"components.Settings.nooptions\": \"Aucun résultat.\",\n  \"components.Settings.notTested\": \"Non testé\",\n  \"components.Settings.seriesMetadataProvider\": \"Fournisseurs de métadonnées de séries\",\n  \"components.Settings.settings\": \"Paramètres\",\n  \"components.Settings.starttyping\": \"Commencez à taper pour rechercher.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Désactiver le web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Une erreur s'est produite lors de la désactivation des notifications push Web.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Activer les notifications push Web\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Moteur\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Gérer les appareils\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Vous n'avez aucun abonnement Web Push à afficher.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"type\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Inconnu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Les notifications push Web ont été désactivées.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Les paramètres de la notification Web push n'ont pas été enregistrés.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Les paramètres de la notification Web push ont été enregistrés avec succès !\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Exclure les mots-clés\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Priorité\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Les paramètres de notifications Ntfy ont été sauvegardés !\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"L'URL de notification de test est définie à {testUrl} au lieu de la véritable URL de webhook.\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Échecs\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Masquer les médias disponibles dans les pages de découverte, mais pas dans les résultats de recherche\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"L'URL ne doit pas se terminer par un slash (/)\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"URL YouTube\",\n  \"components.Settings.metadataProviderSelection\": \"Sélection des fournisseurs de métadonnées\",\n  \"components.Settings.searchKeywords\": \"Recherche par mots-clés…\",\n  \"components.Settings.valueRequired\": \"Vous devez fournir une valeur.\",\n  \"components.Settings.yes\": \"Oui\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Créé\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Appareil\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Une erreur s'est produite lors de la suppression de l'abonnement utilisateur.\",\n  \"i18n.deleted\": \"Supprimé\",\n  \"components.Settings.metadataSettingsSaved\": \"Paramètres du fournisseur de métadonnées enregistrés\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Activer la mise en cache des résolutions DNS pour optimiser les performances et éviter les appels API inutiles\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr met en cache les résolutions DNS pour optimiser les performances et éviter des appels API inutiles.\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"Clé d'API copiée dans le presse-papiers.\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Ratées\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Abouties\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Abouties\",\n  \"components.Settings.noSpecialCharacters\": \"La configuration doit être une liste d'identifiants de mots-clés TMDB délimités par des virgules, et ne doit ni commencer ni se terminer par une virgule.\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"N'activez PAS ceci si vous rencontrez des problèmes avec la résolution DNS\",\n  \"components.Settings.animeMetadataProvider\": \"Fournisseur de métadonnées pour les animés\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Tous les {jobScheduleDays, plural, one {jours} other {{jobScheduleDays} jours}}\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"À propos de Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Faites une contribution\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Soutenez Seerr\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Vous devez fournir un TTL maximum valide\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Vous devez fournir un TTL maximum valide\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Abonnement actif\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Impossible de se connecter à {services}. Certaines informations pourraient ne pas être disponibles.\",\n  \"components.RequestList.unableToConnect\": \"Impossible de se connecter à {services}. Certaines informations pourraient ne pas être disponibles.\",\n  \"components.Blocklist.blocklistedby\": \"{date} par {user}\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Rien à copier\",\n  \"i18n.blocklistError\": \"Une erreur s'est produite. Veuillez réessayer.\",\n  \"component.BlocklistBlock.blocklistdate\": \"Date de mise sur liste noire\",\n  \"component.BlocklistBlock.blocklistedby\": \"Mis sur liste noire par\",\n  \"component.BlocklistModal.blocklisting\": \"Mise sur liste noire\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> n’est pas sur liste noire.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Gérer les médias sur liste noire.\",\n  \"components.Blocklist.blocklistdate\": \"date\",\n  \"components.Blocklist.blocklistsettings\": \"Paramètres de la liste noire\",\n  \"components.Blocklist.filterManual\": \"Manuel\",\n  \"components.Blocklist.mediaName\": \"Nom\",\n  \"components.Blocklist.mediaTmdbId\": \"Id tmdb\",\n  \"components.Blocklist.mediaType\": \"Type\",\n  \"components.Blocklist.showAllBlocklisted\": \"Afficher tous les médias sur liste noire\",\n  \"components.Layout.Sidebar.blocklist\": \"Liste noire\",\n  \"components.PermissionEdit.blocklistedItems\": \"Mettre des médias sur liste noire.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Accorder l'autorisation de mettre des médias sur liste noire.\",\n  \"components.PermissionEdit.manageblocklist\": \"Gérer la liste noire\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Accorder l'autorisation de gérer les médias sur liste noire.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Voir les médias sur liste noire.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Accorder l'autorisation de voir les médias sur liste noire.\",\n  \"i18n.blocklist\": \"Liste noire\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Masquer les éléments sur liste noire\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Masquer les éléments sur liste noire de la page « Découvrir » pour tous les utilisateurs disposant de l'autorisation « Gérer la liste noire »\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Envoyer TOUTES les requêtes HTTP/HTTPS sortantes via un serveur proxy (hôte/port). N'active PAS la configuration HTTPS, SSL ou des certificats.\",\n  \"i18n.addToBlocklist\": \"Ajouter à la liste noire\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> est déjà sur liste noire.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> a été ajouté à la liste noire avec succès.\",\n  \"i18n.blocklisted\": \"Sur liste noire\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> a été retiré de la liste noire avec succès.\",\n  \"i18n.removefromBlocklist\": \"Retirer de la liste noire\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Tags bloqués\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Aucune recherche DNS n'a encore été mise en cache.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Traiter les tags bloqués\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Bloquer le contenu avec des tags\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Limiter le contenu bloqué par tag\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"La tâche « Traiter les tags bloqués » bloquera autant de pages dans chaque tri. Des nombres plus élevés créeront une liste de blocage plus précise, mais utiliseront plus d'espace.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Ajouter automatiquement le contenu avec des tags à la liste de blocage en utilisant la tâche « Traiter les tags bloqués »\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Coller la configuration du tag liste de blocage ci-dessous.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Importer la configuration des tags bloqués\",\n  \"components.Settings.blocklistedTagsText\": \"Tags bloqués\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Êtes-vous sûr de vouloir effacer les tags bloqués ?\",\n  \"components.Settings.copyBlocklistedTags\": \"Les tags bloqués ont été copiés dans le presse-papiers.\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Copier la configuration des tags bloqués\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Importer la configuration des tags bloqués\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"Délai d’expiration des requêtes API\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Durée maximale (en secondes) d’attente des réponses des services externes comme Radarr/Sonarr. Définissez 0 pour ne pas appliquer de délai d’expiration.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Vous devez saisir une valeur de délai d’expiration valide\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Surveiller les nouvelles saisons\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Priorité\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"Veuillez indiquer une priorité comprise entre 1 et 5\",\n  \"components.Discover.timeWindowDay\": \"Quotidien\",\n  \"components.Discover.timeWindowWeek\": \"Hebdomadaire\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"En-têtes personnalisés\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Ajouter un en-tête\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Impossible d'utiliser à la fois l'en-tête d'autorisation et un en-tête d'autorisation personnalisé. Veuillez en supprimer un.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Tous les en-têtes doivent avoir un nom et une valeur\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Nom de l'en-tête\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Retirer\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Ajoutez des en-têtes HTTP personnalisés à inclure dans les requêtes du webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Valeur de l'en-tête\"\n}\n"
  },
  {
    "path": "src/i18n/locale/he.json",
    "content": "{\n  \"components.ManageSlideOver.alltime\": \"כל הזמנים\",\n  \"components.Login.validationemailrequired\": \"יש לספק כתובת מייל תקינה\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"קבל התראה כשבעיות שפתחת נפתחות מחדש.\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"ה <code>{appDataPath}</code> אחסון לא הוגדר כראוי. כל המידע יוסר כאשר הקונטיינר יעצור או יותחל מחדש.\",\n  \"components.CollectionDetails.overview\": \"תצוגה כללית\",\n  \"components.CollectionDetails.numberofmovies\": \"{כמות} סרטים\",\n  \"components.CollectionDetails.requestcollection\": \"אוסף בקשות\",\n  \"components.CollectionDetails.requestcollection4k\": \"אוסף בקשות ב4K\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"סרטי {genre}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} סרטים\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} סדרות\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} סרטים\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} סדרות\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} סדרות\",\n  \"components.IssueDetails.commentplaceholder\": \"הוסף תגובה …\",\n  \"components.IssueDetails.comments\": \"תגובות\",\n  \"components.IssueDetails.deleteissue\": \"מחק מקרה\",\n  \"components.IssueDetails.deleteissueconfirm\": \"האם אתה בטוח שאתה רוצה למחוק את המקרה?\",\n  \"components.AirDateBadge.airsrelative\": \"ישודר בעוד {relativeTime}\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"רשימת הצפייה שלך\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"סוגי סרטים\",\n  \"components.Discover.StudioSlider.studios\": \"אולפנים\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"סוגי סדרות\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"סוגי סדרות\",\n  \"components.Discover.recentlyAdded\": \"נוספו לאחרונה\",\n  \"components.Discover.recentrequests\": \"בקשות אחרונות\",\n  \"components.Discover.trending\": \"חמים\",\n  \"components.Discover.upcoming\": \"סרטים שיצאו בקרוב\",\n  \"components.Discover.upcomingmovies\": \"סרטים שיצאו בקרוב\",\n  \"components.Discover.upcomingtv\": \"סדרות שיצאו בקרוב\",\n  \"components.DownloadBlock.estimatedtime\": \"{time} משוער\",\n  \"components.IssueDetails.IssueComment.delete\": \"מחיקת תגובה\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"למחוק את התגובה?\",\n  \"components.IssueDetails.IssueComment.edit\": \"עריכת תגובה\",\n  \"components.IssueDetails.IssueDescription.edit\": \"ערוך תיאור\",\n  \"components.IssueDetails.allepisodes\": \"כל הפרקים\",\n  \"components.IssueDetails.allseasons\": \"כל העונות\",\n  \"components.IssueDetails.closeissue\": \"סגור מקרה\",\n  \"components.IssueDetails.closeissueandcomment\": \"סגור עם תגובה\",\n  \"components.IssueDetails.episode\": \"פרק {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"מקרה\",\n  \"components.IssueDetails.playonplex\": \"הפעל ב-Plex\",\n  \"components.IssueDetails.play4konplex\": \"הפעל 4K ב-Plex\",\n  \"components.IssueDetails.problemepisode\": \"פרק מושפע\",\n  \"components.IssueDetails.toastissuedeleted\": \"מקרה נמחק בהצלחה!\",\n  \"components.IssueList.IssueItem.issuetype\": \"סוג\",\n  \"components.IssueList.IssueItem.opened\": \"נפתח\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} ע\\\"י {user}\",\n  \"components.IssueModal.issueSubtitles\": \"כתוביות\",\n  \"components.IssueModal.issueVideo\": \"וידאו\",\n  \"components.Layout.Sidebar.dashboard\": \"גילוי חדשים\",\n  \"components.Login.signingin\": \"מבצע לוגאין…\",\n  \"components.Login.signinheader\": \"יש להתחבר בכדי להמשיך\",\n  \"components.Login.signinwithoverseerr\": \"שימוש בחשבון {applicationTitle}\",\n  \"components.Login.signinwithplex\": \"שימוש בחשבון Plex\",\n  \"components.ManageSlideOver.downloadstatus\": \"הורדות\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"רשימת צפייה\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"סוגי סרטים\",\n  \"components.Discover.populartv\": \"סדרות פופולריות\",\n  \"components.IssueDetails.IssueComment.postedby\": \"פורסם לפני {relativeTime} ע\\\"י {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"פורסם לפני {relativeTime} ע\\\"י {username} (נערך)\",\n  \"components.IssueDetails.IssueDescription.description\": \"תיאור\",\n  \"components.IssueDetails.openedby\": \"#{issueId} נפתח לפני {relativeTime} ע\\\"י {username}\",\n  \"components.IssueDetails.openin4karr\": \"נפתח ב4K {arr}\",\n  \"components.IssueDetails.openinarr\": \"פתח ב {arr}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"פרק מושפע\",\n  \"components.IssueList.sortAdded\": \"הכי עדכני\",\n  \"components.IssueList.sortModified\": \"עודכן לאחרונה\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"כל הפרקים\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"יש לספק מידע מפורט אודות המקרה שחווית.\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"הגש מקרה\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"כל השפות\",\n  \"components.Layout.Sidebar.requests\": \"בקשות\",\n  \"components.Layout.Sidebar.settings\": \"הגדרות\",\n  \"components.Layout.Sidebar.users\": \"משתמשים\",\n  \"components.Layout.UserDropdown.myprofile\": \"פרופיל\",\n  \"components.Layout.UserDropdown.settings\": \"הגדרות\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr פיתוח\",\n  \"components.AirDateBadge.airedrelative\": \"שודר ב-{relativeTime}\",\n  \"components.Discover.NetworkSlider.networks\": \"רשתות שידור\",\n  \"components.Discover.discover\": \"לגלות\",\n  \"components.Discover.plexwatchlist\": \"רשימת הצפייה שלך\",\n  \"components.Discover.popularmovies\": \"סרטים פופולרים\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"אנא הכנס הודעה\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"מחק מקרה\",\n  \"components.IssueDetails.issuetype\": \"סוג\",\n  \"components.IssueDetails.lastupdated\": \"עודכן לאחרונה\",\n  \"components.IssueDetails.leavecomment\": \"תגובה\",\n  \"components.IssueDetails.nocomments\": \"אין תגובות.\",\n  \"components.IssueDetails.problemseason\": \"עונה מושפעת\",\n  \"components.IssueDetails.reopenissue\": \"פתח בעיה מחדש\",\n  \"components.IssueDetails.reopenissueandcomment\": \"פתח מחדש עם תגובה\",\n  \"components.IssueDetails.season\": \"עונה {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"משהו השתבש בזמן עריכת תיאור המקרה.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"תיאור המקרה נערך בהצלחה!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"משהו השתבש בזמן מחיקת המקרה.\",\n  \"components.IssueDetails.toaststatusupdated\": \"סטאטוס המקרה עודכן בהצלחה!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"משהו השתבש בזמן עדכון סטאטוס המקרה.\",\n  \"components.IssueDetails.unknownissuetype\": \"לא ידוע\",\n  \"components.IssueList.IssueItem.issuestatus\": \"סטטוס\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"לא ידוע\",\n  \"components.IssueList.IssueItem.viewissue\": \"צפה במקרה\",\n  \"components.IssueList.issues\": \"מקרים\",\n  \"components.IssueList.showallissues\": \"הצג את כל המקרים\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"כל העונות\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"פרק {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"תוספות\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"פרק מושפע\",\n  \"components.IssueModal.CreateIssueModal.season\": \"עונה {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"עונה מושפעת\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"משהו השתבש בזמן הגשת מקרה.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"דווח על מקרה\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"מה השתבש?\",\n  \"components.IssueModal.issueAudio\": \"אודיו\",\n  \"components.IssueModal.issueOther\": \"אחר\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"צפה במקרה\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"אנא כתוב תיאור\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"שפת תצוגה\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"חיפוש סרטים וסדרות\",\n  \"components.LanguageSelector.languageServerDefault\": \"ברירת מחדל({language})\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"בקשות סרטים\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"בקשות סדרות\",\n  \"components.Login.forgotpassword\": \"שכחת סיסמה?\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr יציבה\",\n  \"components.Login.email\": \"כתובת מייל\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"מתקדם\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"ניקוי מידע\",\n  \"components.Discover.emptywatchlist\": \"מדיה נוספה לתוך <PlexWatchlistSupportLink>רשימת צפייה</PlexWatchlistSupportLink> תוצג פה.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"דווח מקרה של <strong>{title}</strong> הוגש בהצלחה!\",\n  \"components.Layout.Sidebar.issues\": \"מקרים\",\n  \"components.Layout.UserDropdown.requests\": \"בקשות\",\n  \"components.Layout.UserDropdown.signout\": \"התנתק\",\n  \"components.Layout.VersionStatus.outofdate\": \"לא מעודכן\",\n  \"components.Login.loginerror\": \"משהו השתבש בלוגאין.\",\n  \"components.Login.password\": \"סיסמה\",\n  \"components.Login.signin\": \"התחברות\",\n  \"components.Login.validationpasswordrequired\": \"יש לספק סיסמה\",\n  \"components.Discover.CreateSlider.editSlider\": \"ערוך סליידר\",\n  \"components.Discover.CreateSlider.editfail\": \"נכשלה עריכת סליידר.\",\n  \"components.Discover.CreateSlider.needresults\": \"אתה צריך לפחות תוצאה אחת.\",\n  \"components.Discover.CreateSlider.nooptions\": \"אין תוצאות.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"ספק מזהה ז'אנר TMDB\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"ספק מזהה מילת מפתח TMDB\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"ספק שאילתת חיפוש\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"ספק מזהה סטודיו TMDB\",\n  \"components.Discover.CreateSlider.searchGenres\": \"חפש ז'אנרים…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"חפש מילות מפתח…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"חפש אולפנים…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"שם הסליידר\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"יש לספק ערך.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"יש לספק כותרת.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"סרטים {keywordTitle}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"סרטים\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"פופולריות בסדר עולה\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"פופולריות בסדר יורד\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"תאריך שחרור בסדר עולה\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"תאריך שחרור בסדר יורד\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"כותר (א-ת, A-Z) עולה\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"כותר (ת-א, A-Z) יורד\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"דירוג TMDB בסדר עולה\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"דירוג TMDB בסדר יורד\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"סליידר נמחק בהצלחה.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"שנה נראות\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"הסר\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {פילטר אחד פעיל} other {# פילטרים פעילים}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"סדרה\",\n  \"components.Discover.CreateSlider.addfail\": \"נכשלה יצירת סליידר חדש.\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"פופולריות בסדר עולה\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"פופולריות בסדר יורד\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"כותר (א-ת, A-Z) עולה\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"כותר (א-ת, A-Z) יורד\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"דירוג TMDB בסדר עולה\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"סדרה {keywordTitle}\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {פילטר אחד פעיל} other {# פילטרים פעילים}}\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"נקה פילטרים פעילים\",\n  \"components.Discover.FilterSlideover.filters\": \"פילטרים\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"תאריך שידור ראשון\",\n  \"components.Discover.FilterSlideover.from\": \"מאת\",\n  \"components.Discover.FilterSlideover.keywords\": \"מילות מפתח\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"שפה מקורית\",\n  \"components.Discover.FilterSlideover.ratingText\": \"דירוג בין {minValue} ל {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"תאריך שחרור\",\n  \"components.Discover.FilterSlideover.runtime\": \"זמן ריצה\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"שירותי הזרמה\",\n  \"components.Discover.FilterSlideover.studio\": \"אולפן\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"דירוג משתמש TMDB\",\n  \"components.Discover.CreateSlider.addSlider\": \"הוסף סליידר\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"צור סליידר מותאם\",\n  \"components.Discover.CreateSlider.addsuccess\": \"סליידר חדש נוצר בהצלחה ונשמרו הגדרות התאמה.\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"ספק מזהה רשת TMDB\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"תאריך שידור ראשון בסדר יורד\",\n  \"components.Discover.CreateSlider.starttyping\": \"התחל להקליד כדי לחפש.\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"זמן ריצה בין {minValue} ל {maxValue}\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {פילטר פעיל} other {# פילטרים פעילים}}\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"כשל במחיקת סליידר.\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"תאריך שידור ראשון בסדר עולה\",\n  \"components.Discover.CreateSlider.editsuccess\": \"סליידר נערך ונשמר בהצלחה.\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"דירוג TMDB בסדר יורד\",\n  \"components.Discover.FilterSlideover.genres\": \"ז'אנרים\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"מספר הצבעות משתמשים בTMDB\",\n  \"components.Discover.FilterSlideover.to\": \"בשביל\",\n  \"components.Discover.FilterSlideover.voteCount\": \"מספר הצבעות בין {minValue} ל-{maxValue}\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"מדיה נוספה ל<PlexWatchlistSupportLink>רשימת צפייה ב-Plex</PlexWatchlistSupportLink>ותופיע שם.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"רשימת הצפייה שלך\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"נוספו לאחרונה\",\n  \"components.Discover.createnewslider\": \"יצירת מחוון חדש\",\n  \"components.Discover.customizediscover\": \"התאם אישית את הגילוי\",\n  \"components.Discover.networks\": \"רשתות\",\n  \"components.Discover.resetsuccess\": \"הגדרות הגילוי אופסו בהצלחה.\",\n  \"components.Discover.resettodefault\": \"אופס לברירת מחדל\",\n  \"components.Discover.stopediting\": \"סיים עריכה\",\n  \"components.Discover.studios\": \"אולפנים\",\n  \"components.Discover.tmdbmoviegenre\": \"ז'אנר סרט בTMDB\",\n  \"components.Discover.tmdbmoviekeyword\": \"מילת מפתח של סרט בTMDB\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"רשת צפייה של סרט בTMDB\",\n  \"components.Discover.tmdbnetwork\": \"רשת בTMDB\",\n  \"components.Discover.tmdbsearch\": \"חיפוש בTMDB\",\n  \"components.Discover.tmdbstudio\": \"אולפן בTMDB\",\n  \"components.Discover.tmdbtvgenre\": \"ז'אנר סדרה בTMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"מילת מפתח של סדרה בTMDB\",\n  \"components.Discover.tvgenres\": \"ז'אנרים של סדרות\",\n  \"components.Discover.updatefailed\": \"משהו השתבש במהלך עדכון הגדרות של גילוי.\",\n  \"components.Discover.updatesuccess\": \"הגדרות הגילוי התעדכנו.\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {עונה} other {עונות}}\",\n  \"components.Layout.Sidebar.browsetv\": \"סדרות\",\n  \"components.Layout.UserWarnings.emailRequired\": \"דרושה כתובת מייל.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"דרושה סיסמה.\",\n  \"components.Login.credentialerror\": \"שם המשתמש או הסיסמה שגויים.\",\n  \"components.Login.description\": \"בהתחברות ראשונית ל-{applicationName}, יש להוסיף כתובת מייל.\",\n  \"components.Login.initialsignin\": \"חיבור\",\n  \"components.Login.initialsigningin\": \"מתחבר…\",\n  \"components.Login.save\": \"הוספה\",\n  \"components.Login.saving\": \"מוסיף…\",\n  \"components.Login.title\": \"הוספת מייל\",\n  \"components.Login.username\": \"שם משתמש\",\n  \"components.Login.validationEmailFormat\": \"כתובת מייל שגוייה\",\n  \"components.Login.validationEmailRequired\": \"יש להוסיף מייל\",\n  \"components.Login.validationemailformat\": \"נדרש מייל תקין\",\n  \"components.Login.validationhostrequired\": \"נדרש קישור של {mediaServerName}\",\n  \"components.Login.validationusernamerequired\": \"נדרש שם משתמש\",\n  \"components.ManageSlideOver.manageModalIssues\": \"תקלות פתוחות\",\n  \"components.ManageSlideOver.manageModalMedia\": \"מדיה\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"מדיה ב-4K\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"אין בקשות.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"בקשות\",\n  \"components.ManageSlideOver.manageModalTitle\": \"נהל {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"סמן כזמין באיכות 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"סמן את כל העונות כזמינות\",\n  \"components.ManageSlideOver.markavailable\": \"סמן כזמין\",\n  \"components.ManageSlideOver.movie\": \"סרט\",\n  \"components.ManageSlideOver.openarr\": \"הפעל ב-{arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"הפעל גרסת 4K ב-{arr}\",\n  \"components.ManageSlideOver.opentautulli\": \"הפעל ב-Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"{days, number} ימים עברו\",\n  \"components.ManageSlideOver.playedby\": \"משוחק על ידי\",\n  \"components.ManageSlideOver.removearr\": \"הסר מ-{arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"הסר את איכות 4K מ-{arr}\",\n  \"components.ManageSlideOver.tvshow\": \"סדרה\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"ראה עוד\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"כל השחקנים\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"כל הצוות\",\n  \"components.MovieDetails.budget\": \"תקציב\",\n  \"components.MovieDetails.cast\": \"ליהוק\",\n  \"components.MovieDetails.digitalrelease\": \"מהדורה דיגיטלית\",\n  \"components.MovieDetails.downloadstatus\": \"מצב הורדה\",\n  \"components.MovieDetails.imdbuserscore\": \"דירוג משתמש ב-IMDB\",\n  \"components.MovieDetails.mark4kavailable\": \"סמן כזמין באיכות 4K\",\n  \"components.MovieDetails.markavailable\": \"סמן כזמין\",\n  \"components.MovieDetails.openradarr\": \"הפעל סרט ב-Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"הפעל סרט באיכות 4K ב-Radarr\",\n  \"components.MovieDetails.originallanguage\": \"שפת מקור\",\n  \"components.MovieDetails.originaltitle\": \"השם במקור\",\n  \"components.MovieDetails.overview\": \"סקירה\",\n  \"components.MovieDetails.physicalrelease\": \"מהדורה פיזית\",\n  \"components.MovieDetails.play\": \"הפעל ב-{mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"הפעל באיכות 4K ב-{mediaServerName}\",\n  \"components.MovieDetails.recommendations\": \"המלצות\",\n  \"components.MovieDetails.revenue\": \"רווח\",\n  \"components.MovieDetails.rtaudiencescore\": \"דירוג צופים ב-Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"דירוג ב-Rotten Tomatoes\",\n  \"components.MovieDetails.runtime\": \"{minutes} דקות\",\n  \"components.MovieDetails.showless\": \"הראה פחות\",\n  \"components.MovieDetails.showmore\": \"הראה יותר\",\n  \"components.MovieDetails.streamingproviders\": \"זמין כעת ב\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {אולפן} other {אולפנים}}\",\n  \"components.Discover.moviegenres\": \"ז'אנרים של סרטים\",\n  \"components.Discover.resetfailed\": \"משהו השתבש, מאפס את ההתאמה האישית בגילוי.\",\n  \"components.Discover.resetwarning\": \"מאפס את כל המחוונים, זה ימחק כל מחוון מותאם אישית!\",\n  \"components.Discover.tmdbtvstreamingservices\": \"רשתות צפייה של סדרות בTMDB\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: עונה {seasonNumber} פרק {episodeNumber}\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {פרק} other {פרקים}}\",\n  \"components.Layout.Sidebar.browsemovies\": \"סרטים\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"כתובת מייל אינה תקינה.\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} מאחור\",\n  \"components.Login.signinwithjellyfin\": \"שימוש בחשבון {mediaServerName}\",\n  \"components.Login.validationhostformat\": \"נדרש קישור תקין\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* כל הנתונים שלך ל-{mediaType}, כולל בקשות, ימחקו. אם זה קיים בספרייה של {mediaServerName}, זה יצור אותה מחדש בסריקה הבאה.\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"סמן את כל העונות כזמינות ב-4K\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {הפעל} other {הפעלות}}\",\n  \"components.MovieDetails.managemovie\": \"נהל סרט\",\n  \"components.MovieDetails.overviewunavailable\": \"סקירה לא זמינה.\",\n  \"components.MovieDetails.productioncountries\": \"נוצר ב-{countryCount, plural, one {Country} other {Countries}}\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {תאריך השקה} other {תאריכי השקה}}\",\n  \"components.MovieDetails.reportissue\": \"דווח על תקלה\",\n  \"components.MovieDetails.similar\": \"כותרים דומים\",\n  \"components.Login.emailtooltip\": \"הכתובת אינה צריכה להיות משוייכת ל-{mediaServerName}.\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* הפעולה תסיר את {mediaType} מ-{arr} כולל כל הקבצים.\",\n  \"components.MovieDetails.theatricalrelease\": \"שיחרור מוגבל\",\n  \"components.MovieDetails.tmdbuserscore\": \"דיגור TMDB\",\n  \"components.MovieDetails.viewfullcrew\": \"צפייה בכל הצוות\",\n  \"components.MovieDetails.watchtrailer\": \"נגן טריילר\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"קבלת התראות כאשר משתמשים אחרים מגיבים למקרה.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"קבלת התראות כאשר משתמשים אחרים פותחים את המקרה מחדש.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"קבלת התראות כאשר המקרה נפתר ע״י משתמשים אחרים.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"תגובה למקרה\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"קבלת התראות כאשר מתקבלות תגובות חדשות למקרים.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"מקרה חדש נפתח\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"קבלת התראות כאשר מקרה חדש נפתח.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"מקרה נפתח מחדש\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"קבלת התראות כאשר מקרים נפתחים מחדש.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"פנייה נפתרה\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"קבלת התראות כאשר פניות נפתרות.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"בקשה אושרה אוטומטית\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"קבלת התראות כאשר משתמשים פותחים בקשה חדשה שמאושרת אוטומטית.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"בקשה אושרה\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"שליחת התראות כאשר בקשות מדיה מאושרות אוטומטית.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"בקשה נפתחה אוטומטית\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"שליחת התראות כאשר הבקשה נוצרת אוטומטית עבור מדיה ברשימת הצפייה.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"בקשה זמינה\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"שליחת התראות כאשר ניתן ליצור בקשות מדיה.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"בקשה נדחתה\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"קבלת התראות כאשר בקשות מדיה נדחות.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"עיבוד הבקשה נכשל\",\n  \"components.NotificationTypeSelector.mediarequested\": \"בקשה ממתינה לאישור\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"קבלת התראות כאשר משתמשים פותחים בקשות מדיה שדורשות אישור.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"קבלת התראות כאשר משתמשים אחרים מדווחים על תקלות.\",\n  \"components.PermissionEdit.admin\": \"מנהל\",\n  \"components.PermissionEdit.adminDescription\": \"גישת מנהל מלאה. עוקף את כל ההרשאות שסומנו.\",\n  \"components.PermissionEdit.advancedrequest\": \"בקשות מתקדמות\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"הרשאות לשינוי אפשרויות בקשות מדיה.\",\n  \"components.PermissionEdit.autoapprove\": \"אישור אוטומטי\",\n  \"components.PermissionEdit.autoapprove4k\": \"אישור אוטומטי של 4K\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"אישור אוטומטי סרטי 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"אישור אוטומטי של בקשות לסרטים 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"אישור אוטומטי של סדרות 4K\",\n  \"components.PermissionEdit.autoapproveDescription\": \"אישור אוטומטי של בקשות לסדרות ברזולוציית נמוכה מ-4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"אישור סרטים אוטומטי\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"אישור בקשות סרטים אוטומטי (ללא 4K).\",\n  \"components.PermissionEdit.autoapproveSeries\": \"אישור סדרות אוטומטי\",\n  \"components.PermissionEdit.autorequest\": \"בקשה אוטומטית\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"קבלת התראות כאשר יש כשל בהוספת בקשות מדיה אל Radarr או Sonarr\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"סוגי התראות\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"קבלת התראות כאשר תקלות שדיווחת מקבלות תגובות חדשות.\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"אישור אוטומטי של בקשות מדיה 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"אישור אוטומטי של בקשות לסדרות ברזולוציית 4K.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"אישור בקשות סדרות אוטומטי (ללא 4K).\",\n  \"components.Login.hostname\": \"{mediaServerName} כתובת URL\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"בסיס ה-URL לא יכול להסתיים בסלאש\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> נוסף לרשימת הצפייה בהצלחה!\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"קבלת התראות כאשר משתמשים אחרים מגישים בקשות מדיה חדשות אשר מאושרות אוטומטית.\",\n  \"components.PermissionEdit.createissuesDescription\": \"הענקת גישה לדווח על בעיות מדיה.\",\n  \"components.PermissionEdit.usersDescription\": \"הענקת גישה לניהול משתמשים. משתמשים עם גישה זאת לא יכולים לשנות משתמשים עם הרשאות מנהל או להעניק הרשאות מנהל.\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} לכל {quotaDays} {days}</quotaUnits>\",\n  \"components.RequestBlock.languageprofile\": \"פרופיל שפה\",\n  \"components.RequestList.RequestItem.failedretry\": \"משהו השתבש בעת ניסוי שליחת הבקשה מחדש.\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* סדרה זו היא אנימה.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"ניתן לראות סיכום של מגבלת הבקשות שלך ב<ProfileLink>דף הפרופיל</ProfileLink> שלך.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"ניתן לראות סיכום של מגבלת הבקשות של משתמש זה ב<ProfileLink>דף הפרופיל</ProfileLink> שלו.\",\n  \"components.RequestModal.requestmovies4k\": \"בקשת {count} {count, plural, one {סרט} other {סרטים}} ב-4K\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>רשימת יישום</ApplicationRegistrationLink> בשביל שימוש עם Seerr\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"קבלת התראות כאשר משתמשים אחרים מגישים בקשות מדיה חדשות שדורשות אישור.\",\n  \"components.PermissionEdit.autorequestMovies\": \"בקשת סרטים אוטומטית\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"הענקת גישה לשליחה אוטומטית של סרטים שאינם 4K בעזרת רשימת הצפייה של Plex.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"הענקת גישה לניהול בקשות מדיה. כל הבקשות שנעשות על ידי משתמש עם גישה זאת יאושרו אוטומטית.\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"הענקת גישה לשליחת בקשות לסרטים שאינם 4K.\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"הענקת גישה לצפות בבקשות מדיה שנשלחו על ידי משתמשים אחרים.\",\n  \"components.RequestBlock.lastmodifiedby\": \"שונה לאחרונה על ידי\",\n  \"components.RequestButton.approverequests\": \"אישור {requestCount, plural, one {בקשה} other {{requestCount} בקשות}}\",\n  \"components.RequestCard.failedretry\": \"משהו השתבש בעת ניסוי שליחת הבקשה מחדש.\",\n  \"components.RequestModal.requestCancel\": \"בקשה ל-<strong>{title}</strong> בוטלה.\",\n  \"components.RequestModal.selectseason\": \"בחירת עונה/ות\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"קישור לאיפוס סיסמה יישלח לכתובת המייל שסופקה אם היא קשורה למשתמש תקין.\",\n  \"components.Selector.canceled\": \"בוטל\",\n  \"components.Selector.ended\": \"נגמר\",\n  \"components.Selector.searchStudios\": \"חיפוש אולפנים…\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"יש לספק אסימון יישום\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"הגדרות ההתראות של Slack נכשלו להישמר.\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"יש לספק כתובת URL תקינה\",\n  \"components.Login.back\": \"חזרה\",\n  \"components.PermissionEdit.viewissuesDescription\": \"הענקת גישה לראות בעיות מדיה שדווחו על ידי משתמשים אחרים.\",\n  \"components.RequestButton.viewrequest4k\": \"צפייה בבקשת 4K\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"מותר לך לבקש <strong>{limit}</strong> {type} כל <strong>{days}</strong> ימים.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"על משתמש זה להיות עם לפחות <strong>{seasons}</strong> {seasons, plural, one {בקשת עונה} other {בקשות עונה}} שנותרו כדי לשלוח בקשה עבור סדרה זו.\",\n  \"components.RequestModal.pending4krequest\": \"בקשת 4K ממתינה\",\n  \"components.RequestModal.requestedited\": \"בקשה עבור <strong>{title}</strong> נערכה בהצלחה!\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"הגדרות ההתראות של Gotify נכשלו להישמר.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"שולח התראת בדיקה של Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"<UsersGroupsLink>מזהה המשתמש או הקבוצה</UsersGroupsLink> בעל ה-30 תווים שלך\",\n  \"components.Login.adminerror\": \"יש להשתמש בחשבון מנהל בשביל להתחבר.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"קבלת התראות כאשר הבעיות שדיווחת נפתרות.\",\n  \"components.Discover.FilterSlideover.status\": \"סטטוס\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {עונה} other {עונות}}\",\n  \"components.RequestModal.errorediting\": \"משהו השתבש בזמן עריכת הבקשה.\",\n  \"components.ResetPassword.validationpasswordrequired\": \"יש לספק סיסמה\",\n  \"components.Selector.inProduction\": \"בהפקה\",\n  \"components.Selector.pilot\": \"פרק דוגמה\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"יצירת אסימון מתוך <PushbulletSettingsLink>הגדרות המשתמש</PushbulletSettingsLink> שלך\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"יש לספק אסימון גישה\",\n  \"components.PersonDetails.appearsin\": \"מופעים\",\n  \"components.RequestCard.tmdbid\": \"מזהה TMDB\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"סדרות שיצאו בקרוב\",\n  \"components.Login.enablessl\": \"השתמש ב-SSL\",\n  \"components.Login.invalidurlerror\": \"לא ניתן להתחבר לשרת {mediaServerName}.\",\n  \"components.Login.loginwithapp\": \"התחברות עם {appName}\",\n  \"components.Login.noadminerror\": \"לא נמצא חשבון מנהל בשרת.\",\n  \"components.Login.orsigninwith\": \"או התחברות עם\",\n  \"components.Login.port\": \"פורט\",\n  \"components.Login.servertype\": \"סוג שרת\",\n  \"components.Login.urlBase\": \"בסיס URL\",\n  \"components.Login.validationPortRequired\": \"יש לספק מספר פורט תקין\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"בסיס ה-URL חייב להתחיל בסלאש\",\n  \"components.Login.validationUrlTrailingSlash\": \"ה-URL לא יכול להסתיים בסלאש\",\n  \"components.Login.validationservertyperequired\": \"אנא בחר סוג שרת\",\n  \"components.MovieDetails.addtowatchlist\": \"הוספה לרשימת הצפייה\",\n  \"components.MovieDetails.removefromwatchlist\": \"הסרה מרשימת הצפייה\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> נמחק מרשימת הצפייה בהצלחה!\",\n  \"components.MovieDetails.watchlistError\": \"משהו השתבש. אנא נסה שוב.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"קבלת התראות שבקשות המדיה שלך מאושרות.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"קבלת התראות כאשר בקשות המדיה שלך הופכות לזמינות.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"קבלת התראות כאשר בקשות המדיה שלך נדחות.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"קבלת התראות כאשר בקשות מדיה נכשלות להתווסף ל-Radarr או Sonarr.\",\n  \"components.PermissionEdit.autorequestDescription\": \"הענקת גישה לשליחה אוטומטית של בקשות מדיה שאינה 4K בעזרת רשימת הצפייה של Plex.\",\n  \"components.PermissionEdit.autorequestSeries\": \"בקשת סדרות אוטומטית\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"הענקת גישה לשליחה אוטומטית של סדרות שאינן 4K בעזרת רשימת הצפייה של Plex.\",\n  \"components.PermissionEdit.createissues\": \"דיווח על בעיות\",\n  \"components.PermissionEdit.manageissues\": \"ניהול בעיות\",\n  \"components.PermissionEdit.manageissuesDescription\": \"הענקת גישה לניהול בעיות מדיה.\",\n  \"components.PermissionEdit.managerequests\": \"ניהול בקשות\",\n  \"components.PermissionEdit.request\": \"בקשה\",\n  \"components.PermissionEdit.request4k\": \"בקשת 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"הענקת גישה לשליחת בקשות למדיה 4K.\",\n  \"components.PermissionEdit.request4kMovies\": \"בקשת סרטי 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"הענקת גישה לשליחת בקשות לסרטי 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"הענקת גישה לשליחת בקשות לסדרות 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"בקשת סדרות 4K\",\n  \"components.PermissionEdit.requestDescription\": \"הענקת גישה לשליחת בקשות למדיה שאינה 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"בקשת סרטים\",\n  \"components.PermissionEdit.requestTv\": \"בקשת סדרה\",\n  \"components.PermissionEdit.requestTvDescription\": \"הענקת גישה לשליחת בקשות לסדרות שאינן 4K.\",\n  \"components.PermissionEdit.users\": \"ניהול משתמשים\",\n  \"components.PermissionEdit.viewissues\": \"צפייה בבעיות\",\n  \"components.PermissionEdit.viewrecent\": \"צפייה בנוסף לאחרונה\",\n  \"components.PermissionEdit.viewrecentDescription\": \"הענקת גישה לצפייה ברשימת המדיה שנוספה לאחרונה.\",\n  \"components.PermissionEdit.viewrequests\": \"צפייה בבקשות\",\n  \"components.PermissionEdit.viewwatchlists\": \"צפייה ברשימות הצפייה של {mediaServerName}\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"הענקת גישה לצפות ברשימות הצפייה של משתמשים אחרים ב-{mediaServerName}.\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} לכל {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {עונה} other {עונות}}\",\n  \"components.QuotaSelector.unlimited\": \"אין-סופי\",\n  \"components.RegionSelector.regionDefault\": \"כל האזורים\",\n  \"components.RegionSelector.regionServerDefault\": \"ברירת מחדל ({region})\",\n  \"components.RequestBlock.approve\": \"אישור בקשה\",\n  \"components.RequestBlock.decline\": \"דחיית בקשה\",\n  \"components.RequestBlock.delete\": \"מחיקת בקשה\",\n  \"components.RequestBlock.edit\": \"עריכת בקשה\",\n  \"components.RequestBlock.profilechanged\": \"פרופיל איכות\",\n  \"components.RequestBlock.requestdate\": \"תאריך בקשה\",\n  \"components.RequestBlock.requestedby\": \"התבקש על ידי\",\n  \"components.RequestBlock.requestoverrides\": \"עקיפות בקשה\",\n  \"components.RequestBlock.rootfolder\": \"תיקיית שורש\",\n  \"components.RequestBlock.server\": \"שרת יעד\",\n  \"components.RequestButton.approve4krequests\": \"אישור {requestCount, plural, one {בקשת 4K} other {{requestCount} בקשות 4K}}\",\n  \"components.RequestButton.approverequest\": \"אישור בקשה\",\n  \"components.RequestButton.approverequest4k\": \"אישור בקשת 4K\",\n  \"components.RequestButton.decline4krequests\": \"דחיית {requestCount, plural, one {בקשת 4K} other {{requestCount} בקשות 4K}}\",\n  \"components.RequestButton.declinerequest\": \"דחיית בקשה\",\n  \"components.RequestButton.declinerequest4k\": \"דחיית בקשת 4K\",\n  \"components.RequestButton.declinerequests\": \"דחיית {requestCount, plural, one {בקשה} other {{requestCount} בקשות}}\",\n  \"components.RequestButton.requestmore\": \"בקש/י עוד\",\n  \"components.RequestButton.requestmore4k\": \"בקש/י עוד ב-4K\",\n  \"components.RequestButton.viewrequest\": \"צפייה בבקשה\",\n  \"components.RequestCard.approverequest\": \"אישור בקשה\",\n  \"components.RequestCard.cancelrequest\": \"ביטול בקשה\",\n  \"components.RequestCard.declinerequest\": \"דחיית בקשה\",\n  \"components.RequestCard.deleterequest\": \"מחיקת בקשה\",\n  \"components.RequestCard.editrequest\": \"עריכת בקשה\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} לא נמצא\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {עונה} other {עונות}}\",\n  \"components.RequestCard.tvdbid\": \"מזהה TheTVDB\",\n  \"components.RequestCard.unknowntitle\": \"כותרת לא ידועה\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"ביטול בקשה\",\n  \"components.RequestList.RequestItem.deleterequest\": \"מחיקת בקשה\",\n  \"components.RequestList.RequestItem.editrequest\": \"עריכת בקשה\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} לא נמצא\",\n  \"components.RequestList.RequestItem.modified\": \"שונה\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} על ידי {user}\",\n  \"components.RequestList.RequestItem.profileName\": \"פרופיל\",\n  \"components.RequestList.RequestItem.removearr\": \"הסרה מ-{arr}\",\n  \"components.RequestList.RequestItem.requested\": \"התבקש\",\n  \"components.RequestList.RequestItem.requesteddate\": \"התבקש\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {עונה} other {עונות}}\",\n  \"components.RequestList.RequestItem.tmdbid\": \"מזהה TMDB\",\n  \"components.RequestList.RequestItem.tvdbid\": \"מזהה TheTVDB\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"כותרת לא ידועה\",\n  \"components.RequestList.requests\": \"בקשות\",\n  \"components.RequestList.showallrequests\": \"הצגת כל הבקשות\",\n  \"components.RequestList.sortAdded\": \"הכי עדכני\",\n  \"components.RequestList.sortDirection\": \"החלפת כיוון מיון\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"מתקדם\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (ברירת מחדל)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"שרת יעד\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"פרופיל שפה\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"אין תגים.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"פרופיל איכות\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"בקשה בתור\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"תיקיית שורש\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"בחירת תגים\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"תגים\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"מותר למשתמש זה לבקש <strong>{limit}</strong> {type} כל <strong>{days}</strong> ימים.\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {סרט} other {סרטים}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"אין מספיק בקשות עונות שנותרו\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {בקשה} other {בקשות}} נותרו\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"עליך להיות עם לפחות <strong>{seasons}</strong> {seasons, plural, one {בקשת עונה} other {בקשות עונה}} שנותרו כדי לשלוח בקשה עבור סדרה זו.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"עונה\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {עונה} other {עונות}}\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"לא הצלחנו למצוא התאמה עבור סדרה זו.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"לא הצלחנו להתאים אוטומטית את הסדרה הזו. אנא בחר/י את ההתאמה הנכונה למטה.\",\n  \"components.RequestModal.alreadyrequested\": \"התבקש כבר\",\n  \"components.RequestModal.approve\": \"אישור בקשה\",\n  \"components.RequestModal.autoapproval\": \"אישור אוטומטי\",\n  \"components.RequestModal.cancel\": \"ביטול בקשה\",\n  \"components.RequestModal.edit\": \"עריכת בקשה\",\n  \"components.RequestList.sortModified\": \"עודכן לאחרונה\",\n  \"components.RequestModal.numberofepisodes\": \"# של פרקים\",\n  \"components.RequestModal.pendingapproval\": \"בקשתך מחכה לאישור.\",\n  \"components.RequestModal.pendingrequest\": \"בקשה ממתינה\",\n  \"components.RequestModal.requestApproved\": \"בקשה ל-<strong>{title}</strong> אושרה!\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> התבקשה בהצלחה!\",\n  \"components.RequestModal.requestadmin\": \"בקשה זו תאושר אוטומטית.\",\n  \"components.RequestModal.requestcancelled\": \"בקשה עבור <strong>{title}</strong> בוטלה.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"אוסף בקשות ב-4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"אוסף בקשות\",\n  \"components.RequestModal.requesterror\": \"משהו השתבש בזמן שליחת הבקשה.\",\n  \"components.RequestModal.requestfrom\": \"הבקשה של {username} מחכה לאישור.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"בקשת סרט ב-4K\",\n  \"components.RequestModal.requestmovies\": \"בקשת {count} {count, plural, one {סרט} other {סרטים}}\",\n  \"components.RequestModal.requestmovietitle\": \"בקשת סרט\",\n  \"components.RequestModal.requestseasons\": \"בקשת {seasonCount} {seasonCount, plural, one {עונה} other {עונות}}\",\n  \"components.RequestModal.requestseasons4k\": \"בקשת {seasonCount} {seasonCount, plural, one {עונה} other {עונות}} ב-4K\",\n  \"components.RequestModal.requestseries4ktitle\": \"בקשת סדרה ב-4K\",\n  \"components.RequestModal.requestseriestitle\": \"בקשת סדרה\",\n  \"components.RequestModal.season\": \"עונה\",\n  \"components.RequestModal.seasonnumber\": \"עונה {number}\",\n  \"components.RequestModal.selectmovies\": \"בחירת סרט/ים\",\n  \"components.ResetPassword.confirmpassword\": \"אישור סיסמה\",\n  \"components.ResetPassword.email\": \"כתובת מייל\",\n  \"components.ResetPassword.emailresetlink\": \"קישור לשחזור מייל\",\n  \"components.ResetPassword.gobacklogin\": \"חזרה לדף ההתחברות\",\n  \"components.ResetPassword.password\": \"סיסמה\",\n  \"components.ResetPassword.passwordreset\": \"איפוס סיסמה\",\n  \"components.ResetPassword.resetpassword\": \"איפוס סיסמתך\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"סיסמה אופסה בהצלחה!\",\n  \"components.ResetPassword.validationemailrequired\": \"יש לספק כתובת מייל חוקית\",\n  \"components.ResetPassword.validationpasswordmatch\": \"הסיסמאות חייבות להתאים\",\n  \"components.ResetPassword.validationpasswordminchars\": \"הסיסמה קצרה מדי; צריך להיות מינימום של 8 תווים\",\n  \"components.Search.search\": \"חיפוש\",\n  \"components.Search.searchresults\": \"תוצאות חיפוש\",\n  \"components.Selector.nooptions\": \"אין תוצאות.\",\n  \"components.Selector.planned\": \"מתוכנן\",\n  \"components.Selector.returningSeries\": \"סדרה חוזרת\",\n  \"components.Selector.searchGenres\": \"בחירת ז'נרים…\",\n  \"components.Selector.searchKeywords\": \"חיפוש מילות מפתח…\",\n  \"components.Selector.searchStatus\": \"בחירת סטטוס...\",\n  \"components.Selector.searchUsers\": \"בחירת משתמשים…\",\n  \"components.Selector.showless\": \"הראה פחות\",\n  \"components.Selector.showmore\": \"הראה יותר\",\n  \"components.Selector.starttyping\": \"התחל להזין כדי לחפש.\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"הפעל סוכן\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"הגדרות ההתראות של Gotify נשמרו בהצלחה!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"התראת הבדיקה של Gotify נכשלה להשלח.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"שולח התראת בדיקה של Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"התראת הבדיקה של Gotify נשלחה!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"אסימון גישה\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"הפעל סוכן\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"תג ערוץ\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"הגדרות ההתראות של Pushbullet נכשלו להישמר.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"הגדרות ההתראות של Pushbullet נשמרו בהצלחה!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"התראת הבדיקה של Pushbullet נכשלה להשלח.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"התראת הבדיקה של Pushbullet נשלחה!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"יש לבחור לפחות סוג התראה אחד\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"התראת הבדיקה של Pushover נכשלה להשלח.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"שולח התראת בדיקה של Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"התראת הבדיקה של Pushover נשלחה!\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"מפתח משתמש או קבוצה\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"יש לספק אסימון יישום תקין\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"יש לבחור לפחות סוג התראה אחד\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"יש לספק משתמש או מפתח קבוצה תקין\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"הפעל סוכן\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"הגדרות ההתראות של Slack נשמרו בהצלחה!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"התראת הבדיקה של Slack נכשלה להשלח.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"שולח התראת בדיקה של Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"התראת הבדיקה של Slack נשלחה!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"יש לבחור לפחות סוג התראה אחד\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL של ה-Webhook\",\n  \"components.PersonDetails.alsoknownas\": \"גם ידוע בתור: {names}\",\n  \"components.PersonDetails.ascharacter\": \"בתור {character}\",\n  \"components.PersonDetails.birthdate\": \"נולד/ה ב-{birthdate}\",\n  \"components.PersonDetails.crewmember\": \"צוות\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {יום} other {ימים}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {סרט} other {סרטים}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"סרט\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"אסימון יישום\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"כתובת URL של שרת\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"יש לבחור לפחות סוג התראות אחד\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"יש לספק כתובת URL תקינה\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"על כתובת ה-URL לא להסתיים בסלאש\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"אסימון API של היישום\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"הפעל סוכן\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"ברירת המחדל של המכשיר\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"הגדרות ההתראות של Pushover נכשלו להישמר.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"הגדרות ההתראות של Pushover נשמרו בהצלחה!\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"צליל התראה\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"איפוס לברירת מחדל\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"הפעל סוכן\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"כותרת עליונה של הרשאות\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"מטען JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"מטען JSON התאפס בהצלחה!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"התראת הבדיקה של ה-Webhook נשלחה!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"יש לספק מטען JSON תקין\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"יש לבחור לפחות סוג התראה אחד\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"יש לספק כתובת URL תקינה\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL של ה-Webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"הגדרות ההתראות של ה-Webhook נכשלו להשמר.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"הגדרות ההתראות של ה-Webhook נשמרו בהצלחה!\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"הפעל סוכן\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"התראת הבדיקה של ה-Webhook נכשלה להשלח.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"שולח התראת בדיקה של ה-Webhook…\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"על מנת לקבל התראות אינטרנט, על Seerr להיות מוגש בעזרת HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"תבנית משתנה עזרה\",\n  \"i18n.noresults\": \"אין תוצאות.\",\n  \"i18n.requested\": \"התבקש\",\n  \"i18n.notrequested\": \"לא נתבקש\",\n  \"i18n.open\": \"פתוח\",\n  \"i18n.partiallyavailable\": \"זמין חלקית\",\n  \"i18n.pending\": \"ממתין\",\n  \"i18n.previous\": \"קודם\",\n  \"i18n.processing\": \"מעבד\",\n  \"i18n.request\": \"בקשה\",\n  \"i18n.request4k\": \"בקשה ב-4K\",\n  \"i18n.requesting\": \"מבקש…\",\n  \"i18n.resolved\": \"נפתר\",\n  \"i18n.restartRequired\": \"נדרשת הפעלה מחדש\",\n  \"i18n.resultsperpage\": \"הצג {pageSize} תוצאות בכל דף\",\n  \"i18n.retry\": \"נסה שוב\",\n  \"i18n.retrying\": \"מנסה שוב…\",\n  \"i18n.save\": \"שמירת שינויים\",\n  \"i18n.saving\": \"שומר…\",\n  \"i18n.settings\": \"הגדרות\",\n  \"i18n.showingresults\": \"מציג <strong>{from}</strong> ל-<strong>{to}</strong> מתוך <strong>{total}</strong> תוצאות\",\n  \"i18n.specials\": \"פרקים מיוחדים\",\n  \"i18n.status\": \"סטטוס\",\n  \"i18n.test\": \"בדיקה\",\n  \"i18n.testing\": \"בודק…\",\n  \"i18n.tvshow\": \"סדרה\",\n  \"i18n.tvshows\": \"סדרות\",\n  \"i18n.unavailable\": \"לא זמין\",\n  \"i18n.usersettings\": \"הגדרות משתמש\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"שגיאת שרת פנימית\",\n  \"pages.oops\": \"אופס\",\n  \"pages.pagenotfound\": \"דף לא נמצא\",\n  \"pages.returnHome\": \"חזרה לדף הבית\",\n  \"pages.serviceunavailable\": \"שירות לא זמין\",\n  \"pages.somethingwentwrong\": \"משהו השתבש\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"התראת הבדיקה דרך הרשת נכשלה להשלח.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"הגדרות ההתראות דרך הרשת נשמרו בהצלחה!\",\n  \"components.Settings.SonarrModal.hostname\": \"שם מארח או כתובת IP\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"יש לספק מספר פורט תקין\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"כתובת URL של תמונת הבוט\",\n  \"components.Settings.Notifications.botUsername\": \"שם משתמש של הבוט\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"חתימת הודעות אי-מייל מוצפנות בעזרת <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.RadarrModal.hostname\": \"שם מארח או כתובת IP\",\n  \"components.Settings.Notifications.chatIdTip\": \"התחל שיחה עם הבוט שלך, הוסף <GetIdBotLink>@get_id_bot</GetIdBotLink>, ובצע את הפקודה <code>/my_id</code>\",\n  \"components.Settings.Notifications.encryptionDefault\": \"שימוש ב-STARTTLS אם זמין\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"התראת בדיקה של Discord נשלחה!\",\n  \"components.Settings.validationHostnameRequired\": \"יש לספק שם מארח או כתובת IP תקינה\",\n  \"components.Settings.Notifications.encryptionTip\": \"ברוב המקרים, Implicit TLS משתמש בפורט 465 ו-STARTTLS משתמש בפורט 587\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"יש לספק שם מארח או כתובת IP תקינה\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"שולח התראת בדיקה של Discord…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"התראת הבדיקה של Telegram נכשלה להשלח.\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"יש לספק מזהה צ'אט תקין\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"שם מארח Proxy\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"יש לספק שם מארח או כתובת IP תקינה\",\n  \"components.Settings.hostname\": \"שם מארח או כתובת IP\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"שולח התראת בדיקה דרך הרשת…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"התראת הבדיקה דרך הרשת נשלחה!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"הגדרות ההתראות דרך הרשת נכשלו להשמר.\",\n  \"components.Settings.Notifications.agentenabled\": \"הפעל סוכן\",\n  \"components.Settings.Notifications.authPass\": \"סיסמת SMTP\",\n  \"components.Settings.Notifications.authUser\": \"שם משתמש SMTP\",\n  \"components.Settings.Notifications.botAPI\": \"אסימון הרשאת בוט\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>יצירת בוט</CreateBotLink> לשימוש עם Seerr\",\n  \"components.Settings.Notifications.botUsernameTip\": \"אפשר למשתמשים גם להתחיל שיחה עם הבוט שלך ולהגדיר התראות אישיות\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"הגדרות ההתראות של Discord נכשלו להשמר.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"הגדרות ההתראות של Discord נשמרו בהצלחה!\",\n  \"components.Settings.Notifications.emailsender\": \"כתובת מוען\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"הגדרות התראות ה-Email נכשלו להשמר.\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"הגדרות התראות ה-Email נשמרו בהצלחה!\",\n  \"components.Settings.Notifications.enableMentions\": \"הפעל תיוגים\",\n  \"components.Settings.Notifications.encryption\": \"שיטת הצפנה\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"שימוש ב Implicit TLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"ללא\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"תמיד השתמש ב-STARTTLS\",\n  \"components.Settings.Notifications.pgpPassword\": \"סיסמת PGP\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"מפתח PGP פרטי\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"שליחת התראות ללא קול\",\n  \"components.Settings.Notifications.sendSilently\": \"שליחה בשקט\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"התראת הבדיקה דרך אימייל נכשלה להשלח.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"שולח התראת בדיקה דרך אימייל…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"התראת בדיקה דרך אימייל נשלחה בהצלחה!\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"התראת הבדיקה של Telegram נשלחה!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"שולח התראת בדיקה של Telegram…\",\n  \"components.Settings.Notifications.userEmailRequired\": \"דרוש אימייל משתמש\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"יש לספק סיסמת PGP\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"יש לספק אסימון הרשאת בוט\",\n  \"components.Settings.Notifications.validationEmail\": \"יש לספק כתובת מייל תקינה\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"יש לספק מפתח PGP פרטי תקין\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"יש לספק שם מארח או כתובת IP תקינה\",\n  \"components.Settings.Notifications.validationTypes\": \"יש לבחור לפחות סוג התראות אחד\",\n  \"components.Settings.Notifications.validationUrl\": \"יש לספק כתובת URL תקינה\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL של ה-Webhook\",\n  \"components.Settings.Notifications.chatId\": \"מזהה צ'אט\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.add\": \"\",\n  \"components.Settings.RadarrModal.announced\": \"\",\n  \"components.Settings.RadarrModal.baseUrl\": \"\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"\",\n  \"components.Settings.RadarrModal.createradarr\": \"\",\n  \"components.Settings.RadarrModal.default4kserver\": \"\",\n  \"components.Settings.RadarrModal.defaultserver\": \"\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"\",\n  \"components.Settings.RadarrModal.editradarr\": \"\",\n  \"components.Settings.RadarrModal.enableSearch\": \"\",\n  \"components.Settings.RadarrModal.externalUrl\": \"\",\n  \"components.Settings.RadarrModal.inCinemas\": \"\",\n  \"components.Settings.RadarrModal.loadingTags\": \"\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"\",\n  \"components.Settings.RadarrModal.notagoptions\": \"\",\n  \"components.Settings.RadarrModal.port\": \"\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"\",\n  \"components.Settings.RadarrModal.released\": \"\",\n  \"components.Settings.RadarrModal.rootfolder\": \"\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"\",\n  \"components.Settings.RadarrModal.selecttags\": \"\",\n  \"components.Settings.RadarrModal.server4k\": \"\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"\",\n  \"components.Settings.RadarrModal.tagRequests\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.RadarrModal.tags\": \"\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"\",\n  \"components.Settings.SettingsAbout.about\": \"\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"\",\n  \"components.Settings.SettingsAbout.documentation\": \"\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"\",\n  \"components.Settings.SettingsAbout.outofdate\": \"\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"\",\n  \"components.Settings.SettingsAbout.timezone\": \"\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"\",\n  \"components.Settings.SettingsAbout.uptodate\": \"\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.cache\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.process\": \"\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"\",\n  \"components.Settings.SettingsLogs.extraData\": \"\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"\",\n  \"components.Settings.SettingsLogs.filterError\": \"\",\n  \"components.Settings.SettingsLogs.label\": \"\",\n  \"components.Settings.SettingsLogs.level\": \"\",\n  \"components.Settings.SettingsLogs.logDetails\": \"\",\n  \"components.Settings.SettingsLogs.logs\": \"\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"\",\n  \"components.Settings.SettingsLogs.showall\": \"\",\n  \"components.Settings.SettingsLogs.time\": \"\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"\",\n  \"components.Settings.SettingsMain.apikey\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"\",\n  \"components.Settings.SettingsMain.applicationurl\": \"\",\n  \"components.Settings.SettingsMain.cacheImages\": \"\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.general\": \"\",\n  \"components.Settings.SettingsMain.generalsettings\": \"\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.locale\": \"\",\n  \"components.Settings.SettingsMain.originallanguage\": \"\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"\",\n  \"components.Settings.SettingsUsers.localLogin\": \"\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"\",\n  \"components.Settings.SonarrModal.apiKey\": \"\",\n  \"components.Settings.SonarrModal.baseUrl\": \"\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.createsonarr\": \"\",\n  \"components.Settings.SonarrModal.default4kserver\": \"\",\n  \"components.Settings.SonarrModal.defaultserver\": \"\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.enableSearch\": \"\",\n  \"components.Settings.SonarrModal.externalUrl\": \"\",\n  \"components.Settings.SonarrModal.languageprofile\": \"\",\n  \"components.Settings.SonarrModal.loadingTags\": \"\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"\",\n  \"components.Settings.SonarrModal.notagoptions\": \"\",\n  \"components.Settings.SonarrModal.port\": \"\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"\",\n  \"components.Settings.SonarrModal.rootfolder\": \"\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"\",\n  \"components.Settings.SonarrModal.selecttags\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.server4k\": \"\",\n  \"components.Settings.SonarrModal.servername\": \"\",\n  \"components.Settings.SonarrModal.ssl\": \"\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SonarrModal.tags\": \"\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.addradarr\": \"\",\n  \"components.Settings.address\": \"\",\n  \"components.Settings.addsonarr\": \"\",\n  \"components.Settings.advancedTooltip\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.cancelscan\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.currentlibrary\": \"\",\n  \"components.Settings.default\": \"\",\n  \"components.Settings.default4k\": \"\",\n  \"components.Settings.deleteServer\": \"\",\n  \"components.Settings.deleteserverconfirm\": \"\",\n  \"components.Settings.email\": \"\",\n  \"components.Settings.enablessl\": \"\",\n  \"components.Settings.experimentalTooltip\": \"\",\n  \"components.Settings.externalUrl\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.is4k\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.librariesRemaining\": \"\",\n  \"components.Settings.manualscan\": \"\",\n  \"components.Settings.manualscanDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.mediaTypeMovie\": \"\",\n  \"components.Settings.mediaTypeSeries\": \"\",\n  \"components.Settings.menuAbout\": \"\",\n  \"components.Settings.menuGeneralSettings\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuJobs\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.menuNotifications\": \"\",\n  \"components.Settings.menuPlexSettings\": \"\",\n  \"components.Settings.menuServices\": \"\",\n  \"components.Settings.menuUsers\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noDefault4kServer\": \"\",\n  \"components.Settings.noDefaultNon4kServer\": \"\",\n  \"components.Settings.noDefaultServer\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"\",\n  \"components.Settings.notifications\": \"\",\n  \"components.Settings.notificationsettings\": \"\",\n  \"components.Settings.notrunning\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.plex\": \"\",\n  \"components.Settings.plexlibraries\": \"\",\n  \"components.Settings.plexlibrariesDescription\": \"\",\n  \"components.Settings.plexsettings\": \"\",\n  \"components.Settings.plexsettingsDescription\": \"\",\n  \"components.Settings.port\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.restartrequiredTooltip\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scan\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.scanning\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.serverLocal\": \"\",\n  \"components.Settings.serverRemote\": \"\",\n  \"components.Settings.serverSecure\": \"\",\n  \"components.Settings.serverpreset\": \"\",\n  \"components.Settings.serverpresetLoad\": \"\",\n  \"components.Settings.serverpresetManualMessage\": \"\",\n  \"components.Settings.serverpresetRefreshing\": \"\",\n  \"components.Settings.serviceSettingsDescription\": \"\",\n  \"components.Settings.services\": \"\",\n  \"components.Settings.settingUpPlexDescription\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.sonarrsettings\": \"\",\n  \"components.Settings.ssl\": \"\",\n  \"components.Settings.startscan\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.tautulliApiKey\": \"\",\n  \"components.Settings.tautulliSettings\": \"\",\n  \"components.Settings.tautulliSettingsDescription\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.toastPlexConnecting\": \"\",\n  \"components.Settings.toastPlexConnectingFailure\": \"\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"\",\n  \"components.Settings.toastPlexRefreshFailure\": \"\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.urlBase\": \"\",\n  \"components.Settings.validationApiKey\": \"\",\n  \"components.Settings.validationPortRequired\": \"\",\n  \"components.Settings.validationUrl\": \"\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Settings.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.webAppUrl\": \"\",\n  \"components.Settings.webAppUrlTip\": \"\",\n  \"components.Settings.webhook\": \"\",\n  \"components.Settings.webpush\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.configureservices\": \"\",\n  \"components.Setup.continue\": \"\",\n  \"components.Setup.finish\": \"\",\n  \"components.Setup.finishing\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.setup\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinMessage\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.Setup.welcome\": \"\",\n  \"components.StatusBadge.managemedia\": \"\",\n  \"components.StatusBadge.openinarr\": \"\",\n  \"components.StatusBadge.playonplex\": \"\",\n  \"components.StatusBadge.seasonepisodenumber\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.StatusBadge.status\": \"\",\n  \"components.StatusBadge.status4k\": \"\",\n  \"components.StatusChecker.appUpdated\": \"\",\n  \"components.StatusChecker.appUpdatedDescription\": \"\",\n  \"components.StatusChecker.reloadApp\": \"\",\n  \"components.StatusChecker.restartRequired\": \"\",\n  \"components.StatusChecker.restartRequiredDescription\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.cleardata\": \"\",\n  \"components.TitleCard.mediaerror\": \"\",\n  \"components.TitleCard.tmdbid\": \"\",\n  \"components.TitleCard.tvdbid\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.Season.noepisodes\": \"\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.anime\": \"\",\n  \"components.TvDetails.cast\": \"\",\n  \"components.TvDetails.episodeCount\": \"\",\n  \"components.TvDetails.episodeRuntime\": \"\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"\",\n  \"components.TvDetails.firstAirDate\": \"\",\n  \"components.TvDetails.manageseries\": \"\",\n  \"components.TvDetails.network\": \"\",\n  \"components.TvDetails.nextAirDate\": \"\",\n  \"components.TvDetails.originallanguage\": \"\",\n  \"components.TvDetails.originaltitle\": \"\",\n  \"components.TvDetails.overview\": \"\",\n  \"components.TvDetails.overviewunavailable\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.productioncountries\": \"\",\n  \"components.TvDetails.recommendations\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.reportissue\": \"\",\n  \"components.TvDetails.rtaudiencescore\": \"\",\n  \"components.TvDetails.rtcriticsscore\": \"\",\n  \"components.TvDetails.seasonnumber\": \"\",\n  \"components.TvDetails.seasons\": \"\",\n  \"components.TvDetails.seasonstitle\": \"\",\n  \"components.TvDetails.showtype\": \"\",\n  \"components.TvDetails.similar\": \"\",\n  \"components.TvDetails.status4k\": \"\",\n  \"components.TvDetails.streamingproviders\": \"\",\n  \"components.TvDetails.tmdbuserscore\": \"\",\n  \"components.TvDetails.viewfullcrew\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.TvDetails.watchtrailer\": \"\",\n  \"components.UserList.accounttype\": \"\",\n  \"components.UserList.admin\": \"\",\n  \"components.UserList.autogeneratepassword\": \"\",\n  \"components.UserList.autogeneratepasswordTip\": \"\",\n  \"components.UserList.bulkedit\": \"\",\n  \"components.UserList.create\": \"\",\n  \"components.UserList.created\": \"\",\n  \"components.UserList.createlocaluser\": \"\",\n  \"components.UserList.creating\": \"\",\n  \"components.UserList.deleteconfirm\": \"\",\n  \"components.UserList.deleteuser\": \"\",\n  \"components.UserList.edituser\": \"\",\n  \"components.UserList.email\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importedfromplex\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.importfromplex\": \"\",\n  \"components.UserList.importfromplexerror\": \"\",\n  \"components.UserList.localLoginDisabled\": \"\",\n  \"components.UserList.localuser\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.newplexsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.nouserstoimport\": \"\",\n  \"components.UserList.owner\": \"\",\n  \"components.UserList.password\": \"\",\n  \"components.UserList.passwordinfodescription\": \"\",\n  \"components.UserList.plexuser\": \"\",\n  \"components.UserList.role\": \"\",\n  \"components.UserList.sortCreated\": \"\",\n  \"components.UserList.sortDisplayName\": \"\",\n  \"components.UserList.sortRequests\": \"\",\n  \"components.UserList.totalrequests\": \"\",\n  \"components.UserList.user\": \"\",\n  \"components.UserList.usercreatedfailed\": \"\",\n  \"components.UserList.usercreatedfailedexisting\": \"\",\n  \"components.UserList.usercreatedsuccess\": \"\",\n  \"components.UserList.userdeleted\": \"\",\n  \"components.UserList.userdeleteerror\": \"\",\n  \"components.UserList.userfail\": \"\",\n  \"components.UserList.userlist\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.users\": \"\",\n  \"components.UserList.userssaved\": \"\",\n  \"components.UserList.validationEmail\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserList.validationpasswordminchars\": \"\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"\",\n  \"components.UserProfile.ProfileHeader.profile\": \"\",\n  \"components.UserProfile.ProfileHeader.settings\": \"\",\n  \"components.UserProfile.ProfileHeader.userid\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"components.UserProfile.movierequests\": \"\",\n  \"components.UserProfile.pastdays\": \"\",\n  \"components.UserProfile.plexwatchlist\": \"\",\n  \"components.UserProfile.recentlywatched\": \"\",\n  \"components.UserProfile.recentrequests\": \"\",\n  \"components.UserProfile.requestsperdays\": \"\",\n  \"components.UserProfile.seriesrequest\": \"\",\n  \"components.UserProfile.totalrequests\": \"\",\n  \"components.UserProfile.unlimited\": \"\",\n  \"i18n.advanced\": \"\",\n  \"i18n.all\": \"\",\n  \"i18n.approve\": \"\",\n  \"i18n.approved\": \"\",\n  \"i18n.areyousure\": \"\",\n  \"i18n.available\": \"\",\n  \"i18n.back\": \"\",\n  \"i18n.cancel\": \"\",\n  \"i18n.canceling\": \"\",\n  \"i18n.close\": \"\",\n  \"i18n.collection\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.decline\": \"\",\n  \"i18n.declined\": \"\",\n  \"i18n.delete\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.deleting\": \"\",\n  \"i18n.delimitedlist\": \"\",\n  \"i18n.edit\": \"\",\n  \"i18n.experimental\": \"\",\n  \"i18n.failed\": \"\",\n  \"i18n.import\": \"\",\n  \"i18n.importing\": \"\",\n  \"i18n.loading\": \"\",\n  \"i18n.movie\": \"\",\n  \"i18n.movies\": \"\",\n  \"i18n.next\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.allowselfsigned\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"\",\n  \"components.Settings.Notifications.senderName\": \"\",\n  \"components.Settings.Notifications.smtpHost\": \"\",\n  \"components.Settings.Notifications.smtpPort\": \"\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"\",\n  \"components.Settings.menuLogs\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.RadarrModal.servername\": \"\",\n  \"components.Settings.RadarrModal.ssl\": \"\",\n  \"components.Settings.SettingsAbout.version\": \"\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"\",\n  \"components.Settings.RadarrModal.apiKey\": \"\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"\",\n  \"components.Settings.SonarrModal.editsonarr\": \"\",\n  \"components.Settings.SettingsLogs.message\": \"\",\n  \"components.Settings.toastPlexRefresh\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"\",\n  \"components.UserProfile.emptywatchlist\": \"\",\n  \"components.UserProfile.limit\": \"\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"\",\n  \"components.Settings.SettingsUsers.userSettings\": \"\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"\",\n  \"components.Settings.SettingsUsers.users\": \"\",\n  \"components.Settings.SonarrModal.add\": \"\",\n  \"components.Settings.SonarrModal.animeTags\": \"\",\n  \"components.Settings.activeProfile\": \"\",\n  \"components.Settings.radarrsettings\": \"\",\n  \"i18n.view\": \"\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"\",\n  \"components.Settings.SettingsJobsCache.command\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/hi.json",
    "content": "{\n  \"components.CollectionDetails.numberofmovies\": \"{count} फिल्में\",\n  \"components.CollectionDetails.requestcollection\": \"संग्रह अनुरोध\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} फिल्में\",\n  \"components.CollectionDetails.overview\": \"अवलोकन\",\n  \"components.CollectionDetails.requestcollection4k\": \"4K में संग्रह अनुरोध\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code> वॉल्यूम माउंट ठीक से कॉन्फ़िगर नहीं किया गया था। कंटेनर के बंद होने या फिर से चालू होने पर सारा डेटा साफ़ हो जाएगा।\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} फिल्में\",\n  \"components.AirDateBadge.airedrelative\": \"प्रसारित {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"प्रसारण {relativeTime}\",\n  \"components.Discover.CreateSlider.addSlider\": \"स्लाइडर जोड़ें\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"कस्टम स्लाइडर बनाएँ\",\n  \"components.Discover.CreateSlider.addfail\": \"नया स्लाइडर बनाने में विफल.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"नया स्लाइडर बनाया गया और खोज अनुकूलन सेटिंग्स को सहेजा गया.\",\n  \"components.Discover.CreateSlider.editSlider\": \"स्लाइडर संपादित करें\",\n  \"components.Discover.CreateSlider.editfail\": \"स्लाइडर संपादित करने में विफल।\",\n  \"components.Discover.CreateSlider.editsuccess\": \"संपादित स्लाइडर और सहेजी गई खोज अनुकूलन सेटिंग्स।\",\n  \"components.Discover.CreateSlider.nooptions\": \"कोई परिणाम नहीं।\",\n  \"components.Discover.CreateSlider.needresults\": \"आपके पास कम से कम 1 परिणाम होना चाहिए।\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"एक TMDB शैली आईडी प्रदान करें\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"एक TMDB कीवर्ड आईडी प्रदान करें\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"टीएमडीबी नेटवर्क आईडी प्रदान करें\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"TMDB स्टूडियो आईडी दें\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"एक खोज क्वेरी प्रदान करें\",\n  \"components.Discover.CreateSlider.searchGenres\": \"खोज शैलियां…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"मुख्य शब्द खोजे…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"स्टूडियो खोजें…\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"आपको एक डेटा मान प्रदान करना होगा।\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"आपको एक शीर्षक प्रदान करना होगा।\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} फिल्में\",\n  \"pages.somethingwentwrong\": \"कुछ गलत हो गया\",\n  \"components.Discover.createnewslider\": \"नया स्लाइडर बनाएं\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"स्लाइडर का नाम\",\n  \"components.Discover.CreateSlider.starttyping\": \"खोजने के लिए लिखना प्रारंभ कर रहा है.\",\n  \"components.UserList.importfromplex\": \"Plex उपयोगकर्ता आयात करें\",\n  \"components.UserList.userdeleted\": \"उपयोगकर्ता सफलतापूर्वक हटा दिया गया!\",\n  \"components.UserList.userdeleteerror\": \"उपयोगकर्ता को हटाते समय कुछ गलत हुआ.\",\n  \"components.UserList.sortDisplayName\": \"प्रदर्शित होने वाला नाम\",\n  \"components.UserList.sortRequests\": \"अनुरोध संख्या\",\n  \"components.UserList.user\": \"उपयोगकर्ता\",\n  \"components.UserList.password\": \"पासवर्ड\",\n  \"components.UserList.plexuser\": \"Plex उपयोगकर्ता\",\n  \"components.UserList.email\": \"मेल पता\",\n  \"components.UserList.edituser\": \"उपयोगकर्ता अनुमतियां संपादित करें\",\n  \"components.UserList.importfromplexerror\": \"Plex उपयोगकर्ताओं को आयात करते समय कुछ गलत हुआ.\",\n  \"components.UserList.role\": \"भूमिका\",\n  \"components.UserList.userlist\": \"उपयोगकर्ता सूची\",\n  \"components.UserList.users\": \"उपयोगकर्ता\",\n  \"components.UserList.userssaved\": \"उपयोगकर्ता अनुमतियां सफलतापूर्वक सहेजी गईं!\",\n  \"components.UserList.validationEmail\": \"आपको एक मान्य ईमेल पता प्रदान करना होगा\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"शामिल हुए {joindate}\",\n  \"components.UserList.passwordinfodescription\": \"एप्लिकेशन URL कॉन्फ़िगर करें और स्वचालित पासवर्ड जनरेशन की अनुमति देने के लिए ईमेल सूचनाएं सक्षम करें।\",\n  \"components.UserList.nouserstoimport\": \"आयात करने के लिए कोई Plex उपयोगकर्ता नहीं हैं।\",\n  \"components.UserList.totalrequests\": \"अनुरोध\",\n  \"components.UserList.usercreatedfailed\": \"उपयोगकर्ता बनाते समय कुछ गड़बड़ी हुई.\",\n  \"components.UserList.sortCreated\": \"संलग्न तिथि\",\n  \"components.UserList.validationpasswordminchars\": \"पारण शब्द बहुत छोटा है; कम से कम 8 वर्ण होने चाहिए\",\n  \"components.UserList.localuser\": \"स्थानीय उपयोगकर्ता\",\n  \"components.UserList.owner\": \"स्वामी\",\n  \"components.UserList.usercreatedfailedexisting\": \"प्रदान किया गया ईमेल पता पहले से ही किसी अन्य उपयोगकर्ता द्वारा उपयोग में है।\",\n  \"components.UserList.usercreatedsuccess\": \"उपयोगकर्ता सफलतापूर्वक बनाया गया!\",\n  \"components.UserList.userfail\": \"उपयोगकर्ता अनुमतियां सहेजते समय कोई गड़बड़ी हुई.\",\n  \"components.UserProfile.ProfileHeader.profile\": \"प्रोफ़ाइल देखें\",\n  \"components.UserProfile.ProfileHeader.settings\": \"सेटिंग्स बदलें\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} शृंखला\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} शृंखला\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"फिल्म शैली\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} शृंखला\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} फिल्में\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"स्लाइडर को हटाने में विफल रहा।.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"स्लाइडर सफलतापूर्वक हटाया गया.\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} शृंखला\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"आपकी प्लेक्स वॉचलिस्ट\",\n  \"components.Discover.NetworkSlider.networks\": \"नेटवर्क\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"घटती लोकप्रियता\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"बढ़ती रिलीज की तारीख\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB रेटिंग आरोही\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"दृश्यता टॉगल करें\",\n  \"components.Discover.DiscoverTv.discovertv\": \"शृंखला\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"पहली एयर डेट आरोही\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"पहली एयर डेट अवरोही\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"बढ़ती लोकप्रियता\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"शीर्षक (क-ख-घ) आरोही\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"शीर्षक (क-ख-घ) अवरोही\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB रेटिंग आरोही\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB रेटिंग अवरोही\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"प्लेक्स वॉचलिस्ट\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"सक्रिय फिल्टर साफ़ करें\",\n  \"components.Discover.FilterSlideover.filters\": \"फ़िल्टर\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"पहला एयर डेट\",\n  \"components.Discover.FilterSlideover.genres\": \"शैलियां\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"मूल भाषा\",\n  \"components.Discover.FilterSlideover.ratingText\": \"{minValue} और {maxValue} के बीच रेटिंग्स\",\n  \"components.Discover.FilterSlideover.runtime\": \"रनटाइम\",\n  \"components.Discover.FilterSlideover.studio\": \"स्टुडियो\",\n  \"components.Discover.FilterSlideover.to\": \"तक\",\n  \"pages.serviceunavailable\": \"सेवा अनुपलब्ध है\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"बढ़ती लोकप्रियता\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"शीर्षक (क-ख-घ) अवरोही\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"फिल्में\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB रेटिंग अवरोही\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"घटती रिलीज की तारीख\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"शीर्षक (क-ख-घ) आरोही\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"निकालें\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"घटती लोकप्रियता\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"रिलीज़ की तारीख\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} मिनट का रनटाइम\",\n  \"components.Discover.FilterSlideover.from\": \"से\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"स्ट्रीमिंग सेवाएं\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB उपयोगकर्ता स्कोर\",\n  \"components.Discover.FilterSlideover.keywords\": \"खोजशब्दों\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"फिल्म शैली\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{गिनती, बहुवचन, एक {# सक्रिय फ़िल्टर} अन्य {# सक्रिय फ़िल्टर}}\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{गिनती, बहुवचन, एक {# सक्रिय फ़िल्टर} अन्य {# सक्रिय फ़िल्टर}}\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{गिनती, बहुवचन, एक {# सक्रिय फ़िल्टर} अन्य {# सक्रिय फ़िल्टर}}\",\n  \"components.Discover.networks\": \"नेटवर्क\",\n  \"components.Discover.plexwatchlist\": \"आपकी प्लेक्स वॉचलिस्ट\",\n  \"components.Discover.popularmovies\": \"लोकप्रिय फिल्में\",\n  \"components.Discover.studios\": \"स्टूडियो\",\n  \"components.Discover.tmdbnetwork\": \"TMDB नेटवर्क\",\n  \"components.Discover.tmdbsearch\": \"TMDB खोज\",\n  \"components.Discover.recentlyAdded\": \"हाल ही में जोड़ा गया\",\n  \"components.Discover.recentrequests\": \"हाल के अनुरोध\",\n  \"components.Discover.trending\": \"ट्रेंडिंग\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"श्रृंखला शैलियों\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"श्रृंखला शैलियों\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"हाल ही में जोड़ा गया\",\n  \"components.Discover.StudioSlider.studios\": \"स्टूडियो\",\n  \"components.Discover.customizediscover\": \"डिस्कवर को अनुकूलित करें\",\n  \"components.Discover.emptywatchlist\": \"आपकी <PlexWatchlistSupportLink>Plex वॉचलिस्ट</PlexWatchlistSupportLink> में जोड़ा गया मीडिया यहां दिखाई देगा.\",\n  \"components.Discover.populartv\": \"लोकप्रिय श्रृंखला\",\n  \"components.Discover.resetfailed\": \"खोज अनुकूलन सेटिंग्स को रीसेट करने में कुछ गलत हो गया।\",\n  \"components.Discover.resettodefault\": \"डिफ़ॉल्ट पर रीसेट करें\",\n  \"components.Discover.stopediting\": \"संपादन बंद करो\",\n  \"components.Discover.tmdbmoviegenre\": \"टीएमडीबी मूवी शैली\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB मूवी कीवर्ड\",\n  \"components.Discover.tmdbstudio\": \"TMDB स्टूडियो\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB सीरीज कीवर्ड\",\n  \"components.Discover.tvgenres\": \"श्रृंखला शैलियों\",\n  \"components.Discover.moviegenres\": \"फिल्म शैली\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"आपकी प्लेक्स वॉचलिस्ट\",\n  \"components.Discover.resetwarning\": \"सभी स्लाइडर्स को डिफ़ॉल्ट रूप से रीसेट करें। यह किसी भी कस्टम स्लाइडर को भी हटा देगा!\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB श्रृंखला शैली\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"आपकी <PlexWatchlistSupportLink>Plex वॉचलिस्ट</PlexWatchlistSupportLink> में जोड़ा गया मीडिया यहां दिखाई देगा.\",\n  \"components.Discover.discover\": \"खोज\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"\",\n  \"components.Discover.FilterSlideover.voteCount\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.Discover.resetsuccess\": \"\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"\",\n  \"components.Discover.tmdbtvstreamingservices\": \"\",\n  \"components.Discover.upcoming\": \"\",\n  \"components.Discover.upcomingmovies\": \"\",\n  \"components.Discover.upcomingtv\": \"\",\n  \"components.Discover.updatefailed\": \"\",\n  \"components.Discover.updatesuccess\": \"\",\n  \"components.DownloadBlock.estimatedtime\": \"\",\n  \"components.DownloadBlock.formattedTitle\": \"\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"\",\n  \"components.IssueDetails.IssueComment.delete\": \"\",\n  \"components.IssueDetails.IssueComment.edit\": \"\",\n  \"components.IssueDetails.IssueComment.postedby\": \"\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"\",\n  \"components.IssueDetails.IssueDescription.description\": \"\",\n  \"components.IssueDetails.IssueDescription.edit\": \"\",\n  \"components.IssueDetails.allepisodes\": \"\",\n  \"components.IssueDetails.allseasons\": \"\",\n  \"components.IssueDetails.closeissue\": \"\",\n  \"components.IssueDetails.closeissueandcomment\": \"\",\n  \"components.IssueDetails.commentplaceholder\": \"\",\n  \"components.IssueDetails.comments\": \"\",\n  \"components.IssueDetails.deleteissue\": \"\",\n  \"components.IssueDetails.deleteissueconfirm\": \"\",\n  \"components.IssueDetails.episode\": \"\",\n  \"components.IssueDetails.issuepagetitle\": \"\",\n  \"components.IssueDetails.issuetype\": \"\",\n  \"components.IssueDetails.lastupdated\": \"\",\n  \"components.IssueDetails.leavecomment\": \"\",\n  \"components.IssueDetails.nocomments\": \"\",\n  \"components.IssueDetails.openedby\": \"\",\n  \"components.IssueDetails.openin4karr\": \"\",\n  \"components.IssueDetails.openinarr\": \"\",\n  \"components.IssueDetails.play4konplex\": \"\",\n  \"components.IssueDetails.playonplex\": \"\",\n  \"components.IssueDetails.problemepisode\": \"\",\n  \"components.IssueDetails.problemseason\": \"\",\n  \"components.IssueDetails.reopenissue\": \"\",\n  \"components.IssueDetails.reopenissueandcomment\": \"\",\n  \"components.IssueDetails.season\": \"\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"\",\n  \"components.IssueDetails.toastissuedeleted\": \"\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"\",\n  \"components.IssueDetails.toaststatusupdated\": \"\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"\",\n  \"components.IssueDetails.unknownissuetype\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.IssueList.IssueItem.episodes\": \"\",\n  \"components.IssueList.IssueItem.issuestatus\": \"\",\n  \"components.IssueList.IssueItem.issuetype\": \"\",\n  \"components.IssueList.IssueItem.opened\": \"\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"\",\n  \"components.IssueList.IssueItem.problemepisode\": \"\",\n  \"components.IssueList.IssueItem.seasons\": \"\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"\",\n  \"components.IssueList.IssueItem.viewissue\": \"\",\n  \"components.IssueList.issues\": \"\",\n  \"components.IssueList.showallissues\": \"\",\n  \"components.IssueList.sortAdded\": \"\",\n  \"components.IssueList.sortModified\": \"\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"\",\n  \"components.IssueModal.CreateIssueModal.season\": \"\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"\",\n  \"components.IssueModal.issueAudio\": \"\",\n  \"components.IssueModal.issueOther\": \"\",\n  \"components.IssueModal.issueSubtitles\": \"\",\n  \"components.IssueModal.issueVideo\": \"\",\n  \"components.LanguageSelector.languageServerDefault\": \"\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"\",\n  \"components.Layout.Sidebar.browsemovies\": \"\",\n  \"components.Layout.Sidebar.browsetv\": \"\",\n  \"components.Layout.Sidebar.dashboard\": \"\",\n  \"components.Layout.Sidebar.issues\": \"\",\n  \"components.Layout.Sidebar.requests\": \"\",\n  \"components.Layout.Sidebar.settings\": \"\",\n  \"components.Layout.Sidebar.users\": \"\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"\",\n  \"components.Layout.UserDropdown.myprofile\": \"\",\n  \"components.Layout.UserDropdown.requests\": \"\",\n  \"components.Layout.UserDropdown.settings\": \"\",\n  \"components.Layout.UserDropdown.signout\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"\",\n  \"components.Layout.VersionStatus.outofdate\": \"\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"\",\n  \"components.Layout.VersionStatus.streamstable\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.email\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.forgotpassword\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.password\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signin\": \"\",\n  \"components.Login.signingin\": \"\",\n  \"components.Login.signinheader\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.signinwithoverseerr\": \"\",\n  \"components.Login.signinwithplex\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationemailrequired\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationpasswordrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.alltime\": \"\",\n  \"components.ManageSlideOver.downloadstatus\": \"\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"\",\n  \"components.ManageSlideOver.manageModalIssues\": \"\",\n  \"components.ManageSlideOver.manageModalMedia\": \"\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.manageModalRequests\": \"\",\n  \"components.ManageSlideOver.manageModalTitle\": \"\",\n  \"components.ManageSlideOver.mark4kavailable\": \"\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"\",\n  \"components.ManageSlideOver.markavailable\": \"\",\n  \"components.ManageSlideOver.movie\": \"\",\n  \"components.ManageSlideOver.openarr\": \"\",\n  \"components.ManageSlideOver.openarr4k\": \"\",\n  \"components.ManageSlideOver.opentautulli\": \"\",\n  \"components.ManageSlideOver.pastdays\": \"\",\n  \"components.ManageSlideOver.playedby\": \"\",\n  \"components.ManageSlideOver.plays\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.ManageSlideOver.tvshow\": \"\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.budget\": \"\",\n  \"components.MovieDetails.cast\": \"\",\n  \"components.MovieDetails.digitalrelease\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.imdbuserscore\": \"\",\n  \"components.MovieDetails.managemovie\": \"\",\n  \"components.MovieDetails.mark4kavailable\": \"\",\n  \"components.MovieDetails.markavailable\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.originallanguage\": \"\",\n  \"components.MovieDetails.originaltitle\": \"\",\n  \"components.MovieDetails.overview\": \"\",\n  \"components.MovieDetails.overviewunavailable\": \"\",\n  \"components.MovieDetails.physicalrelease\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.productioncountries\": \"\",\n  \"components.MovieDetails.recommendations\": \"\",\n  \"components.MovieDetails.releasedate\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.reportissue\": \"\",\n  \"components.MovieDetails.revenue\": \"\",\n  \"components.MovieDetails.rtaudiencescore\": \"\",\n  \"components.MovieDetails.rtcriticsscore\": \"\",\n  \"components.MovieDetails.runtime\": \"\",\n  \"components.MovieDetails.showless\": \"\",\n  \"components.MovieDetails.showmore\": \"\",\n  \"components.MovieDetails.similar\": \"\",\n  \"components.MovieDetails.streamingproviders\": \"\",\n  \"components.MovieDetails.studio\": \"\",\n  \"components.MovieDetails.theatricalrelease\": \"\",\n  \"components.MovieDetails.tmdbuserscore\": \"\",\n  \"components.MovieDetails.viewfullcrew\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.MovieDetails.watchtrailer\": \"\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.issuecomment\": \"\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.issuecreated\": \"\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"\",\n  \"components.NotificationTypeSelector.issuereopened\": \"\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.issueresolved\": \"\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediafailed\": \"\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediarequested\": \"\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"\",\n  \"components.PermissionEdit.admin\": \"\",\n  \"components.PermissionEdit.adminDescription\": \"\",\n  \"components.PermissionEdit.advancedrequest\": \"\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"\",\n  \"components.PermissionEdit.autoapprove\": \"\",\n  \"components.PermissionEdit.autoapprove4k\": \"\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"\",\n  \"components.PermissionEdit.autoapproveDescription\": \"\",\n  \"components.PermissionEdit.autoapproveMovies\": \"\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"\",\n  \"components.PermissionEdit.autoapproveSeries\": \"\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"\",\n  \"components.PermissionEdit.autorequest\": \"\",\n  \"components.PermissionEdit.autorequestDescription\": \"\",\n  \"components.PermissionEdit.autorequestMovies\": \"\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"\",\n  \"components.PermissionEdit.autorequestSeries\": \"\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"\",\n  \"components.PermissionEdit.createissues\": \"\",\n  \"components.PermissionEdit.createissuesDescription\": \"\",\n  \"components.PermissionEdit.manageissues\": \"\",\n  \"components.PermissionEdit.manageissuesDescription\": \"\",\n  \"components.PermissionEdit.managerequests\": \"\",\n  \"components.PermissionEdit.managerequestsDescription\": \"\",\n  \"components.PermissionEdit.request\": \"\",\n  \"components.PermissionEdit.request4kDescription\": \"\",\n  \"components.PermissionEdit.request4kMovies\": \"\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"\",\n  \"components.PermissionEdit.request4kTv\": \"\",\n  \"components.PermissionEdit.request4kTvDescription\": \"\",\n  \"components.PermissionEdit.requestDescription\": \"\",\n  \"components.PermissionEdit.requestMovies\": \"\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"\",\n  \"components.PermissionEdit.requestTv\": \"\",\n  \"components.PermissionEdit.requestTvDescription\": \"\",\n  \"components.PermissionEdit.users\": \"\",\n  \"components.PermissionEdit.usersDescription\": \"\",\n  \"components.PermissionEdit.viewissues\": \"\",\n  \"components.PermissionEdit.viewissuesDescription\": \"\",\n  \"components.PermissionEdit.viewrecent\": \"\",\n  \"components.PermissionEdit.viewrecentDescription\": \"\",\n  \"components.PermissionEdit.viewrequests\": \"\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"\",\n  \"components.PermissionEdit.viewwatchlists\": \"\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"\",\n  \"components.PersonDetails.alsoknownas\": \"\",\n  \"components.PersonDetails.appearsin\": \"\",\n  \"components.PersonDetails.ascharacter\": \"\",\n  \"components.PersonDetails.birthdate\": \"\",\n  \"components.PersonDetails.crewmember\": \"\",\n  \"components.PersonDetails.lifespan\": \"\",\n  \"components.QuotaSelector.days\": \"\",\n  \"components.QuotaSelector.movieRequests\": \"\",\n  \"components.QuotaSelector.movies\": \"\",\n  \"components.QuotaSelector.seasons\": \"\",\n  \"components.QuotaSelector.tvRequests\": \"\",\n  \"components.QuotaSelector.unlimited\": \"\",\n  \"components.RegionSelector.regionDefault\": \"\",\n  \"components.RegionSelector.regionServerDefault\": \"\",\n  \"components.RequestBlock.approve\": \"\",\n  \"components.RequestBlock.decline\": \"\",\n  \"components.RequestBlock.delete\": \"\",\n  \"components.RequestBlock.edit\": \"\",\n  \"components.RequestBlock.languageprofile\": \"\",\n  \"components.RequestBlock.lastmodifiedby\": \"\",\n  \"components.RequestBlock.profilechanged\": \"\",\n  \"components.RequestBlock.requestdate\": \"\",\n  \"components.RequestBlock.requestedby\": \"\",\n  \"components.RequestBlock.requestoverrides\": \"\",\n  \"components.RequestBlock.rootfolder\": \"\",\n  \"components.RequestBlock.seasons\": \"\",\n  \"components.RequestBlock.server\": \"\",\n  \"components.RequestButton.approve4krequests\": \"\",\n  \"components.RequestButton.approverequest\": \"\",\n  \"components.RequestButton.approverequest4k\": \"\",\n  \"components.RequestButton.approverequests\": \"\",\n  \"components.RequestButton.decline4krequests\": \"\",\n  \"components.RequestButton.declinerequest\": \"\",\n  \"components.RequestButton.declinerequest4k\": \"\",\n  \"components.RequestButton.declinerequests\": \"\",\n  \"components.RequestButton.requestmore\": \"\",\n  \"components.RequestButton.requestmore4k\": \"\",\n  \"components.RequestButton.viewrequest\": \"\",\n  \"components.RequestButton.viewrequest4k\": \"\",\n  \"components.RequestCard.approverequest\": \"\",\n  \"components.RequestCard.cancelrequest\": \"\",\n  \"components.RequestCard.declinerequest\": \"\",\n  \"components.RequestCard.deleterequest\": \"\",\n  \"components.RequestCard.editrequest\": \"\",\n  \"components.RequestCard.failedretry\": \"\",\n  \"components.RequestCard.mediaerror\": \"\",\n  \"components.RequestCard.seasons\": \"\",\n  \"components.RequestCard.tmdbid\": \"\",\n  \"components.RequestCard.tvdbid\": \"\",\n  \"components.RequestCard.unknowntitle\": \"\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"\",\n  \"components.RequestList.RequestItem.deleterequest\": \"\",\n  \"components.RequestList.RequestItem.editrequest\": \"\",\n  \"components.RequestList.RequestItem.failedretry\": \"\",\n  \"components.RequestList.RequestItem.mediaerror\": \"\",\n  \"components.RequestList.RequestItem.modified\": \"\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.RequestItem.requested\": \"\",\n  \"components.RequestList.RequestItem.requesteddate\": \"\",\n  \"components.RequestList.RequestItem.seasons\": \"\",\n  \"components.RequestList.RequestItem.tmdbid\": \"\",\n  \"components.RequestList.RequestItem.tvdbid\": \"\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"\",\n  \"components.RequestList.requests\": \"\",\n  \"components.RequestList.showallrequests\": \"\",\n  \"components.RequestList.sortAdded\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.RequestList.sortModified\": \"\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"\",\n  \"components.RequestModal.AdvancedRequester.default\": \"\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.season\": \"\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"\",\n  \"components.RequestModal.alreadyrequested\": \"\",\n  \"components.RequestModal.approve\": \"\",\n  \"components.RequestModal.autoapproval\": \"\",\n  \"components.RequestModal.cancel\": \"\",\n  \"components.RequestModal.edit\": \"\",\n  \"components.RequestModal.errorediting\": \"\",\n  \"components.RequestModal.numberofepisodes\": \"\",\n  \"components.RequestModal.pending4krequest\": \"\",\n  \"components.RequestModal.pendingapproval\": \"\",\n  \"components.RequestModal.pendingrequest\": \"\",\n  \"components.RequestModal.requestApproved\": \"\",\n  \"components.RequestModal.requestCancel\": \"\",\n  \"components.RequestModal.requestSuccess\": \"\",\n  \"components.RequestModal.requestadmin\": \"\",\n  \"components.RequestModal.requestcancelled\": \"\",\n  \"components.RequestModal.requestcollection4ktitle\": \"\",\n  \"components.RequestModal.requestcollectiontitle\": \"\",\n  \"components.RequestModal.requestedited\": \"\",\n  \"components.RequestModal.requesterror\": \"\",\n  \"components.RequestModal.requestfrom\": \"\",\n  \"components.RequestModal.requestmovie4ktitle\": \"\",\n  \"components.RequestModal.requestmovies\": \"\",\n  \"components.RequestModal.requestmovies4k\": \"\",\n  \"components.RequestModal.requestmovietitle\": \"\",\n  \"components.RequestModal.requestseasons\": \"\",\n  \"components.RequestModal.requestseasons4k\": \"\",\n  \"components.RequestModal.requestseries4ktitle\": \"\",\n  \"components.RequestModal.requestseriestitle\": \"\",\n  \"components.RequestModal.season\": \"\",\n  \"components.RequestModal.seasonnumber\": \"\",\n  \"components.RequestModal.selectmovies\": \"\",\n  \"components.RequestModal.selectseason\": \"\",\n  \"components.ResetPassword.confirmpassword\": \"\",\n  \"components.ResetPassword.email\": \"\",\n  \"components.ResetPassword.emailresetlink\": \"\",\n  \"components.ResetPassword.gobacklogin\": \"\",\n  \"components.ResetPassword.password\": \"\",\n  \"components.ResetPassword.passwordreset\": \"\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"\",\n  \"components.ResetPassword.resetpassword\": \"\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"\",\n  \"components.ResetPassword.validationemailrequired\": \"\",\n  \"components.ResetPassword.validationpasswordmatch\": \"\",\n  \"components.ResetPassword.validationpasswordminchars\": \"\",\n  \"components.ResetPassword.validationpasswordrequired\": \"\",\n  \"components.Search.search\": \"\",\n  \"components.Search.searchresults\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.nooptions\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchGenres\": \"\",\n  \"components.Selector.searchKeywords\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchStudios\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Selector.showless\": \"\",\n  \"components.Selector.showmore\": \"\",\n  \"components.Selector.starttyping\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.Settings.Notifications.agentenabled\": \"\",\n  \"components.Settings.Notifications.allowselfsigned\": \"\",\n  \"components.Settings.Notifications.authPass\": \"\",\n  \"components.Settings.Notifications.authUser\": \"\",\n  \"components.Settings.Notifications.botAPI\": \"\",\n  \"components.Settings.Notifications.botApiTip\": \"\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"\",\n  \"components.Settings.Notifications.botUsername\": \"\",\n  \"components.Settings.Notifications.botUsernameTip\": \"\",\n  \"components.Settings.Notifications.chatId\": \"\",\n  \"components.Settings.Notifications.chatIdTip\": \"\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"\",\n  \"components.Settings.Notifications.emailsender\": \"\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.enableMentions\": \"\",\n  \"components.Settings.Notifications.encryption\": \"\",\n  \"components.Settings.Notifications.encryptionDefault\": \"\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"\",\n  \"components.Settings.Notifications.encryptionNone\": \"\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"\",\n  \"components.Settings.Notifications.encryptionTip\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.pgpPassword\": \"\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"\",\n  \"components.Settings.Notifications.sendSilently\": \"\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"\",\n  \"components.Settings.Notifications.senderName\": \"\",\n  \"components.Settings.Notifications.smtpHost\": \"\",\n  \"components.Settings.Notifications.smtpPort\": \"\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"\",\n  \"components.Settings.Notifications.validationEmail\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"\",\n  \"components.Settings.Notifications.validationTypes\": \"\",\n  \"components.Settings.Notifications.validationUrl\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.Notifications.webhookUrl\": \"\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.add\": \"\",\n  \"components.Settings.RadarrModal.announced\": \"\",\n  \"components.Settings.RadarrModal.apiKey\": \"\",\n  \"components.Settings.RadarrModal.baseUrl\": \"\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"\",\n  \"components.Settings.RadarrModal.createradarr\": \"\",\n  \"components.Settings.RadarrModal.default4kserver\": \"\",\n  \"components.Settings.RadarrModal.defaultserver\": \"\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"\",\n  \"components.Settings.RadarrModal.editradarr\": \"\",\n  \"components.Settings.RadarrModal.enableSearch\": \"\",\n  \"components.Settings.RadarrModal.externalUrl\": \"\",\n  \"components.Settings.RadarrModal.hostname\": \"\",\n  \"components.Settings.RadarrModal.inCinemas\": \"\",\n  \"components.Settings.RadarrModal.loadingTags\": \"\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"\",\n  \"components.Settings.RadarrModal.notagoptions\": \"\",\n  \"components.Settings.RadarrModal.port\": \"\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"\",\n  \"components.Settings.RadarrModal.released\": \"\",\n  \"components.Settings.RadarrModal.rootfolder\": \"\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"\",\n  \"components.Settings.RadarrModal.selecttags\": \"\",\n  \"components.Settings.RadarrModal.server4k\": \"\",\n  \"components.Settings.RadarrModal.servername\": \"\",\n  \"components.Settings.RadarrModal.ssl\": \"\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"\",\n  \"components.Settings.RadarrModal.tagRequests\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.RadarrModal.tags\": \"\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"\",\n  \"components.Settings.SettingsAbout.about\": \"\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"\",\n  \"components.Settings.SettingsAbout.documentation\": \"\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"\",\n  \"components.Settings.SettingsAbout.outofdate\": \"\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"\",\n  \"components.Settings.SettingsAbout.timezone\": \"\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"\",\n  \"components.Settings.SettingsAbout.uptodate\": \"\",\n  \"components.Settings.SettingsAbout.version\": \"\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.cache\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"\",\n  \"components.Settings.SettingsJobsCache.command\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.process\": \"\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"\",\n  \"components.Settings.SettingsLogs.extraData\": \"\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"\",\n  \"components.Settings.SettingsLogs.filterError\": \"\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"\",\n  \"components.Settings.SettingsLogs.label\": \"\",\n  \"components.Settings.SettingsLogs.level\": \"\",\n  \"components.Settings.SettingsLogs.logDetails\": \"\",\n  \"components.Settings.SettingsLogs.logs\": \"\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"\",\n  \"components.Settings.SettingsLogs.message\": \"\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"\",\n  \"components.Settings.SettingsLogs.showall\": \"\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"\",\n  \"components.Settings.SettingsMain.apikey\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"\",\n  \"components.Settings.SettingsMain.applicationurl\": \"\",\n  \"components.Settings.SettingsMain.cacheImages\": \"\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.general\": \"\",\n  \"components.Settings.SettingsMain.generalsettings\": \"\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.locale\": \"\",\n  \"components.Settings.SettingsMain.originallanguage\": \"\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"\",\n  \"components.Settings.SettingsUsers.localLogin\": \"\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.userSettings\": \"\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"\",\n  \"components.Settings.SettingsUsers.users\": \"\",\n  \"components.Settings.SonarrModal.add\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.animeTags\": \"\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"\",\n  \"components.Settings.SonarrModal.apiKey\": \"\",\n  \"components.Settings.SonarrModal.baseUrl\": \"\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.createsonarr\": \"\",\n  \"components.Settings.SonarrModal.default4kserver\": \"\",\n  \"components.Settings.SonarrModal.defaultserver\": \"\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.editsonarr\": \"\",\n  \"components.Settings.SonarrModal.enableSearch\": \"\",\n  \"components.Settings.SonarrModal.externalUrl\": \"\",\n  \"components.Settings.SonarrModal.hostname\": \"\",\n  \"components.Settings.SonarrModal.languageprofile\": \"\",\n  \"components.Settings.SonarrModal.loadingTags\": \"\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"\",\n  \"components.Settings.SonarrModal.notagoptions\": \"\",\n  \"components.Settings.SonarrModal.port\": \"\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"\",\n  \"components.Settings.SonarrModal.rootfolder\": \"\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"\",\n  \"components.Settings.SonarrModal.selecttags\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.server4k\": \"\",\n  \"components.Settings.SonarrModal.servername\": \"\",\n  \"components.Settings.SonarrModal.ssl\": \"\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SonarrModal.tags\": \"\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.activeProfile\": \"\",\n  \"components.Settings.addradarr\": \"\",\n  \"components.Settings.address\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.addsonarr\": \"\",\n  \"components.Settings.advancedTooltip\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.cancelscan\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.currentlibrary\": \"\",\n  \"components.Settings.default\": \"\",\n  \"components.Settings.default4k\": \"\",\n  \"components.Settings.deleteServer\": \"\",\n  \"components.Settings.deleteserverconfirm\": \"\",\n  \"components.Settings.email\": \"\",\n  \"components.Settings.enablessl\": \"\",\n  \"components.Settings.experimentalTooltip\": \"\",\n  \"components.Settings.externalUrl\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.hostname\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.is4k\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.librariesRemaining\": \"\",\n  \"components.Settings.manualscan\": \"\",\n  \"components.Settings.manualscanDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.mediaTypeMovie\": \"\",\n  \"components.Settings.mediaTypeSeries\": \"\",\n  \"components.Settings.menuAbout\": \"\",\n  \"components.Settings.menuGeneralSettings\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuJobs\": \"\",\n  \"components.Settings.menuLogs\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.menuNotifications\": \"\",\n  \"components.Settings.menuPlexSettings\": \"\",\n  \"components.Settings.menuServices\": \"\",\n  \"components.Settings.menuUsers\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noDefault4kServer\": \"\",\n  \"components.Settings.noDefaultNon4kServer\": \"\",\n  \"components.Settings.noDefaultServer\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"\",\n  \"components.Settings.notifications\": \"\",\n  \"components.Settings.notificationsettings\": \"\",\n  \"components.Settings.notrunning\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.plex\": \"\",\n  \"components.Settings.plexlibraries\": \"\",\n  \"components.Settings.plexlibrariesDescription\": \"\",\n  \"components.Settings.plexsettings\": \"\",\n  \"components.Settings.plexsettingsDescription\": \"\",\n  \"components.Settings.port\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.radarrsettings\": \"\",\n  \"components.Settings.restartrequiredTooltip\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scan\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.scanning\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.serverLocal\": \"\",\n  \"components.Settings.serverRemote\": \"\",\n  \"components.Settings.serverSecure\": \"\",\n  \"components.Settings.serverpreset\": \"\",\n  \"components.Settings.serverpresetLoad\": \"\",\n  \"components.Settings.serverpresetManualMessage\": \"\",\n  \"components.Settings.serverpresetRefreshing\": \"\",\n  \"components.Settings.serviceSettingsDescription\": \"\",\n  \"components.Settings.services\": \"\",\n  \"components.Settings.settingUpPlexDescription\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.sonarrsettings\": \"\",\n  \"components.Settings.ssl\": \"\",\n  \"components.Settings.startscan\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.tautulliApiKey\": \"\",\n  \"components.Settings.tautulliSettings\": \"\",\n  \"components.Settings.tautulliSettingsDescription\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.toastPlexConnecting\": \"\",\n  \"components.Settings.toastPlexConnectingFailure\": \"\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"\",\n  \"components.Settings.toastPlexRefresh\": \"\",\n  \"components.Settings.toastPlexRefreshFailure\": \"\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.urlBase\": \"\",\n  \"components.Settings.validationApiKey\": \"\",\n  \"components.Settings.validationHostnameRequired\": \"\",\n  \"components.Settings.validationPortRequired\": \"\",\n  \"components.Settings.validationUrl\": \"\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Settings.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.webAppUrl\": \"\",\n  \"components.Settings.webAppUrlTip\": \"\",\n  \"components.Settings.webhook\": \"\",\n  \"components.Settings.webpush\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.configureservices\": \"\",\n  \"components.Setup.continue\": \"\",\n  \"components.Setup.finish\": \"\",\n  \"components.Setup.finishing\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.setup\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinMessage\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.Setup.welcome\": \"\",\n  \"components.StatusBadge.managemedia\": \"\",\n  \"components.StatusBadge.openinarr\": \"\",\n  \"components.StatusBadge.playonplex\": \"\",\n  \"components.StatusBadge.seasonepisodenumber\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.StatusBadge.status\": \"\",\n  \"components.StatusBadge.status4k\": \"\",\n  \"components.StatusChecker.appUpdated\": \"\",\n  \"components.StatusChecker.appUpdatedDescription\": \"\",\n  \"components.StatusChecker.reloadApp\": \"\",\n  \"components.StatusChecker.restartRequired\": \"\",\n  \"components.StatusChecker.restartRequiredDescription\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.cleardata\": \"\",\n  \"components.TitleCard.mediaerror\": \"\",\n  \"components.TitleCard.tvdbid\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.Season.noepisodes\": \"\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.anime\": \"\",\n  \"components.TvDetails.cast\": \"\",\n  \"components.TvDetails.episodeCount\": \"\",\n  \"components.TvDetails.episodeRuntime\": \"\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"\",\n  \"components.TvDetails.firstAirDate\": \"\",\n  \"components.TvDetails.manageseries\": \"\",\n  \"components.TvDetails.network\": \"\",\n  \"components.TvDetails.nextAirDate\": \"\",\n  \"components.TvDetails.originallanguage\": \"\",\n  \"components.TvDetails.originaltitle\": \"\",\n  \"components.TvDetails.overview\": \"\",\n  \"components.TvDetails.overviewunavailable\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.productioncountries\": \"\",\n  \"components.TvDetails.recommendations\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.reportissue\": \"\",\n  \"components.TvDetails.rtaudiencescore\": \"\",\n  \"components.TvDetails.rtcriticsscore\": \"\",\n  \"components.TvDetails.seasonnumber\": \"\",\n  \"components.TvDetails.seasons\": \"\",\n  \"components.TvDetails.seasonstitle\": \"\",\n  \"components.TvDetails.showtype\": \"\",\n  \"components.TvDetails.similar\": \"\",\n  \"components.TvDetails.status4k\": \"\",\n  \"components.TvDetails.streamingproviders\": \"\",\n  \"components.TvDetails.tmdbuserscore\": \"\",\n  \"components.TvDetails.viewfullcrew\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.TvDetails.watchtrailer\": \"\",\n  \"components.UserList.accounttype\": \"\",\n  \"components.UserList.admin\": \"\",\n  \"components.UserList.autogeneratepassword\": \"\",\n  \"components.UserList.autogeneratepasswordTip\": \"\",\n  \"components.UserList.bulkedit\": \"\",\n  \"components.UserList.create\": \"\",\n  \"components.UserList.created\": \"\",\n  \"components.UserList.createlocaluser\": \"\",\n  \"components.UserList.creating\": \"\",\n  \"components.UserList.deleteconfirm\": \"\",\n  \"components.UserList.deleteuser\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importedfromplex\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.localLoginDisabled\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.newplexsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.ProfileHeader.userid\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"\",\n  \"components.UserProfile.emptywatchlist\": \"\",\n  \"components.UserProfile.limit\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"components.UserProfile.movierequests\": \"\",\n  \"components.UserProfile.pastdays\": \"\",\n  \"components.UserProfile.plexwatchlist\": \"\",\n  \"components.UserProfile.recentlywatched\": \"\",\n  \"components.UserProfile.recentrequests\": \"\",\n  \"components.UserProfile.requestsperdays\": \"\",\n  \"components.UserProfile.seriesrequest\": \"\",\n  \"components.UserProfile.totalrequests\": \"\",\n  \"components.UserProfile.unlimited\": \"\",\n  \"i18n.advanced\": \"\",\n  \"i18n.all\": \"\",\n  \"i18n.approve\": \"\",\n  \"i18n.approved\": \"\",\n  \"i18n.areyousure\": \"\",\n  \"i18n.available\": \"\",\n  \"i18n.back\": \"\",\n  \"i18n.cancel\": \"\",\n  \"i18n.canceling\": \"\",\n  \"i18n.close\": \"\",\n  \"i18n.collection\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.decline\": \"\",\n  \"i18n.declined\": \"\",\n  \"i18n.delete\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.deleting\": \"\",\n  \"i18n.delimitedlist\": \"\",\n  \"i18n.edit\": \"\",\n  \"i18n.experimental\": \"\",\n  \"i18n.failed\": \"\",\n  \"i18n.import\": \"\",\n  \"i18n.importing\": \"\",\n  \"i18n.loading\": \"\",\n  \"i18n.movie\": \"\",\n  \"i18n.movies\": \"\",\n  \"i18n.next\": \"\",\n  \"i18n.noresults\": \"\",\n  \"i18n.notrequested\": \"\",\n  \"i18n.open\": \"\",\n  \"i18n.partiallyavailable\": \"\",\n  \"i18n.pending\": \"\",\n  \"i18n.previous\": \"\",\n  \"i18n.processing\": \"\",\n  \"i18n.request\": \"\",\n  \"i18n.request4k\": \"\",\n  \"i18n.requested\": \"\",\n  \"i18n.requesting\": \"\",\n  \"i18n.resolved\": \"\",\n  \"i18n.restartRequired\": \"\",\n  \"i18n.resultsperpage\": \"\",\n  \"i18n.retry\": \"\",\n  \"i18n.retrying\": \"\",\n  \"i18n.save\": \"\",\n  \"i18n.saving\": \"\",\n  \"i18n.settings\": \"\",\n  \"i18n.showingresults\": \"\",\n  \"i18n.specials\": \"\",\n  \"i18n.status\": \"\",\n  \"i18n.test\": \"\",\n  \"i18n.testing\": \"\",\n  \"i18n.tvshow\": \"\",\n  \"i18n.tvshows\": \"\",\n  \"i18n.unavailable\": \"\",\n  \"i18n.usersettings\": \"\",\n  \"i18n.view\": \"\",\n  \"pages.errormessagewithcode\": \"\",\n  \"pages.internalservererror\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.PermissionEdit.request4k\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"\",\n  \"components.Settings.SettingsLogs.time\": \"\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.TitleCard.tmdbid\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"\",\n  \"pages.oops\": \"\",\n  \"pages.pagenotfound\": \"\",\n  \"pages.returnHome\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/hr.json",
    "content": "{\n  \"components.CollectionDetails.numberofmovies\": \"{count} Filmovi\",\n  \"components.CollectionDetails.overview\": \"Pregled\",\n  \"components.CollectionDetails.requestcollection4k\": \"Zahtjev za serijalom u 4K\",\n  \"components.CollectionDetails.requestcollection\": \"Zahtjev za serijalom\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} Filmovi\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Filmovi\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} Serije\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} Filmovi\",\n  \"components.Discover.discover\": \"Otkrivanje\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Serije\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Serije\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Vaš Plex popis za gledanje\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Filmski Žanrovi\",\n  \"components.Discover.StudioSlider.studios\": \"Studio\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Serijski Žanrovi\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Serijski Žanrovi\",\n  \"components.Discover.plexwatchlist\": \"Vaš Plex popis za gledanje\",\n  \"components.Discover.popularmovies\": \"Popularni Filmovi\",\n  \"components.Discover.recentlyAdded\": \"Nedavno Dodano\",\n  \"components.Discover.recentrequests\": \"Nedavni Zahtjevi\",\n  \"components.Discover.trending\": \"Popularno\",\n  \"components.IssueDetails.IssueComment.edit\": \"Uredi Komentar\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Izbriši problem\",\n  \"components.IssueDetails.IssueDescription.description\": \"Opis\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Uredi opis\",\n  \"components.IssueDetails.allepisodes\": \"Sve Epizode\",\n  \"components.IssueDetails.closeissue\": \"Zatvori Problem\",\n  \"components.IssueDetails.closeissueandcomment\": \"Zatvori s komentarom\",\n  \"components.IssueDetails.commentplaceholder\": \"Dodaj komentar…\",\n  \"components.IssueDetails.comments\": \"Komentari\",\n  \"components.IssueDetails.deleteissue\": \"Izbriši problem\",\n  \"components.AirDateBadge.airedrelative\": \"Emitirano {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Emitiranje {relativeTime}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Navedeni <code>{appDataPath}</code> mapirani volumen nije ispravno podešen. Svi podaci će biti izbrisani kada se spremnik (container) zaustavi ili ponovno pokrene.\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex popis za gledanje\",\n  \"components.Discover.emptywatchlist\": \"Filmovi dodani na Vaš <PlexWatchlistSupportLink> popis za gledanje </PlexWatchlistSupportLink> pojaviti će se ovdje.\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Filmski Žanrovi\",\n  \"components.Discover.NetworkSlider.networks\": \"Striming servisi\",\n  \"components.Discover.populartv\": \"Popularne Serije\",\n  \"components.Discover.upcomingtv\": \"Nadolazeće Serije\",\n  \"components.Discover.upcoming\": \"Nadolazeći Filmovi\",\n  \"components.Discover.upcomingmovies\": \"Nadolazeći Filmovi\",\n  \"components.DownloadBlock.estimatedtime\": \"Procijenjeno {time}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Jeste li sigurni da želite izbrisati ovaj komentar?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Izbriši Komentar\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Objavljeno u {relativeTime} od korisnika {username}\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Morate unijeti poruku\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Objavljeno u {relativeTime} od korisnika {username} (Uređeno)\",\n  \"components.IssueDetails.allseasons\": \"Sve Sezone\",\n  \"components.IssueDetails.episode\": \"Epizode {episodeNumber}\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Jeste li sigurni da želite izbrisati ovaj problem?\",\n  \"components.IssueDetails.lastupdated\": \"Zadnje ažurirano\",\n  \"components.IssueDetails.leavecomment\": \"Komentar\",\n  \"components.IssueDetails.nocomments\": \"Bez komentara.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} otvoren u {relativeTime} od korisnka {username}\",\n  \"components.IssueDetails.openin4karr\": \"Otvoren u 4K {arr}\",\n  \"components.IssueDetails.openinarr\": \"Otvoren u {arr}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Nešto nije u redu prilikom uređivanja opisa problema.\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Sve epizode\",\n  \"components.IssueDetails.toastissuedeleted\": \"Problem je uspješno izbrisan!\",\n  \"components.IssueDetails.unknownissuetype\": \"Nepoznato\",\n  \"components.IssueList.issues\": \"Problem\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} od korinika {user}\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Sve sezone\",\n  \"components.IssueModal.issueOther\": \"Ostalo\",\n  \"components.IssueModal.issueAudio\": \"Zvuk\",\n  \"components.IssueModal.issueSubtitles\": \"Podnaslov\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Sezona} other {Sezone}}\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Layout.UserDropdown.requests\": \"Zahtjevi\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr stablina verzija\",\n  \"components.Login.password\": \"Lozinka\",\n  \"components.ManageSlideOver.openarr4k\": \"Otvori 4K u {arr}u\",\n  \"components.ManageSlideOver.pastdays\": \"Proteklih {days, number} dana\",\n  \"components.Login.signinwithplex\": \"Koristite svoj Plex račun\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.Login.validationemailrequired\": \"Morate unijeti valjanu adresu e-pošte\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Zahtjevi\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Ovo će nepovratno ukloniti sve podatke za ovaj {mediaType}, uključujući sve zahtjeve. Ako ova stavka postoji u vašoj {mediaServerName} biblioteci, informacije o medijima ponovno će se stvoriti tijekom sljedećeg skeniranja.\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K Mediji\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Nema zahtjeva.\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Mediji\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Upravljanje {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Označi kao dostupno u 4K\",\n  \"components.MovieDetails.originaltitle\": \"Izvorni naslov\",\n  \"components.MovieDetails.overview\": \"Pregled\",\n  \"components.ManageSlideOver.openarr\": \"Otvori u {arr}u\",\n  \"components.MovieDetails.cast\": \"Glumci\",\n  \"components.MovieDetails.budget\": \"Proračun\",\n  \"components.ManageSlideOver.opentautulli\": \"Otvori u Tautulliju\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Vidi više\",\n  \"components.MovieDetails.markavailable\": \"Označi kao dostupno\",\n  \"components.ManageSlideOver.tvshow\": \"serije\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {Zemlja produkcije} few {Zemlje produkcije} other {Zemlje produkcije}}\",\n  \"components.MovieDetails.managemovie\": \"Upravljaj filmom\",\n  \"components.MovieDetails.overviewunavailable\": \"Pregled nedostupan.\",\n  \"components.MovieDetails.reportissue\": \"Prijavi problem\",\n  \"components.MovieDetails.revenue\": \"Prihod\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes ocjena publike\",\n  \"components.MovieDetails.showless\": \"Prikaži manje\",\n  \"components.MovieDetails.showmore\": \"Prikaži više\",\n  \"components.MovieDetails.similar\": \"Slični naslovi\",\n  \"components.MovieDetails.streamingproviders\": \"Trenutačno se prikacuje na\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Pošaljite obavijest kada problemi dobiju nove komentare.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problem riješen\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problem ponovno otvoren\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Pošalji obavijest kada se problem riješi.\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Pošalji obavijest kada se problem ponovno otvori.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Automatsko odobravanje zahtjeva\",\n  \"components.IssueDetails.issuepagetitle\": \"Problem\",\n  \"components.IssueDetails.issuetype\": \"Vrsta\",\n  \"components.IssueDetails.play4konplex\": \"Reproduciraj u 4K na {mediaServerName}u\",\n  \"components.IssueDetails.playonplex\": \"Reproduciraj na {mediaServerName}u\",\n  \"components.IssueDetails.problemseason\": \"Zahvaćena sezona\",\n  \"components.IssueDetails.problemepisode\": \"Zahvaćena epizoda\",\n  \"components.IssueDetails.reopenissue\": \"Ponovo otvori problem\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Ponovo otvori s komentarom\",\n  \"components.IssueDetails.season\": \"Sezona {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Opis problema je uspješno uređen!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Nešto nije u redu prilikom brisanja problema.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Status problema je uspješno ažuriran!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Nešto nije u redu prilikom ažuriranja statusa problema.\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Status\",\n  \"components.IssueList.IssueItem.issuetype\": \"Vrsta\",\n  \"components.IssueList.IssueItem.opened\": \"Otvoren\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Zahvaćene Epizode\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Nepoznato\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Epizoda} other {Epizode}}\",\n  \"components.IssueList.IssueItem.viewissue\": \"Pogledaj problem\",\n  \"components.IssueList.showallissues\": \"Prikaži sve probleme\",\n  \"components.IssueList.sortAdded\": \"Najnoviji\",\n  \"components.IssueList.sortModified\": \"Zadnje promjene\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Epizoda {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Dodaci\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Zahvaćene epizode\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Zahvaćene sezone\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Navedite detaljno objašnjenje problema na koji ste naišli.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Prijavite problem\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Sezona {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Pošalji problem\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Nešto nije u redu prilikom slanja problema.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Problem prijavljen za <strong>{title}</strong> je uspješno predan!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Pogledaj problem\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Morate unijeti opis\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Što nije u redu?\",\n  \"components.LanguageSelector.languageServerDefault\": \"Default ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Svi jezici\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Jezik prikaza\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Pretražite filmove i TV\",\n  \"components.Layout.Sidebar.dashboard\": \"Otkrivanje\",\n  \"components.Layout.Sidebar.issues\": \"Problemi\",\n  \"components.Layout.Sidebar.requests\": \"Zahtjevi\",\n  \"components.Layout.Sidebar.settings\": \"Postavke\",\n  \"components.Layout.Sidebar.users\": \"Korisnici\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Zahtjevi za serije\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Zahtjevi za filmove\",\n  \"components.Layout.UserDropdown.settings\": \"Postavke\",\n  \"components.Layout.UserDropdown.signout\": \"Odjavi se\",\n  \"components.Layout.VersionStatus.outofdate\": \"Zastarjelo\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Razvoj\",\n  \"components.Login.email\": \"Adresa e-pošte\",\n  \"components.Login.forgotpassword\": \"Zaboravljena lozinka?\",\n  \"components.Login.loginerror\": \"Nešto nije u redu prilikom pokušaja prijave.\",\n  \"components.Login.signin\": \"Prijavite se\",\n  \"components.Login.signingin\": \"Prijava…\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"\",\n  \"components.Login.signinheader\": \"Prijavite se za nastavak\",\n  \"components.Login.signinwithoverseerr\": \"Koristite svoj {applicationTitle} račun\",\n  \"components.Login.validationpasswordrequired\": \"Morate unijeti lozinku\",\n  \"components.ManageSlideOver.alltime\": \"Cijelo vrijeme\",\n  \"components.ManageSlideOver.downloadstatus\": \"Preuzimanja\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Napredna\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Obriši podatke\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Otvoreni problemi\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Označi sve sezone kao dostupne u 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Označi sve sezone kao dostupne\",\n  \"components.ManageSlideOver.markavailable\": \"Označi kao dostupno\",\n  \"components.ManageSlideOver.playedby\": \"Reproducirano od\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, broj}</strong> {playCount, plural, one {reproducirano} other {reproducirano}}\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Glumačka postava\",\n  \"components.MovieDetails.digitalrelease\": \"Digitalno izdanje\",\n  \"components.MovieDetails.mark4kavailable\": \"Označi kao dostupno u 4K\",\n  \"components.MovieDetails.originallanguage\": \"Izvorni jezik\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Filmska postava\",\n  \"components.MovieDetails.physicalrelease\": \"Fizičko izdanje\",\n  \"components.MovieDetails.recommendations\": \"Preporuke\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Datum Izlaska} other {Datumi izlaska}}\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.MovieDetails.runtime\": \"{minutes} minute\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studiji}}\",\n  \"components.MovieDetails.theatricalrelease\": \"Izdanje u kinima\",\n  \"components.MovieDetails.tmdbuserscore\": \"Ocjena korisnika TMDB-a\",\n  \"components.MovieDetails.viewfullcrew\": \"Pogledajte cijelu filmsku postavu\",\n  \"components.MovieDetails.watchtrailer\": \"Pogledajte najavu\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Primite obavijest kada drugi korisnici komentiraju probleme.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Primite obavijest kada problem ponovno otvore drugi korisnici.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Primite obavijest kada drugi korisnici riješe probleme.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Komentiraj problem\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problem prijavljen\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Pošalji obavijest kada se problem prijavi.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Primite obavijest kada problemi koje ste prijavili budu riješeni.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Slanje obavijesti kada medijski zahtjevi postanu dostupni.\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Slanje obavijesti kada su medijski zahtjevi odbijeni.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Zahtjev čeka odobrenje\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Slanje obavijesti kada korisnici pošalju nove medijske zahtjeve koji zahtijevaju odobrenje.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Zahtjev je automatski poslan\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Zahtjev dostupan\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Slanje obavijesti kada se medijski zahtjevi ne uspiju dodati u Radarr ili Sonarr.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Primite obavijest kada problemi koje ste prijavili dobiju nove komentare.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Automatsko odobravanje serija u 4K\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Primite obavijest kada se medijski zahtjevi ne uspiju dodati u Radarr ili Sonarr.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Primite obavijest kada drugi korisnici pošalju nove medijske zahtjeve koji zahtijevaju odobrenje.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Primite obavijest kada drugi korisnici pošalju nove medijske zahtjeve koji se automatski odobravaju.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Primite obavijest kada vaši medijski zahtjevi budu odbijeni.\",\n  \"components.PermissionEdit.adminDescription\": \"Potpuni administratorski pristup. Zaobilazi sve druge provjere dopuštenja.\",\n  \"components.PermissionEdit.advancedrequest\": \"Napredni zahtjevi\",\n  \"components.PermissionEdit.autoapprove4k\": \"Automatsko odobravanje 4K\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Dozvolite automatsko odobravanje zahtjeva za serijale koji nisu u 4K.\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Dozvolite automatsko odobravanje zahtjeva za filmove u 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Dozvolite automatsko odobravanje zahtjeva za serije u 4K.\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {danu} other {danu}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {filmova}}\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Dozvolite automatsko odobravanje zahtjeva za filmove koji nisu u 4K.\",\n  \"components.RequestButton.approve4krequests\": \"Odobriti {requestCount, plural, one {4K Zahtjev} other {{requestCount} 4K Zahtjeve}}\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {filmova}}\",\n  \"components.RequestButton.approverequests\": \"Odobriti {requestCount, plural, one {Zatjev} other {{requestCount} Zahtjeve}}\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {sezona} other {sezone}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Sezona} other {Sezone}}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Sezona} other {Sezone}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Sezona} other {Sezone}}\",\n  \"components.RequestButton.decline4krequests\": \"Odbiti {requestCount, plural, one {4K Zahtjev} other {{requestCount} 4K Zahtjeve}}\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Ovaj korisnik treba imati još barem <strong>{seasons}</strong> {seasons, plural, one {jedan zahtjev za sezonu} other {nekoliko zahtjeva za sezone}} kako bi mogao preadti zahtjev za ovu seriju.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Morate imati još barem <strong>{seasons}</strong> {seasons, plural, one {jedan zahtjev za sezonu} other {nekoliko zahtjeva za sezone}} kako bi mogli preadti zahtjev za ovu seriju.\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {sezona} other {sezona/e}}\",\n  \"components.RequestModal.requestmovies\": \"{count} {count, plural, one {Zahtjev za film} other {Zahtjevi za filmove}}\",\n  \"components.RequestModal.requestmovies4k\": \"{count} {count, plural, one {Zahtjev za film} other {Zahtejvi za filmove}} u 4K\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Slanje obavijesti kada korisnici pošalju novi medijski zahtjev koji se automatski odobrava.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Zahtjev odobren\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Slanje obavijesti kada se medijski zahtjev ručno odobri.\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Primite obavijest kada se automatski pošalje novi medijski zahtjevi za stavke na vašoj Plex listi koju pratite.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Zahtjev je odbijen\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Obrada zahtjeva nije uspjela\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Vrste obavijesti\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Primite obavijest kada drugi korisnici prijave probleme.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Primite obavijest kada se problemi koje ste prijavili ponovno otvore.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Primite obavijest kada vaši zahtjevi za medije budu odobreni.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Primite obavijest kada vaši medijski zahtjevi postanu dostupni.\",\n  \"components.PermissionEdit.admin\": \"Administrator\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Dodajte dozvolu za izmjenu naprednih opcija zahtjeva za medije.\",\n  \"components.PermissionEdit.autoapprove\": \"Automatsko odobravanje\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Automatsko odobravanje 4K filmova\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Dozvolite automatsko odobravanje svih zahtjeva za 4K medije.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Dozvolite automatsko odobravanje svih zahtjeva koji nisu u 4K mediji.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Automatsko odobravanje filmova\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Automatsko odobravanje serija\",\n  \"components.RequestButton.declinerequests\": \"Odbij {requestCount, plural, one {zahtjev} few {{requestCount} zahtjeva} other {{requestCount} zahtjeva}}\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {0} other {<strong>#</strong>}} {type} {remaining, plural, one {zahtjev preostao} few {zahtjeva preostala} other {zahtjeva preostalo}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Aktualna učestalost\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Nova učestalost\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"{jobScheduleHours, plural, one {Svaki sat} few {Svaka {jobScheduleHours} sata} other {Svakih {jobScheduleHours} sati}}\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Dogodila se greška prilikom spremanja zadatka.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Zadatak uspješno promijenjen!\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Sinkronizacija Plex popisa gledanja\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Pokreni sada\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Nepoznat zadatak\",\n  \"components.Settings.SettingsLogs.extraData\": \"Dodatni podaci\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Poruka zapisnika je kopirana u međuspremnik.\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Otklanjanje grešaka\",\n  \"components.Settings.SettingsLogs.filterError\": \"Greška\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Informacije\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Upozorenje\",\n  \"components.Settings.SettingsLogs.label\": \"Etiketa\",\n  \"components.Settings.SettingsLogs.level\": \"Važnost\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Detalji zapisa\",\n  \"components.Settings.SettingsLogs.logs\": \"Zapisi\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Nastavi\",\n  \"components.Settings.SettingsLogs.showall\": \"Prikaži sve zapise\",\n  \"components.Settings.SettingsLogs.time\": \"Vremenska oznaka\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Prikaz detalja\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Zadane dozvole\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Početne dozvole dodijeljene novim korisnicima\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Aktiviraj lokalnu prijavu\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Dozvoli korisnicima da se prijave koristeći svoju e-mail adresu i lozinku, umjesto Plex OAutha\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Globalno ograničenje zahtjeva za filmove\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Korisničke postavke su uspješno spremljene!\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Globalno ograničenje zahtjeva za serije\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Korisničke postavke\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Konfiguriraj globalne i zadane korisničke postavke.\",\n  \"components.Settings.SettingsUsers.users\": \"Korisnici\",\n  \"components.Settings.SonarrModal.add\": \"Dodaj poslužitelj\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime oznake\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime profil jezika\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime profil kvalitete\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime početna mapa\",\n  \"components.Settings.SonarrModal.apiKey\": \"API ključ\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Osnovni URL\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Dodaj novi 4K Sonarr poslužitelj\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Dodaj novi Sonarr poslužitelj\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Zadani 4K poslužitelj\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Zadani poslužitelj\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Uredi 4K Sonarr poslužitelj\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Uredi Sonarr poslužitelj\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Aktiviraj automatsku pretragu\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Eksterni URL\",\n  \"components.Settings.SonarrModal.hostname\": \"Ime računala ili IP adresa\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Profil jezika\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Učitavanje oznaka …\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Učitavanje profila kvalitete …\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Učitavanje početnih mapa …\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Nema oznaka.\",\n  \"components.Settings.SonarrModal.port\": \"Priključak\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Početna mapa\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Profil kvalitete\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Mape za sezone\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Odaberi profil jezika\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Odaberi profil kvalitete\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Odaberi početnu mapu\",\n  \"components.Settings.SonarrModal.selecttags\": \"Odaberi oznake\",\n  \"components.Settings.SonarrModal.server4k\": \"4K poslužitelj\",\n  \"components.Settings.SonarrModal.servername\": \"Ime poslužitelja\",\n  \"components.Settings.SonarrModal.ssl\": \"Koristi SSL\",\n  \"components.Settings.SonarrModal.tags\": \"Oznake\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Provjeri vezu za učitavanje profila kvalitete\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Provjeri vezu za učitavanje početnih mapa\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Provjeri vezu za učitavanje oznaka\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr veza je uspješno uspostavljena!\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Moraš navesti valjani API ključ\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Moraš navesti valjani URL\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Osnovni URL mora početi s kosom crtom\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Osnovni URL ne smije završiti s kosom crtom\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Moraš navesti valjano ime računala ili IP adresu\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Moraš odabrati profil jezika\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Moraš navesti ime poslužitelja\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Moraš navesti valjani broj priključka\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Moraš odabrati profil kvalitete\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Moraš odabrati početnu mapu\",\n  \"components.Settings.activeProfile\": \"Aktivni profil\",\n  \"components.Settings.addradarr\": \"Dodaj Radarr poslužitelj\",\n  \"components.Settings.address\": \"Adresa\",\n  \"components.Settings.addsonarr\": \"Dodaj Sonarr poslužitelj\",\n  \"components.Settings.currentlibrary\": \"Aktualna biblioteka: {name}\",\n  \"components.Settings.default\": \"Zadano\",\n  \"components.Settings.default4k\": \"Zadano 4K\",\n  \"components.Settings.deleteServer\": \"Izbriši {serverType} poslužitelj\",\n  \"components.Settings.deleteserverconfirm\": \"Stvarno želiš izbrisati ovaj poslužitelj?\",\n  \"components.Settings.email\": \"E-mail\",\n  \"components.Settings.enablessl\": \"Koristi SSL\",\n  \"components.Settings.experimentalTooltip\": \"Aktiviranjem ove postavke može doći do neočekivanog ponašanja programa\",\n  \"components.Settings.externalUrl\": \"Eksterni URL\",\n  \"components.Settings.hostname\": \"Ime računala ili IP adresa\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.librariesRemaining\": \"Preostale biblioteke: {count}\",\n  \"components.Settings.menuAbout\": \"Informacije\",\n  \"components.Settings.menuGeneralSettings\": \"Opće\",\n  \"components.Settings.menuJobs\": \"Zadaci i predmemorija\",\n  \"components.Settings.menuLogs\": \"Zapisi\",\n  \"components.Settings.menuNotifications\": \"Obavijesti\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Usluge\",\n  \"components.Settings.menuUsers\": \"Korisnici\",\n  \"components.Settings.noDefault4kServer\": \"4K {serverType} poslužitelj mora biti označen kao zadani kako bi se korisnicima omogućilo slanje zahtjeva za 4K {mediaType}.\",\n  \"components.Settings.noDefaultServer\": \"Barem jedan {serverType} poslužitelj mora biti označen kao zadani kako bi se zahtjevi za {mediaType} mogli obraditi.\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Konfiguriraj i aktiviraj agente obavijesti.\",\n  \"components.Settings.notifications\": \"Obavijesti\",\n  \"components.Settings.notificationsettings\": \"Postavke obavijesti\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.plexlibraries\": \"Plex biblioteke\",\n  \"components.Settings.plexsettings\": \"Plex postavke\",\n  \"components.Settings.plexsettingsDescription\": \"Konfiguriraj postavke za tvoj Plex poslužitelj. Seerr skenira tvoje Plex biblioteke kako bi utvrdio dostupnost sadržaja.\",\n  \"components.Settings.port\": \"Priključak\",\n  \"components.Settings.radarrsettings\": \"Radarr postavke\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr se mora ponovo pokrenuti kako bi promjene ove postavke stupile na snagu\",\n  \"components.Settings.scan\": \"Sinkronizraj biblioteke\",\n  \"components.Settings.scanning\": \"Sinkronizacija …\",\n  \"components.Settings.serverLocal\": \"lokalni\",\n  \"components.Settings.serverSecure\": \"sigurno\",\n  \"components.Settings.serverpreset\": \"Poslužitelj\",\n  \"components.Settings.serverpresetRefreshing\": \"Dohvaćanje poslužitelja …\",\n  \"components.Settings.serviceSettingsDescription\": \"Dolje donfiguriraj svoje {serverType} poslužitelje. Možeš povezati više {serverType} poslužitelja, ali samo dva od njih mogu biti označena kao zadana (jedan ne-4K i jedan 4K). Administratori mogu promijeniti poslužitelj koji se koristi za obradu novih zahtjeva prije odobrenja.\",\n  \"components.Settings.serverpresetLoad\": \"Pritisni gumb za učitavanje dostupnih polsužitelja\",\n  \"components.Settings.serverpresetManualMessage\": \"Ručna konfiguracija\",\n  \"components.Settings.services\": \"Usluge\",\n  \"components.Settings.settingUpPlexDescription\": \"Za postavljanje Plexa unesi detalje ručno ili odaberi poslužitelj dohvaćen s <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Pritisni gumb desno od padajućeg izbornika za dohvaćanje popisa dostupnih poslužitelja.\",\n  \"components.Settings.sonarrsettings\": \"Sonarr postavke\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.tautulliApiKey\": \"API ključ\",\n  \"components.Settings.tautulliSettingsDescription\": \"Opcionalno konfiguriraj postavke za tvoj Tautulli poslužitelj. Seerr dohvaća podatke o povijesti gledanja za tvoje Plex medije od Tautullija.\",\n  \"components.Settings.toastPlexConnecting\": \"Pokušaj povezivanja na Plex …\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Neuspjelo povezivanje na Plex.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex veza je uspješno uspostavljena!\",\n  \"components.Settings.toastPlexRefresh\": \"Dohvaćanje popisa poslužitelja od Plexa …\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Neuspjelo dohvaćanje popisa Plex poslužitelja.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Popis Plex poslužitelja je uspješno dohvaćen!\",\n  \"components.Settings.urlBase\": \"Osnovni URL\",\n  \"components.Settings.validationApiKey\": \"Moraš navesti valjani API ključ\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Setup.continue\": \"Nastaviti\",\n  \"components.Setup.finish\": \"Završi postavljanje\",\n  \"components.Setup.welcome\": \"Seerr dobrodošlica\",\n  \"components.Setup.finishing\": \"Završavanje…\",\n  \"components.Setup.setup\": \"Postavljanje\",\n  \"components.Setup.signinMessage\": \"Za postavljanje se prijavi s tvojim Plex računom\",\n  \"components.StatusBadge.managemedia\": \"Upravljaj {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Otvori u {arr}\",\n  \"components.StatusBadge.playonplex\": \"Reproduciraj na Plexu\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} ažuriran\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Svi glumci serije\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Svi suradnici serije\",\n  \"components.TvDetails.cast\": \"Glumci\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# epizoda} few {# epizode} other {# epizoda}}\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# sezona} few {# sezone} other {# sezona}}\",\n  \"components.TvDetails.seasonstitle\": \"Sezone\",\n  \"components.UserList.creating\": \"Stvaranje …\",\n  \"components.UserList.edituser\": \"Uredi korisničke dozvole\",\n  \"components.UserList.email\": \"E-mail adresa\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {korisnik je uspješno uvezen} few {korisnika su uspješno uvezena} other {korisnika su uspješno uvezeni}}!\",\n  \"components.UserList.importfromplex\": \"Uvezi Plex korisnike\",\n  \"components.UserList.localuser\": \"Lokalni korisnik\",\n  \"components.UserList.newplexsigninenabled\": \"Postavka <strong>Aktiviraj novu Plex prijavu</strong> je trenutačno dektivirana. Plex korisnici s pristupom biblioteci se ne moraju uvesti da bi se mogli prijaviti.\",\n  \"components.UserList.owner\": \"Vlasnik\",\n  \"components.UserList.password\": \"Lozinka\",\n  \"components.UserList.passwordinfodescription\": \"Konfiguriraj URL programa i aktiviraj e-mail obavijesti za dozvoljavanje automatskog generiranja lozinke.\",\n  \"components.UserList.plexuser\": \"Plex korisnik\",\n  \"components.UserList.role\": \"Uloga\",\n  \"components.UserList.sortCreated\": \"Datum pridruživanja\",\n  \"components.UserList.sortDisplayName\": \"Prikazano ime\",\n  \"components.UserList.sortRequests\": \"Broj zahtjeva\",\n  \"components.UserList.totalrequests\": \"Zahtjevi\",\n  \"components.UserList.user\": \"Korisnik\",\n  \"components.UserList.usercreatedfailed\": \"Dogodila se greška prilikom stvaranja korisnika.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Navedenu e-mail adresu koristi već jedan drugi korisnik.\",\n  \"components.UserList.userdeleteerror\": \"Dogodila se greška prilikom brisanja korisnika.\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Datum pridruživanja: {joindate}\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID korisnika: {userid}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Vrsta računa\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrator\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Jezik prikaza\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Korisnički ID na Discordu\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"<FindDiscordIdLink>Višeznamenkasti ID broj</FindDiscordIdLink> povezan s tvojim korisničkim računom na Discordu\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Prikazano ime\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Mijenjanje globalnih ograničenja\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Opće\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Opće postavke\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Zadano ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtriraj sadržaj po izvornom jeziku\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Jezik otkrivanja\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex korisnik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Automatsko zahtijevanje filmova\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Automatski zatraži filmove na tvom <PlexWatchlistSupportLink>Plex popisu gledanja</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Automatsko zahtijevanje serija\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Ograničenje zahtjeva za serije\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtriraj sadržaj prema regionalnoj dostupnosti\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Uloga\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord postavke obavijesti su uspješno spremljene!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Neuspjelo spremanje e-mail postavki obavijesti.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"E-mail postavke obavijesti su uspješno spremljene!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Obavijesti\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Postavke za obavijesti\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Token za pristup\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet postavke obavijesti su uspješno spremljene!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"API token programa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registriraj jedan program</ApplicationRegistrationLink> za korištenje s {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Pošalji tiho\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Pošalji obavijesti bez zvuka\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chat ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Započni chat</TelegramBotLink>, dodaj <GetIdBotLink>@get_id_bot</GetIdBotLink> zadaj naredbu <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Neuspjelo spremanje Telegram postavki obavijesti.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Aktualna lozinka\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Ovaj korisnički račun trenutačno nema postavljenu lozinku. Dolje konfiguriraj lozinku kako bi se ovom računu omogućila prijava kao „lokalni korisnik.”\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Tvoj račun trenutačno nema postavljenu lozinku. Konfiguriraj lozinku za omogućavanje prijave kao „lokalni korisnik” koristeći tvoju e-mail adresu.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Nemaš dozvole za mijenjenje lozinke ovog korisnika.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Lozinka\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Dogodila se greška prilikom spremanja lozinke.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Dogodila se greška prilikom spremanja lozinke. Je li tvoja aktualna lozinka ispravno upisana?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Lozinka je uspješno spremljena!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Moraš navesti tvoju aktualnu lozinku\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Moraš navesti novu lozinku\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Lozinka je prekratka; mora sadržati barem 8 znakova\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Dogodila se greška prilikom spremanja postavki.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Dozvole su uspješno spremljene!\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Ne možeš promijeniti vlastite dozvole.\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Opće\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Obavijesti\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Dozvole\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Nemaš dozvole za mijenjenje postavki ovog korisnika.\",\n  \"components.UserProfile.emptywatchlist\": \"Mediji koji su dodani u tvoj <PlexWatchlistSupportLink>Plex popis gledanja</PlexWatchlistSupportLink> pojavit će se ovdje.\",\n  \"components.UserProfile.movierequests\": \"Zahtjevi za filmove\",\n  \"components.UserProfile.pastdays\": \"{type} (zadnjih {days} dana)\",\n  \"components.UserProfile.plexwatchlist\": \"Plex popis gledanja\",\n  \"components.UserProfile.seriesrequest\": \"Zahtjevi za serije\",\n  \"components.UserProfile.totalrequests\": \"Ukupno zahtjeva\",\n  \"components.UserProfile.unlimited\": \"Neograničeno\",\n  \"i18n.available\": \"Dostupno\",\n  \"i18n.back\": \"Natrag\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.edit\": \"Uredi\",\n  \"i18n.experimental\": \"Eksperimentalno\",\n  \"i18n.pending\": \"Na čekanju\",\n  \"i18n.previous\": \"Prethodno\",\n  \"i18n.processing\": \"Obrada\",\n  \"i18n.request\": \"Zahtjev\",\n  \"i18n.request4k\": \"Zatraži u 4K\",\n  \"i18n.requested\": \"Zatraženo\",\n  \"i18n.resultsperpage\": \"Prikaži {pageSize} rezultata po stranici\",\n  \"i18n.retrying\": \"Pokušaj se ponavlja …\",\n  \"i18n.requesting\": \"Zahtijevanje …\",\n  \"i18n.resolved\": \"Riješeno\",\n  \"i18n.save\": \"Spremi promjene\",\n  \"i18n.saving\": \"Spremanje …\",\n  \"i18n.settings\": \"Postavke\",\n  \"i18n.showingresults\": \"Prikaz <strong>{from}</strong> do <strong>{to}</strong> od <strong>{total}</strong> rezultata\",\n  \"i18n.test\": \"Provjeri\",\n  \"i18n.testing\": \"Provjeravanje …\",\n  \"i18n.tvshow\": \"Serije\",\n  \"i18n.tvshows\": \"Serije\",\n  \"i18n.unavailable\": \"Nedostupno\",\n  \"i18n.usersettings\": \"Korisničke postavke\",\n  \"i18n.view\": \"Prikaz\",\n  \"pages.errormessagewithcode\": \"{statusCode} – {error}\",\n  \"pages.internalservererror\": \"Interna greška poslužitelja\",\n  \"pages.pagenotfound\": \"Stranica nije pronađena\",\n  \"pages.returnHome\": \"Vrati se na početnu stranicu\",\n  \"pages.serviceunavailable\": \"Usluga nije dostupna\",\n  \"pages.somethingwentwrong\": \"Dogodila se greška\",\n  \"components.PermissionEdit.requestTv\": \"Zahtjev za serijama\",\n  \"components.PermissionEdit.users\": \"Upravljanje korisnicima\",\n  \"components.PermissionEdit.viewissues\": \"Prikaz problema\",\n  \"components.PermissionEdit.viewrecent\": \"Prikaz nedavno dodanih\",\n  \"components.PermissionEdit.viewrequests\": \"Prikaz zahtjeva\",\n  \"components.PermissionEdit.viewwatchlists\": \"Prikaži Plex popise gledanja\",\n  \"components.PersonDetails.alsoknownas\": \"Poznat/a i kao: {names}\",\n  \"components.PersonDetails.appearsin\": \"Nastupanja\",\n  \"components.PersonDetails.ascharacter\": \"kao {character}\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.unlimited\": \"Neograničeno\",\n  \"components.RegionSelector.regionDefault\": \"Sve regije\",\n  \"components.RegionSelector.regionServerDefault\": \"Zadano ({region})\",\n  \"components.RequestBlock.approve\": \"Odobri zahtjev\",\n  \"components.RequestBlock.decline\": \"Odbij zahtjev\",\n  \"components.RequestBlock.delete\": \"Izbriši zahtjev\",\n  \"components.RequestBlock.edit\": \"Uredi zahtjev\",\n  \"components.RequestBlock.server\": \"Odredišni poslužitelj\",\n  \"components.RequestButton.approverequest\": \"Odobri zahtjev\",\n  \"components.RequestButton.approverequest4k\": \"Odobri 4K zahtjev\",\n  \"components.RequestButton.requestmore\": \"Zatraži više\",\n  \"components.RequestButton.requestmore4k\": \"Zatraži više u 4K\",\n  \"components.RequestButton.viewrequest\": \"Prikaz zahtjeva\",\n  \"components.RequestButton.viewrequest4k\": \"Prikaz 4K zahtjeva\",\n  \"components.RequestCard.approverequest\": \"Odobri zahtjev\",\n  \"components.RequestCard.cancelrequest\": \"Otkaži zahtjev\",\n  \"components.RequestCard.declinerequest\": \"Odbij zahtjev\",\n  \"components.RequestCard.deleterequest\": \"Izbriši zahtjev\",\n  \"components.RequestCard.editrequest\": \"Uredi zahtjev\",\n  \"components.RequestCard.failedretry\": \"Dogodila se greška prilikom ponovnog pokušaja slanja zahtjeva.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} nije pronađen\",\n  \"components.RequestList.RequestItem.requested\": \"Zatraženo\",\n  \"components.RequestList.requests\": \"Zahtjevi\",\n  \"components.RequestList.showallrequests\": \"Prikaži sve zahtjeve\",\n  \"components.RequestList.sortModified\": \"Zadnja promjena\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Napredno\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Zatraži kao\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Odaberi oznake\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Oznake\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.RequestModal.errorediting\": \"Dogodila se greška prilikom uređivanja zahtjeva.\",\n  \"components.RequestModal.numberofepisodes\": \"Broj epizoda\",\n  \"components.RequestModal.pending4krequest\": \"4K zahtjevi na čekanju\",\n  \"components.RequestModal.pendingapproval\": \"Tvoj zahtjev čeka na odobrenje.\",\n  \"components.RequestCard.tvdbid\": \"TVDB ID\",\n  \"components.RequestModal.pendingrequest\": \"Zahtjevai na čekanju\",\n  \"components.RequestModal.requestApproved\": \"Zahtjev za <strong>{title}</strong> je odobren!\",\n  \"components.RequestModal.requestcancelled\": \"Zahtjev za <strong>{title}</strong> je prekinut.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Zatraži zbirku u 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Zatraži zbirku\",\n  \"components.RequestModal.requesterror\": \"Dogodila se greška prilikom slanja zahtjeva.\",\n  \"components.RequestModal.requestfrom\": \"Zahtjev korisnika {username} čeka na odobrenje.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Zatraži film u 4K\",\n  \"components.RequestModal.requestseries4ktitle\": \"Zatraži seriju u 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Zatraži seriju\",\n  \"components.RequestModal.season\": \"Sezona\",\n  \"components.RequestModal.seasonnumber\": \"Sezona {number}\",\n  \"components.RequestModal.selectmovies\": \"Odaberi filmove\",\n  \"components.RequestModal.selectseason\": \"Odaberi sezone\",\n  \"components.ResetPassword.gobacklogin\": \"Vrati se na stranicu za prijavu\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Lozinke se moraju poklapati\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Lozinka je prekratka; mora sadržati barem 8 znakova\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Moraš navesti lozinku\",\n  \"components.Search.searchresults\": \"Rezultati pretrage\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Aktiviraj agenta\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Neuspjelo spremanje postavki Gotify obavijesti.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Slanje Gotify obavijesti provjere …\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify obavijest provjere je poslana!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token programa\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL poslužitelja\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL ne smije završiti s kosom crtom\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Token za pristup\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Neuspjelo spremanje postavki Pushbullet obavijesti.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Neuspjelo slanje Pushbullet obavijesti provjere.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Moraš navesti valjani token za pristup\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Moraš odabrati barem jednu vrstu obavijesti\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"API token programa\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registriraj jedan program</ApplicationRegistrationLink> za korištenje s Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Neuspjelo spremanje Pushover postavki obavijesti.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Neuspjelo slanje Pushover obavijesti provjere.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Moraš navesti valjani token programa\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Moraš odabrati barem jednu vrstu obavijesti\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Moraš navesti valjani ključ korisnika ili grupe\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Aktiviraj agenta\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Neuspjelo spremanje Slack postavki obavijesti.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack postavke obavijesti su uspješno spremljene!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Neuspjelo slanje Slack obavijesti provjere.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Slanje Slack obavijesti provjere …\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack obavijest provjere je poslana!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Moraš odabrati barem jednu vrstu obavijesti\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Slanje webhook obavijesti provjere …\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook obavijest provjere je poslana!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Moraš odabrati barem jednu vrstu obavijesti\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Moraš navesti valjani URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Dozvoli samopotpisane certifikate\",\n  \"components.Settings.Notifications.authPass\": \"SMTP lozinka\",\n  \"components.Settings.Notifications.authUser\": \"SMTP korisničko ime\",\n  \"components.Settings.Notifications.botAPI\": \"Token autorizacije bota\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL avatara bota\",\n  \"components.Settings.Notifications.botUsername\": \"Korisničko ime bota\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Dozvoli korisnicima da započnu chat s tvojim botom i da konfiguriraju vlastite obavijesti\",\n  \"components.Settings.Notifications.encryption\": \"Metoda šifriranja\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Koristi STARTTLS ako je dostupno\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Koristi implicitni TLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"Ništa\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Uvijek koristi STARTTLS\",\n  \"components.Settings.Notifications.encryptionTip\": \"U većini slučajeva implicitni TLS koristi priključak 465, a STARTTLS priključak 587\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP lozinka\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Pošalji obavijesti bez zvuka\",\n  \"components.Settings.Notifications.senderName\": \"Ime pošiljatelja\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP računalo\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP priključak\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Neuspjelo spremanje Telegram postavki obavijesti.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram postavke obavijesti su uspješno spremljene!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Neuspjelo slanje e-mail obavijesti provjere.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Slanje e-mail obavijesti provjere …\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"E-mail obavijest provjere je poslana!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Neuspjelo slanje Telegram obavijesti provjere.\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Moraš navesti token autorizacije za bot\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Moraš navesti valjani chat ID\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Osnovni URL\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Dodaj novi 4K Radarr poslužitelj\",\n  \"components.Settings.RadarrModal.createradarr\": \"Dodaj novi Radarr poslužitelj\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Zadani 4K poslužitelj\",\n  \"components.Settings.RadarrModal.editradarr\": \"Uredi Radarr poslužitelj\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Aktiviraj automatsku pretragu\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Eksterni URL\",\n  \"components.Settings.RadarrModal.hostname\": \"Ime računala ili IP adresa\",\n  \"components.Settings.RadarrModal.inCinemas\": \"U kinima\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Nema oznaka.\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Odaberi profil kvalitete\",\n  \"components.Settings.RadarrModal.port\": \"Priključak\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Odaberi početnu mapu\",\n  \"components.Settings.RadarrModal.selecttags\": \"Odaberi oznake\",\n  \"components.Settings.RadarrModal.server4k\": \"4K poslužitelj\",\n  \"components.Settings.RadarrModal.servername\": \"Ime poslužitelja\",\n  \"components.Settings.RadarrModal.ssl\": \"Koristi SSL\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Provjeri vezu za učitavanje početnih mapa\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr veza je uspješno uspostavljena!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Moraš navesti valjani API ključ\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Moraš navesti valjani URL\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL ne smije završiti s kosom crtom\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Osnovni URL mora početi s kosom crtom\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Moraš odabrati najmanju dostupnost\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Moraš navesti valjani broj priključka\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Moraš odabrati profil kvalitete\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Trenutno\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Najnovije\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Podaci izdanja trenutačno nisu nedostupni.\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} – zapisnik promjena\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Prikaz promjena\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Prikaz na GitHubu\",\n  \"components.Settings.SettingsAbout.about\": \"Informacije\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Mapa podataka\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Ukupno zahtjeva\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Aktualno\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr sprema zahtjeve na eksterne točke pristupa API-u za optimiranje izvedbe i izbjegavanje upućivanja nepotrebnih API poziva.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Predmemorija {cachename} je ispražnjena.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Pogodci\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Aktiviraj novu Plex prijavu\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Dogodila se greška prilikom spremanja postavki.\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Učitavanje profila jezika …\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Neuspjelo povezivanje na Sonarr.\",\n  \"components.Settings.manualscan\": \"Ručno skeniranje biblioteke\",\n  \"components.Settings.mediaTypeSeries\": \"serija\",\n  \"components.Settings.tautulliSettings\": \"Tautulli postavke\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Osnovni URL mora početi s kosom crtom\",\n  \"components.Settings.webAppUrlTip\": \"Opcionalno usmjeri korisnike na web program na tvom poslužitelju umjesto na „hostirani” web program\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Pritisni donji gumb za ponovno pokretanje programa.\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Ponovo pokreni poslužitelja kako bi se ažurirane postavke primijenile.\",\n  \"components.TvDetails.episodeRuntime\": \"Trajanje epizode\",\n  \"components.TvDetails.nextAirDate\": \"Datum sljedećeg emitiranja\",\n  \"components.TvDetails.rtaudiencescore\": \"Ocjena Rotten Tomatoes publike\",\n  \"components.TvDetails.seasonnumber\": \"Sezona {seasonNumber}\",\n  \"components.UserList.createlocaluser\": \"Stvori lokalnog korisnika\",\n  \"components.UserList.deleteuser\": \"Izbriši korisnika\",\n  \"components.UserList.importfromplexerror\": \"Dogodila se greška prilikom uvoza Plex korisnika.\",\n  \"components.UserList.localLoginDisabled\": \"Postavka <strong>Aktiviraj lokalnu prijavu</strong> je trenutačno deaktivirana.\",\n  \"components.UserList.nouserstoimport\": \"Nema Plex korisnika za uvoz.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Javni PGP ključ\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Šifriraj e-mail poruke koristeći <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Moraš navesti valjani chat ID\",\n  \"components.UserProfile.limit\": \"{remaining} od {limit}\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TVDB ID\",\n  \"components.PermissionEdit.autorequest\": \"Automatsko zahtijevanje\",\n  \"components.PermissionEdit.autorequestMovies\": \"Automatsko zahtijevanje filmova\",\n  \"components.PermissionEdit.autorequestSeries\": \"Automatsko zahtijevanje serija\",\n  \"components.PermissionEdit.createissues\": \"Prijavljivanje problema\",\n  \"components.PermissionEdit.manageissues\": \"Upravljanje problemima\",\n  \"components.PermissionEdit.managerequests\": \"Upravljaj zahtjevima\",\n  \"components.PermissionEdit.request\": \"Zahtjev\",\n  \"components.PermissionEdit.request4k\": \"Zahtjev za 4K rezoluciju\",\n  \"components.PermissionEdit.request4kMovies\": \"Zahtjev za filmove u 4K rezoluciji\",\n  \"components.PermissionEdit.request4kTv\": \"Zahtjev za serije u 4K rezoluciji\",\n  \"components.PermissionEdit.requestMovies\": \"Zahtjev za filmovima\",\n  \"components.PersonDetails.birthdate\": \"Datum rođenja {birthdate}\",\n  \"components.PersonDetails.crewmember\": \"Suradnik\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} po {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} po {quotaDays} {days}</quotaUnits>\",\n  \"components.RequestBlock.languageprofile\": \"Profil jezika\",\n  \"components.RequestBlock.lastmodifiedby\": \"Zadnja promjena od\",\n  \"components.RequestBlock.profilechanged\": \"Profil kvalitete\",\n  \"components.RequestBlock.requestdate\": \"Datum zahtjeva\",\n  \"components.RequestBlock.requestedby\": \"Podnositelj zahtjeva\",\n  \"components.RequestBlock.requestoverrides\": \"Promjene zahtjeva\",\n  \"components.RequestBlock.rootfolder\": \"Početna mapa\",\n  \"components.RequestButton.declinerequest\": \"Odbij zahtjev\",\n  \"components.RequestButton.declinerequest4k\": \"Odbij 4K zahtjev\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Prekini zahtjev\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Izbriši zahtjev\",\n  \"components.RequestList.RequestItem.editrequest\": \"Uredi zahtjev\",\n  \"components.RequestList.RequestItem.failedretry\": \"Dogodila se greška prilikom ponovnog pokušaja slanja zahtjeva.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} nije pronađen\",\n  \"components.RequestList.RequestItem.modified\": \"Promijenjeno\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date}, korisnik: {user}\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Zatraženo\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.sortAdded\": \"Najnoviji\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Ovo je serija anime filmova.\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (zadano)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Odredišni poslužitelj\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Profil jezika\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Nema oznaka.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Profil kvalitete\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Početna mapa\",\n  \"components.RequestModal.QuotaDisplay.season\": \"sezona\",\n  \"components.RequestModal.alreadyrequested\": \"Već zatraženo\",\n  \"components.RequestModal.approve\": \"Odobri zahtjev\",\n  \"components.RequestModal.autoapproval\": \"Automatsko odobravanje\",\n  \"components.RequestModal.cancel\": \"Prekini zahtjev\",\n  \"components.RequestModal.edit\": \"Uredi zahtjev\",\n  \"components.RequestModal.requestCancel\": \"Zahtjev za <strong>{title}</strong> je prekinut.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> je uspješno zatražen!\",\n  \"components.RequestModal.requestedited\": \"Zahtjev za <strong>{title}</strong> je uspješno uređen!\",\n  \"components.RequestModal.requestmovietitle\": \"Zatraži film\",\n  \"components.RequestModal.requestseasons\": \"Zatraži {seasonCount} {seasonCount, plural, one {sezonu} few {sezone} other {sezona}}\",\n  \"components.RequestModal.requestseasons4k\": \"Zatraži {seasonCount} {seasonCount, plural, one {sezonu} few {sezone} other {sezona}} u 4K\",\n  \"components.ResetPassword.confirmpassword\": \"Potvrdi lozinku\",\n  \"components.ResetPassword.email\": \"E-mail adresa\",\n  \"components.ResetPassword.password\": \"Lozinka\",\n  \"components.ResetPassword.passwordreset\": \"Ponovo postavljanje lozinke\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Poveznica za ponovno postavljanje lozinke bit će poslana na navedenu e-mail adresu ako je povezana s valjanim korisnikom.\",\n  \"components.ResetPassword.resetpassword\": \"Obnovni svoju lozinku\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Lozinka je uspješno ponovno postavljena!\",\n  \"components.ResetPassword.validationemailrequired\": \"Moraš zadati valjanju e‑mail adresu\",\n  \"components.Search.search\": \"Pretraga\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify postavke obavijesti su uspješno spremljene!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Neuspjelo slanje Gotify obavijesti provjere.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Moraš navesti token programa\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Moraš odabrati barem jednu vrstu obavijesti\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Moraš navesti valjani URL\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Stvori token iz tvojih <PushbulletSettingsLink>postavki računa</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Aktiviraj agenta\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Oznaka kanala\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet postavke obavijesti su uspješno spremljene!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Slanje Pushbullet obavijesti provjere …\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet obavijest provjere je poslana!\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Aktiviraj agenta\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover postavke obavijesti su uspješno spremljene!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Slanje Pushover obavijesti provjere …\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover obavijest provjere je poslana!\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Ključ korisnika ili grupe\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Tvoj <UsersGroupsLink>identifikator korisnika ili grupe</UsersGroupsLink> s 30 znakova\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Moraš navesti valjani URL\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Aktiviraj agenta\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Stvori <WebhookLink>ulaznu Webhook</WebhookLink> integraciju\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Neuspjelo slanje Web push obavijesti provjere.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Slanje web push obavijesti provjere …\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Web push obavijest provjere je poslana!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Neuspjelo spremanje Web push postavki obavijesti.\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Aktiviraj agenta\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Web push postavke obavijesti su uspješno spremljene!\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Zaglavlje autorizacije\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Resetiraj na zadane vrijednosti\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Neuspjelo slanje Webhook obavijesti provjere.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Neuspjelo spremanje Webhook postavki obavijesti.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Webhook postavke obavijesti su uspješno spremljene!\",\n  \"components.Settings.Notifications.agentenabled\": \"Aktiviraj agenta\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Stvori bot</CreateBotLink> za korištenje s Seerr\",\n  \"components.Settings.Notifications.chatId\": \"Chat ID\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Neuspjelo spremanje Discord postavki za obavijesti.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord postavke obavijesti su uspješno spremljene!\",\n  \"components.Settings.Notifications.emailsender\": \"Adresa pošiljatelja\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Neuspjelo spremanje e-mail postavki obavijesti.\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"E-mail postavke obavijesti su uspješno spremljene!\",\n  \"components.Settings.Notifications.enableMentions\": \"Aktiviraj spominjanja\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Potpiši šifrirane e-mail poruke koristeći <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Privatni PGP ključ\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Potpiši šifrirane e-mail poruke koristeći <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.sendSilently\": \"Pošalji tiho\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Neuspjelo slanje Discord obavijesti provjere.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Slanje Discord obavijesti provjere …\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord obavijest provjere je poslana!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Slanje Telegram obavijesti provjere …\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram obavijest provjere je poslana!\",\n  \"components.Settings.Notifications.validationEmail\": \"Moraš navesti valjanju e‑mail adresu\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Moraš navesti PGP lozinku\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Moraš navesti valjan privatni PGP ključ\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Moraš navesti valjano ime računala ili IP adresu\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Moraš navesti valjani broj priključka\",\n  \"components.Settings.Notifications.validationTypes\": \"Moraš odabrati barem jednu vrstu obavijesti\",\n  \"components.Settings.Notifications.validationUrl\": \"Moraš navesti valjani URL\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook URL\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Stvori <DiscordWebhookLink>webhook integraciju</DiscordWebhookLink> u tvom poslužitelju\",\n  \"components.Settings.RadarrModal.add\": \"Dodaj poslužitelj\",\n  \"components.Settings.RadarrModal.announced\": \"Najavljeno\",\n  \"components.Settings.RadarrModal.apiKey\": \"API ključ\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Zadani poslužitelj\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Uredi 4K Radarr poslužitelj\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Učitavanje oznaka …\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Učitavanje profila kvalitete …\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Učitavanje početnih mapa …\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Najmanja dostupnost\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Profil kvalitete\",\n  \"components.Settings.RadarrModal.released\": \"Objavljeno\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Početna mapa\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Odaberi najmanju dostupnost\",\n  \"components.Settings.RadarrModal.tags\": \"Oznake\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Provjeri vezu za učitavanje profila kvalitete\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Provjeri vezu za učitavanje oznaka\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Neuspjelo povezivanje na Radarr.\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Osnovni URL ne smije završiti s kosom crtom\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Moraš navesti valjano ime računala ili IP adresu\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Moraš navesti ime poslužitelja\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Moraš odabrati početnu mapu\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Izdanja\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentacija\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Dobivanje pomoći\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Rasprave na GitHubu\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Zastarjela verzija\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Pokrećeš <code>razvojnu</code> Seerr granu, koja se preporučuje samo onima koji doprinose razvoju ili pomažu najnovijem testiranju.\",\n  \"components.Settings.SettingsAbout.timezone\": \"Vremenska zona\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Ukupno medija\",\n  \"components.Settings.SettingsAbout.version\": \"Verzija\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Predmemorija\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Ukupno ključeva\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Veličina ključa\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Promašaji\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Ime predmemorije\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Veličina vrijednosti\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Prekini zadatak\",\n  \"components.Settings.SettingsJobsCache.command\": \"Naredba\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Sinkronizacija preuzimanja\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Resetiraj sinkronizaciju preuzimanja\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Promijeni zadatak\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"{jobScheduleHours, plural, one {Svake minute} few {Svake {jobScheduleHours} minute} other {Svakih {jobScheduleHours} minuta}}\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Isprazni predmemoriju\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"Zadatak {jobname} prekinut.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Ime zadatka\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Zadaci\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr obavlja određene zadatke održavanja kao redovito planirane zadatke, ali oni se također mogu dolje ručno pokrenuti. Ručno pokretanje zadatka neće promijeniti njegov plan.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Vrsta\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Zadaci i predmemorija\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"Zadatak {jobname} je pokrenut.\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Sljedeće izvršavanje\",\n  \"components.Settings.SettingsJobsCache.process\": \"Obrada\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Kopiraj u međuspremnik\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Ove zapise možeš izravno vidjeti i putem <code>stdout</code> ili u <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.message\": \"Poruka\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Zaustavi\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Dozvoli Plex korisnicima da se prijave bez da se prethodno uvezu\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Provjeri vezu za učitavanje profila jezika\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL ne smije završiti s kosom crtom\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Dogodila se greška prilikom spremanja Tautulli postavki.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli postavke su uspješno spremljene!\",\n  \"components.Settings.validationHostnameRequired\": \"Moraš navesti valjano ime računala ili IP adresu\",\n  \"components.Settings.validationPortRequired\": \"Moraš navesti valjani broj priključka\",\n  \"components.Settings.validationUrl\": \"Moraš navesti valjani URL\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"Osnovni URL ne smije završiti s kosom crtom\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL ne smije završiti s kosom crtom\",\n  \"components.Settings.webAppUrl\": \"URL <WebAppLink>web programa</WebAppLink>\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Setup.configureservices\": \"Konfiguriraj usluge\",\n  \"components.StatusChecker.reloadApp\": \"Ponovo pokreni {applicationTitle}\",\n  \"components.StatusChecker.restartRequired\": \"Zahtijeva ponovno pokretanje poslužitelja\",\n  \"components.TitleCard.tvdbid\": \"TVDB ID\",\n  \"components.TitleCard.cleardata\": \"Izbriši podatke\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} nije pronađen\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Dogodila se greška prilikom dohvaćanja podataka sezona.\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} min\",\n  \"components.TvDetails.firstAirDate\": \"Datum prvog emitiranja\",\n  \"components.TvDetails.manageseries\": \"Upravljaj serijama\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {mreža} few {mreže} other {mreža}}\",\n  \"components.TvDetails.originallanguage\": \"Izvorni jezik\",\n  \"components.TvDetails.originaltitle\": \"Izvorni naslov\",\n  \"components.TvDetails.overview\": \"Pregled\",\n  \"components.TvDetails.overviewunavailable\": \"Pregled nedostupan.\",\n  \"components.TvDetails.productioncountries\": \"{countryCount, plural, one {zemlja produkcije} few {zemlje produkcije} other {zemalja produkcije}}\",\n  \"components.TvDetails.recommendations\": \"Preporuke\",\n  \"components.TvDetails.reportissue\": \"Prijavi problem\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometar\",\n  \"components.TvDetails.showtype\": \"Vrste serija\",\n  \"components.TvDetails.similar\": \"Slične serije\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.streamingproviders\": \"Trenutačno se prikazuje na\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB ocjena korisnika\",\n  \"components.TvDetails.viewfullcrew\": \"Prikaz svih suradnika\",\n  \"components.TvDetails.watchtrailer\": \"Gledaj najavu\",\n  \"components.UserList.autogeneratepassword\": \"Automatski generiraj lozinku\",\n  \"components.UserList.autogeneratepasswordTip\": \"Pošalji korisniku e-mail s lozinkom koju je generirao poslužitelj\",\n  \"components.UserList.bulkedit\": \"Grupno uređivanje\",\n  \"components.UserList.accounttype\": \"Vrsta\",\n  \"components.UserList.admin\": \"Administrator\",\n  \"components.UserList.create\": \"Stvori\",\n  \"components.UserList.created\": \"Pridruživanje\",\n  \"components.UserList.deleteconfirm\": \"Stvarno želiš izbrisati ovog korisnika? Svi podaci njegovih zahtjeva će se trajno ukloniti.\",\n  \"components.UserList.usercreatedsuccess\": \"Korisnik je uspješno stvoren!\",\n  \"components.UserList.userdeleted\": \"Korisnik je uspješno izbrisan!\",\n  \"components.UserList.userfail\": \"Dogodila se greška prilikom spremanja korisničkih dozvola.\",\n  \"components.UserList.userlist\": \"Popis korisnika\",\n  \"components.UserList.users\": \"Korisnici\",\n  \"components.UserList.userssaved\": \"Korisničke dozvole su uspješno spremljene!\",\n  \"components.UserList.validationEmail\": \"Moraš zadati valjanju e‑mail adresu\",\n  \"components.UserList.validationpasswordminchars\": \"Lozinka je prekratka; mora sadržati barem 8 znakova\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Prikaz profila\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Uredi postavke\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Lokalni korisnik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Ograničenje zahtjeva za filmove\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Vlasnik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Automatski zatraži serije na tvom <PlexWatchlistSupportLink>Plex popisu gledanja</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Regionalno otkrivanje\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Dogodila se greška prilikom spremanja postavki.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Postavke su uspješno spremljene!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Korisnik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Moraš navesti valjani Discord korisnički ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID korisnika\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"<FindDiscordIdLink>Višeznamenkasti ID broj</FindDiscordIdLink> povezan s tvojim korisničkim računom\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Neuspjelo spremanje Discord postavki obavijesti.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Stvori token iz tvojih <PushbulletSettingsLink>postavki računa</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Neuspjelo spremanje Pushbullet postavki obavijesti.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Ključ korisnika ili grupe\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Tvoj <UsersGroupsLink>identifikator korisnika ili grupe</UsersGroupsLink> s 30 znakova\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Neuspjelo spremanje Pushover postavki obavijesti.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover postavke obavijesti su uspješno spremljene!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram postavke obavijesti su uspješno spremljene!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Moraš navesti valjani korisnički ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Moraš navesti valjani javni ključ stvoren PGP-om\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Moraš navesti valjani token za pristup\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Moraš navesti valjani token programa\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Moraš navesti valjani ključ korisnika ili grupe\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Potvrdi lozinku\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nova lozinka\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Moraš potvrditi novu lozinku\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Lozinke se moraju poklapati\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Dozvole\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Lozinka\",\n  \"components.UserProfile.recentrequests\": \"Nedavni zahtjevi\",\n  \"components.UserProfile.recentlywatched\": \"Nedavno gledano\",\n  \"components.UserProfile.requestsperdays\": \"{limit} preostalo\",\n  \"i18n.advanced\": \"Napredno\",\n  \"i18n.all\": \"Sve\",\n  \"i18n.approve\": \"Odobri\",\n  \"i18n.approved\": \"Odobreno\",\n  \"i18n.areyousure\": \"Sigurno?\",\n  \"i18n.cancel\": \"Odustani\",\n  \"i18n.canceling\": \"Prekidanje …\",\n  \"i18n.close\": \"Zatvori\",\n  \"i18n.decline\": \"Odbij\",\n  \"i18n.declined\": \"Odbijeno\",\n  \"i18n.delete\": \"Izbriši\",\n  \"i18n.deleting\": \"Brisanje …\",\n  \"i18n.failed\": \"Neuspjelo\",\n  \"i18n.import\": \"Uvezi\",\n  \"i18n.importing\": \"Uvoz …\",\n  \"i18n.loading\": \"Učitavanje …\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.movies\": \"Filmovi\",\n  \"i18n.next\": \"Dalje\",\n  \"i18n.noresults\": \"Nema rezultata.\",\n  \"i18n.notrequested\": \"Nije zatraženo\",\n  \"i18n.open\": \"Otvori\",\n  \"i18n.partiallyavailable\": \"Djelomično dostupno\",\n  \"i18n.restartRequired\": \"Zahtijeva ponovno pokretanje\",\n  \"i18n.retry\": \"Pokušaj ponovo\",\n  \"i18n.status\": \"Stanje\",\n  \"pages.oops\": \"Ups\",\n  \"components.Settings.advancedTooltip\": \"Neispravno konfiguriranje ove postavke može pokvariti funkcionalnost\",\n  \"components.Settings.noDefaultNon4kServer\": \"Ako imaš samo jedan {serverType} poslužitelj za ne-4K i za 4K sadržaj (ili ako preuzimaš samo 4K sadržaj), <strong>NEMOJ</strong> odrediti svoj {serverType} poslužitelj kao 4K poslužitelj.\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Dozvoli automatsko slanje zahtjeva za filmove koje nisu u 4K rezoluciji.\",\n  \"components.PermissionEdit.autorequestDescription\": \"Dozvoli automatsko slanje zahtjeva za medije koji nisu u 4K rezoluciji putem Plex popisa gledanja.\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Dozvoli automatsko slanje zahtjeva za filmove koji nisu u 4K rezoluciji putem Plex popisa gledanja.\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Dozvoli automatsko slanje zahtjeva za serije koje nisu u 4K rezoluciji putem Plex popisa gledanja.\",\n  \"components.PermissionEdit.requestDescription\": \"Dozvoli automatsko slanje zahtjeva za medije koje nisu u 4K rezoluciji.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Dozvoli automatsko slanje zahtjeva za serije koje nisu u 4K rezoluciji.\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Dozvoli prikaz za pregled popisa nedavno dodanih medija.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Dozvoli prijavljivanje problema s medijima.\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Dozvoli upravljanje problemima s medijima.\",\n  \"components.PermissionEdit.request4kDescription\": \"Dozvoli slanje zahtjeva za medije u 4K rezoluciji.\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Dozvoli slanje zahtjeva za filmove u 4K rezoluciji.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Dozvoli slanje zahtjeva za serijama u 4K rezoluciji.\",\n  \"components.PermissionEdit.usersDescription\": \"Dozvoli upravljanje korisnicima. Korisnici s ovom dozvolom ne mogu mijenjati korisnike s administratorskom privilegijom ili dozvoliti administratorske privilegije.\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Dozvoli prikaz problema s medijima koje su prijavili drugi korisnici.\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Dozvoli prikaz zahtjeva za medije koje su poslali drugi korisnici.\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Dozvoli prikaz Plex popisa gledanja drugih korisnika.\",\n  \"components.Settings.notrunning\": \"Ne pokreće se\",\n  \"components.Settings.serverRemote\": \"udaljeni\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Sažetak tvojih ograničenja zahtjeva možeš vidjeti na tvojoj <ProfileLink>stranici profila</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Sažetak ograničenja zahtjeva korisničkih zahtjeva možeš vidjeti na njihovoj <ProfileLink>stranici profila</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Nema dovoljno preostalih zahtjeva za sezone\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Nismo uspjeli pronaći seriju koja odgovara ovoj seriji.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Nismo uspjeli automatski naći odgovarajuću seriju. Dolje odaberi odgovarajuću seriju.\",\n  \"components.RequestModal.requestadmin\": \"Ovaj će se zahtjev automatski odobriti.\",\n  \"components.ResetPassword.emailresetlink\": \"E-mail poveznica za obnavljanje lozinke\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Za primanje web push obavijesti, Seerr se mora posluživati putem HTTPS-a.\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Pomoć za varijablu predloška\",\n  \"components.Settings.Notifications.chatIdTip\": \"Započni chat s tvojim botom, dodaj <GetIdBotLink>@get_id_bot</GetIdBotLink> i zadaj naredbu <code>/my_id</code>\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr pretraživanje\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr pretraživanje\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Aktiviraj pretraživanje\",\n  \"components.Settings.cancelscan\": \"Prekini pretraživanje\",\n  \"components.Settings.manualscanDescription\": \"Obično će se to pokrenuti samo jednom svaka 24 sata. Seerr će agresivnije provjeriti tvoj Plex poslužitelj za nedavno dodanim. Ako po prvi put konfiguriraš Plex, preporučuje se jednom ručno pretražiti cijelu biblioteku!\",\n  \"components.Settings.plexlibrariesDescription\": \"Biblioteke u kojima će Seerr tražiti naslove. Postavi i spremi tvoje postavke Plex veze, a zatim pritisni gumb ispod ako je popis biblioteka prazan.\",\n  \"components.Settings.startscan\": \"Pokreni pretraživanje\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Dozvoli upravljanje zahtjevima za medije. Svi zahtjevi korisnika s ovom dozvolom će se automatski odobriti.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON sadržaj\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Pretraživanje cijele Plex biblioteke\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Smiješ zatražiti <strong>{limit}</strong> {type} svakih <strong>{days}</strong> dana.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Ovaj korisnik smije zatražiti <strong>{limit}</strong> {type} svakih <strong>{days}</strong> dana.\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON sadržaj je uspješno resetiran!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Moraš zadati valjani JSON sadržaj\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Aktiviraj pretraživanje\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Pretraživanje nedavno dodanih u Plex biblioteku\",\n  \"components.TvDetails.Season.noepisodes\": \"Popis epizoda nije dostupan.\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Brisanje predmemorije slika\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Predmemorija slika\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Ukupna veličina predmemorije\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Slike spremljene u predmemoriju\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Kad je u postavkama aktivirano, Seerr će služiti kao posrednik i predmemorirati slike iz unaprijed konfiguriranih vanjskih izvora. Predmemorirane slike spremaju se u mapu konfiguracije. Datoteke možeš pronaći u <code>{appDataPath}/cache/images</code>.\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Sezona {seasonNumber} Episoda {episodeNumber}\",\n  \"components.RequestCard.unknowntitle\": \"Nepoznat naslov\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Nepoznat naslov\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Serije\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Nedavno dodani\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmovi\",\n  \"components.Discover.moviegenres\": \"Žanrovi filmova\",\n  \"components.Discover.FilterSlideover.keywords\": \"Ključne riječi\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# aktivni filtar} few {# aktivna filtra} other {# aktivnih filtara}}\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Datum prvog emitiranja\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Tvoj Plex popis gledanja\",\n  \"components.Discover.FilterSlideover.genres\": \"Žanrovi\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Izvorni jezik\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Uređen klizač i spremljene postavke prilagodbe otkrivanja.\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Naziv klizača\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularnost (silazno)\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Pretražite studije…\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Navdeite TMDB ID mreže\",\n  \"components.Discover.CreateSlider.addfail\": \"Izrada novog klizača nije uspjela.\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularnost (uzlazno)\",\n  \"components.Discover.CreateSlider.needresults\": \"Morate imati barem 1 rezultat.\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Stvorite prilagođeni klizač\",\n  \"components.Discover.CreateSlider.editSlider\": \"Uredi klizač\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Morate navesti vrijednost.\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Navedite TMDB ID studija\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Traži žanrove…\",\n  \"components.Discover.CreateSlider.editfail\": \"Uređivanje klizača nije uspjelo.\",\n  \"components.Discover.CreateSlider.starttyping\": \"Počinje tipkati za pretraživanje.\",\n  \"components.Discover.CreateSlider.addSlider\": \"Dodaj klizač\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Navedite upit za pretraživanje\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Navdeite TMDB ID ključne riječi\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} filmovi\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Morate navesti naslov.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Nema rezultata.\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Pretraži ključne riječi…\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Stvoren je novi klizač i spremljene su postavke prilagodbe otkrivanja.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Navedite TMDB ID žanra\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB ocjena (uzlazno)\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Ocjena od {minValue} do {maxValue}\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Prvo emitiranje (uzlazno)\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB ocjena (silazno)\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# aktivni filtar} few {# aktivna filtra} other {# aktivnih filtara}}\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB ocjena (uzlazno)\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Obriši aktivne filtre\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Datum izlaska (silazno)\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# aktivni filtar} few {# aktivna filtra} other {# aktivnih filtara}}\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streaming usluge\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB ocjena korisnika\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularnost (uzlazno)\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Naslov (A-Z) (uzlazno)\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Prvo emitiranje (silazno)\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Datum izlaska\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Greška pri uklanjanju klizača.\",\n  \"components.Discover.FilterSlideover.runtime\": \"Trajanje\",\n  \"components.Discover.FilterSlideover.from\": \"Od\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Naslov (Z-A) (silazno)\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularnost (silazno)\",\n  \"components.Discover.FilterSlideover.to\": \"Do\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtri\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Vidljivost\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"trajanje {minValue}-{maxValue} minuta\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Datum izlaska (uzlazno)\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB ocjena (silazno)\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB broj glasova korisnika\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Klizač uspješno uklonjen.\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Naslov (A-Z) (uzlazno)\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Naslov (Z-A) (silazno)\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Ukloni\",\n  \"components.Discover.tvgenres\": \"Žanrovi serija\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} serije\",\n  \"components.Selector.showmore\": \"Pokaži više\",\n  \"components.Selector.searchGenres\": \"Odaberi žanrove …\",\n  \"components.Selector.searchStudios\": \"Traži studija …\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB žanr serije\",\n  \"components.Selector.showless\": \"Pokaži manje\",\n  \"components.Selector.starttyping\": \"Počni tipkati za pretraživanje.\",\n  \"components.Selector.searchKeywords\": \"Traži ključne riječi …\",\n  \"components.Selector.nooptions\": \"Nema rezultata.\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB žanr filmova\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Broj glasova između {minValue} i {maxValue}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"{jobScheduleHours, plural, one {Svake sekunde} few {Svake {jobScheduleHours} sekunde} other {Svakih {jobScheduleHours} sekundi}}\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmovi\",\n  \"components.Layout.Sidebar.browsetv\": \"Serije\",\n  \"components.Discover.updatesuccess\": \"Aktualiziraj postavke za prilagođavanje otkrivanja.\",\n  \"components.Discover.updatefailed\": \"Dogodila se greška tiijekom aktualiziranja postavki za prilagođavanje otkrivanja.\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Dogodila se greška prilikom generiranja novog API ključa.\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Dogodila se greška prilikom spremanja postavki.\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Mediji koji su dodani u tvoj <PlexWatchlistSupportLink>Plex popis gledanja</PlexWatchlistSupportLink> pojavit će se ovdje.\",\n  \"components.Discover.networks\": \"Mreže\",\n  \"components.Discover.studios\": \"Studiji\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Sakrij dostupne medije\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Zvuk obavijesti\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB ključna riječ filmova\",\n  \"components.Discover.stopediting\": \"Prekini uređivanje\",\n  \"components.Discover.resetsuccess\": \"Uspješno resetiranje postavki prilagodbe otkrivanja.\",\n  \"components.Discover.customizediscover\": \"Prilagodi otkrivanje\",\n  \"components.Settings.SettingsMain.locale\": \"Jezik prikaza\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB ključna riječ serija\",\n  \"components.Discover.tmdbnetwork\": \"TMDB mreža\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Naslov programa\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Jezik otkrivanja\",\n  \"components.Discover.tmdbstudio\": \"TMDB studio\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Opće postavke\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB ocjena korisnika\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB streaming usluge za TV\",\n  \"components.Settings.SettingsMain.apikey\": \"API ključ\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Aktiviraj predmemoriranje slika\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB streaming usluge filmova\",\n  \"components.Discover.resetfailed\": \"Dogodila se greška prilikom resetiranja postavki prilagodbe otkrivanja.\",\n  \"components.Discover.tmdbsearch\": \"TMDB pretraga\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL programa\",\n  \"components.Settings.SettingsMain.general\": \"Opće\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Zvuk obavijesti\",\n  \"components.Discover.resettodefault\": \"Resetiraj na zadane vrijednosti\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Zadane postavke uređaja\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Postavke su uspješno spremljene!\",\n  \"i18n.collection\": \"Zbirka\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtriraj sadržaj po izvornom jeziku\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Predmemoriraj slike eksternih izvora (zahtijeva značajnu količinu memorije na disku)\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Sinkronizacija dostupnosti medija\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL ne smije završiti s kosom crtom\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Vrsta anime serije\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Konfiguriraj globalne i zadane postavke za Seerr.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Novi API ključ je uspješno generiran!\",\n  \"components.Settings.SonarrModal.seriesType\": \"Vrsta serije\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Zadane postavke uređaja\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Moraš navesti valjani URL\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Moraš navesti naslov programa\",\n  \"components.Discover.resetwarning\": \"Vrati sve klizače na zadane postavke. To će također izbrisati sve prilagođene klizače!\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Automatski dodaj dodatnu oznaku s korisničkim ID-om i prikaznim imenom podnositelja zahtjeva\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Automatski dodaj dodatnu oznaku s korisničkim ID-om i prikaznim imenom podnositelja zahtjeva\",\n  \"components.Discover.createnewslider\": \"Stvori novi klizač\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Dopusti djelomične zahtjeve za seriju\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Označi zahtjeve\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Označi zahtjeve\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/hu.json",
    "content": "{\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Alapértelmezett)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Ez a sorozat egy anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Haladó\",\n  \"components.RequestList.sortModified\": \"Utoljára módosítva\",\n  \"components.RequestList.sortAdded\": \"Kérés dátuma\",\n  \"components.RequestList.showallrequests\": \"Összes kérés mutatása\",\n  \"components.RequestList.requests\": \"Kérések\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Évad} other {Évad}}\",\n  \"components.RequestList.RequestItem.failedretry\": \"Hiba történt a kérés újbóli próbálásakor.\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Évad} other {Évad}}\",\n  \"components.RequestButton.viewrequest4k\": \"4K kérés megtekintése\",\n  \"components.RequestButton.viewrequest\": \"Kérés megtekintése\",\n  \"components.RequestButton.requestmore4k\": \"Továbbiak kérése 4K-ban\",\n  \"components.RequestButton.requestmore\": \"Továbbiak kérése\",\n  \"components.RequestButton.declinerequest4k\": \"4K kérés elutasítása\",\n  \"components.RequestButton.declinerequest\": \"Kérés elutasítása\",\n  \"components.RequestButton.approverequest4k\": \"4K kérés jóváhagyása\",\n  \"components.RequestButton.approverequest\": \"Kérés jóváhagyása\",\n  \"components.RequestBlock.server\": \"Cél szerver\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Évad} other {Évad}}\",\n  \"components.RequestBlock.rootfolder\": \"Gyökérmappa\",\n  \"components.RequestBlock.requestoverrides\": \"Kérések felülírása\",\n  \"components.PersonDetails.crewmember\": \"Stáb\",\n  \"components.PersonDetails.ascharacter\": \"mint {character}\",\n  \"components.PersonDetails.appearsin\": \"Szerepel a következőkben\",\n  \"components.PermissionEdit.usersDescription\": \"Engedélyt ad a Seerr-nek felhasználók kezelésére. Az ezzel az engedéllyel rendelkező felhasználók nem módosíthatják a rendszergazdai jogosultsággal rendelkező felhasználókat, és nem adhatják meg a jogosultságot más felhasználónak.\",\n  \"components.PermissionEdit.users\": \"Felhasználók kezelése\",\n  \"components.PermissionEdit.requestDescription\": \"Engedélyt ad filmek és sorozatok kérésére.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Engedélyt ad 4K-s sorozatok kérésére.\",\n  \"components.PermissionEdit.request4kTv\": \"Kérés - 4K sorozatok\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Engedélyt ad 4K-s filmek kérésére.\",\n  \"components.PermissionEdit.request4kMovies\": \"Kérés - 4K filmek\",\n  \"components.PermissionEdit.request4kDescription\": \"Engedélyt ad 4K-s filmek és sorozatok kérésére.\",\n  \"components.PermissionEdit.request4k\": \"Kérés 4K-ban\",\n  \"components.PermissionEdit.request\": \"Kérés\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Engedélyt ad a Seerr-nek a kérések kezelésére. Ez magában foglalja a kérelmek jóváhagyását és elutasítását.\",\n  \"components.PermissionEdit.managerequests\": \"Kérések kezelése\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Automatikusan jóváhagyja a felhasználó minden film kérését.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Automatikusan jóváhagyja a felhasználó minden sorozat kérését.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Sorozatok automatikus jóváhagyása\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Filmek automatikus jóváhagyása\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Automatikusan jóváhagyja a felhasználó minden kérését.\",\n  \"components.PermissionEdit.autoapprove\": \"Automatikus jóváhagyás\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Engedélyt ad a speciális kérési opciók használatára; pl. szerverek, profilok, útvonalak megváltoztatása.\",\n  \"components.PermissionEdit.advancedrequest\": \"Speciális kérések\",\n  \"components.PermissionEdit.adminDescription\": \"Teljes rendszergazdai hozzáférés. Megkerüli az összes engedélyellenőrzést.\",\n  \"components.PermissionEdit.admin\": \"Admin\",\n  \"components.MovieDetails.watchtrailer\": \"Előzetes megtekintése\",\n  \"components.MovieDetails.viewfullcrew\": \"Teljes stáblista megtekintése\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Stúdió} other {Stúdiók}}\",\n  \"components.MovieDetails.similar\": \"Hasonló tartalmak\",\n  \"components.MovieDetails.runtime\": \"{minutes} perc\",\n  \"components.MovieDetails.revenue\": \"Bevétel\",\n  \"components.MovieDetails.releasedate\": \"Megjelenés dátuma\",\n  \"components.MovieDetails.recommendations\": \"Ajánlások\",\n  \"components.MovieDetails.overviewunavailable\": \"Áttekintés nem elérhető.\",\n  \"components.MovieDetails.overview\": \"Áttekintés\",\n  \"components.MovieDetails.originallanguage\": \"Eredeti nyelv\",\n  \"components.MovieDetails.cast\": \"Szereposztás\",\n  \"components.MovieDetails.budget\": \"Költségvetés\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Teljes stáb\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Teljes szereposztás\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Még több\",\n  \"components.Login.validationpasswordrequired\": \"Meg kell adnia egy jelszót\",\n  \"components.Login.validationemailrequired\": \"Érvényes email címet kell megadnod\",\n  \"components.Login.signinwithplex\": \"Használd a Plex fiókod\",\n  \"components.Login.signinwithoverseerr\": \"Bejelentkezés {applicationTitle} fiókkal\",\n  \"components.Login.signinheader\": \"Jelentkezz be a folytatáshoz\",\n  \"components.Login.signingin\": \"Bejelentkezés…\",\n  \"components.Login.signin\": \"Bejelentkezés\",\n  \"components.Login.password\": \"Jelszó\",\n  \"components.Login.loginerror\": \"Valami nem sikerült a bejelentkezés során.\",\n  \"components.Login.email\": \"Email cím\",\n  \"components.Layout.UserDropdown.signout\": \"Kijelentkezés\",\n  \"components.Layout.Sidebar.users\": \"Felhasználók\",\n  \"components.Layout.Sidebar.settings\": \"Beállítások\",\n  \"components.Layout.Sidebar.requests\": \"Kérések\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Filmek és sorozatok keresése\",\n  \"components.Discover.upcomingmovies\": \"Hamarosan megjelenő filmek\",\n  \"components.Discover.upcoming\": \"Hamarosan megjelenő filmek\",\n  \"components.Discover.trending\": \"Felkapott\",\n  \"components.Discover.recentrequests\": \"Legutóbbi kérések\",\n  \"components.Discover.recentlyAdded\": \"Nemrég hozzáadva\",\n  \"components.Discover.populartv\": \"Népszerű sorozatok\",\n  \"components.Discover.popularmovies\": \"Népszerű filmek\",\n  \"components.CollectionDetails.requestcollection\": \"Gyűjtemény kérése\",\n  \"components.CollectionDetails.overview\": \"Áttekintés\",\n  \"components.CollectionDetails.numberofmovies\": \"Filmek száma: {count}\",\n  \"components.Search.searchresults\": \"Keresési találatok\",\n  \"components.RequestModal.selectseason\": \"Válassz évado(ka)t\",\n  \"components.RequestModal.seasonnumber\": \"{number}. évad\",\n  \"components.RequestModal.season\": \"Évad\",\n  \"components.RequestModal.requesterror\": \"Hiba történt a kérés beküldése közben.\",\n  \"components.RequestModal.requestedited\": \"Kérés a <strong>{title}</strong> szerkesztve!\",\n  \"components.RequestModal.requestcancelled\": \"Kérés a <strong>{title}</strong> -hoz/hez törölve.\",\n  \"components.RequestModal.requestadmin\": \"A kérésed azonnal el lesz fogadva.\",\n  \"components.RequestModal.numberofepisodes\": \"Epizódok száma\",\n  \"components.RequestModal.errorediting\": \"Hiba történt a kérés szerkesztése közben.\",\n  \"components.RequestModal.cancel\": \"Kérés visszavonása\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Gyökérmappa\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Minőségi profil\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Cél szerver\",\n  \"components.MovieDetails.markavailable\": \"Megjelölés elérhetőként\",\n  \"components.MovieDetails.mark4kavailable\": \"Megjelölés elérhetőként - 4K\",\n  \"components.Layout.Sidebar.dashboard\": \"Felfedezés\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Kérés elfogadásra vár\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Értesítést küld amikor a kérést nem sikerül hozzáadni a menedzser app-okhoz (Radarr/Sonarr).\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Kérés feldolgozás sikertelen\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Értesítések küldése kérések manuális elfogadásakor.\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Értesítést küld a kérések elutasításakor.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Kérés elutasítva\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Értesítést küld, amikor a kért tartalom elérhetővé válik.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Kérés elérhető\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Kérés elfogadva\",\n  \"components.RequestButton.declinerequests\": \"Visszautasítása {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.approverequests\": \"Jóváhagyás {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.approve4krequests\": \"Jóváhagyás {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.decline4krequests\": \"Visszautasítás {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"pages.returnHome\": \"Vissza a kezdőképernyőre\",\n  \"pages.oops\": \"Hupsz\",\n  \"i18n.unavailable\": \"Nem elérhető\",\n  \"i18n.tvshows\": \"Sorozatok\",\n  \"i18n.retry\": \"Újrapróbálás\",\n  \"i18n.requested\": \"Kérés elküldve\",\n  \"i18n.request\": \"Kérés\",\n  \"i18n.processing\": \"Feldolgozás alatt\",\n  \"i18n.pending\": \"Függőben lévő\",\n  \"i18n.partiallyavailable\": \"Részben elérhető\",\n  \"i18n.movies\": \"Filmek\",\n  \"i18n.failed\": \"Sikertelen\",\n  \"i18n.experimental\": \"Kísérleti\",\n  \"i18n.edit\": \"Szerkesztés\",\n  \"i18n.deleting\": \"Törlés…\",\n  \"i18n.delete\": \"Törlés\",\n  \"i18n.declined\": \"Visszautasítva\",\n  \"i18n.decline\": \"Visszautasítás\",\n  \"i18n.close\": \"Bezárás\",\n  \"i18n.cancel\": \"Mégse\",\n  \"i18n.available\": \"Elérhető\",\n  \"i18n.approved\": \"Jóváhagyva\",\n  \"i18n.approve\": \"Jóváhagyás\",\n  \"components.UserList.validationpasswordminchars\": \"A jelszó túl rövid; minimum 8 karakter hosszú kell legyen\",\n  \"components.UserList.userssaved\": \"A felhasználói engedélyeket sikeresen mentette!\",\n  \"components.UserList.userlist\": \"Felhasználók listája\",\n  \"components.UserList.userdeleteerror\": \"Hiba történt a felhasználó törlése közben.\",\n  \"components.UserList.userdeleted\": \"Felhasználó sikeresen törölve!\",\n  \"components.UserList.usercreatedsuccess\": \"Felhasználó sikeresen létrehozva!\",\n  \"components.UserList.usercreatedfailed\": \"Hiba történt a felhasználó létrehozása közben.\",\n  \"components.UserList.user\": \"Felhasználó\",\n  \"components.UserList.totalrequests\": \"Kérések\",\n  \"components.UserList.role\": \"Jogosultság\",\n  \"components.UserList.plexuser\": \"Plex felhasználó\",\n  \"components.UserList.passwordinfodescription\": \"Konfigurálja az alkalmazás URL-jét, és engedélyezze az e-mailes értesítéseket az automatikus jelszógenerálás engedélyezéséhez.\",\n  \"components.UserList.password\": \"Jelszó\",\n  \"components.UserList.localuser\": \"Helyi felhasználó\",\n  \"components.UserList.importfromplexerror\": \"Hiba történt a felhasználók Plex-ből történő importálása közben.\",\n  \"components.UserList.importfromplex\": \"Felhasználók importálása Plex-ből\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {felhasználó} other {felhasználó}} sikeresen importálva!\",\n  \"components.UserList.email\": \"E-mail-cím\",\n  \"components.UserList.deleteuser\": \"Felhasználó törlése\",\n  \"components.UserList.deleteconfirm\": \"Biztos benne, hogy törli ezt a felhasználót? A felhasználó összes adata törlődni fog.\",\n  \"components.UserList.creating\": \"Létrehozás…\",\n  \"components.UserList.createlocaluser\": \"Helyi felhasználó létrehozása\",\n  \"components.UserList.admin\": \"Adminisztrátor\",\n  \"components.UserList.created\": \"Csatlakozott\",\n  \"components.UserList.create\": \"Létrehozás\",\n  \"components.UserList.bulkedit\": \"Tömeges szerkesztés\",\n  \"components.UserList.autogeneratepassword\": \"Jelszó generálása automatikusan\",\n  \"components.TvDetails.watchtrailer\": \"Előzetes megtekintése\",\n  \"components.TvDetails.viewfullcrew\": \"Teljes stáb megtekintése\",\n  \"components.TvDetails.similar\": \"Hasonló sorozatok\",\n  \"components.TvDetails.showtype\": \"Sorozat típusa\",\n  \"components.TvDetails.recommendations\": \"Ajánlások\",\n  \"components.TvDetails.overviewunavailable\": \"Áttekintés nem elérhető.\",\n  \"components.TvDetails.overview\": \"Áttekintés\",\n  \"components.TvDetails.originallanguage\": \"Eredeti nyelv\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Hálózat} other {Hálózatok}}\",\n  \"components.TvDetails.firstAirDate\": \"Első adás dátuma\",\n  \"components.TvDetails.cast\": \"Szereposztás\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Sorozat teljes stábja\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Sorozat teljes szereposztása\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Setup.welcome\": \"Üdv a Seerr-ben\",\n  \"components.Setup.signinMessage\": \"Kezdésnek lépj be a Plex fiókoddal\",\n  \"components.Setup.finishing\": \"Befejezés…\",\n  \"components.Setup.finish\": \"Beállítás befejezése\",\n  \"components.Setup.continue\": \"Folytatás\",\n  \"components.Setup.configureservices\": \"Szolgáltatások beállítása\",\n  \"components.RequestModal.requestfrom\": \"Jelenleg van egy folyamatban lévő kérés {username} felhasználótól.\",\n  \"components.RequestModal.requestseasons\": \"{seasonCount} évad kérése\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> kérés elküldve!\",\n  \"components.RequestModal.requestCancel\": \"<strong>{title}</strong> kérése visszavonva.\",\n  \"components.RequestModal.pendingrequest\": \"Függőben lévő kérés\",\n  \"components.RequestModal.pending4krequest\": \"Függőben lévő 4K-s kérés\",\n  \"components.RequestModal.autoapproval\": \"Automatikus jóváhagyás\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Nem sikerült azonosítani a kérését. Kérem, válassza ki a megfelelő találatot az alábbi listából.\",\n  \"components.RequestBlock.profilechanged\": \"Minőségi profil\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Értesítések küldése, amikor a felhasználók olyan új médiakéréseket nyújtanak be, amiknél elfogadásra van szükség.\",\n  \"components.PermissionEdit.viewrequests\": \"Kérések megtekintése\",\n  \"components.Discover.discover\": \"Felfedezés\",\n  \"components.Login.forgotpassword\": \"Elfelejtett jelszó?\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Új jelszót kell megadnia\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Meg kell adnia az aktuális jelszavát\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"A jelszavaknak meg kell egyezniük\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Meg kell erősítenie az új jelszót\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Jelszó sikeresen mentve!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Valami elromlott a jelszó mentése közben. Helyesen adta meg a jelenlegi jelszavát?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Hiba történt a jelszó mentése közben.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Jelszó\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Nincs jogosultsága a felhasználó jelszavának módosítására.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Az Ön fiókjához jelenleg nincs jelszó beállítva. Állítson be egy jelszót az alábbiakban, hogy \\\"helyi felhasználóként\\\" bejelentkezhessen az e-mail címét használva.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Ehhez a felhasználói fiókhoz jelenleg nincs jelszó beállítva. Az alábbiakban konfiguráljon jelszót, hogy ez a fiók \\\"helyi felhasználóként\\\" bejelentkezhessen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Új jelszó\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Jelenlegi jelszó\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Jelszó megerősítése\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Meg kell adnia egy érvényes chat azonosítót\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Érvényes PGP- kulcsot kell megadnia\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Érvényes felhasználói azonosítót kell megadnia\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram értesítés beállítások mentése sikeres!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"A Telegram-értesítés beállításait nem sikerült elmenteni.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Csevegés indítása</TelegramBotLink>, <GetIdBotLink>@get_id_bot</GetIdBotLink> hozzáadása, és a <code>/my_id</code> parancs kiadása\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chat ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Értesítések küldése hang nélkül\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Küldés csendben\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"E-mail üzenetek titkosítása az <OpenPgpLink>OpenPGP</OpenPgpLink> használatával\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"PGP nyilvános kulcs\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Értesítési beállítások\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Értesítések\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Az e-mail értesítések beállításai sikeresen mentésre kerültek!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Az e-mail értesítés beállításait nem sikerült elmenteni.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord értesítés beállítások sikeresen mentve!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"A Discord értesítés beállításait nem sikerült elmenteni.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"A felhasználói fiók <FindDiscordIdLink>azonosítószáma</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Felhasználói azonosító\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Felhasználó\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"A beállítások sikeresen mentve!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Valami elromlott a beállítások mentése közben.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Sorozatkérési limit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Jogosultság\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"A tartalom szűrése a regionális elérhetőség szerint\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Felfedezés régiója\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex felhasználó\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Tulajdonos\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Tartalom szűrése eredeti nyelv szerint\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Nyelv felfedezése\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Filmkérési limit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Helyi felhasználó\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Alap ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Általános beállítások\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Általános\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Globális korlát felülírása\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Megjelenített név\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Megjelenítési nyelv\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Admin\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Fiók típus\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Felhasználói azonosító: {userid}\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Beállítások szerkesztése\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Profil megtekintése\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Csatlakozott: {joindate}\",\n  \"components.UserList.validationEmail\": \"Érvényes email cím szükséges\",\n  \"components.UserList.users\": \"Felhasználók\",\n  \"components.UserList.userfail\": \"Valami hiba történt a felhasználói jogosultságok mentése közben.\",\n  \"components.UserList.usercreatedfailedexisting\": \"A megadott e-mail címet már egy másik felhasználó használja.\",\n  \"components.UserList.sortRequests\": \"Kérések száma\",\n  \"components.UserList.sortDisplayName\": \"Megjelenített név\",\n  \"components.UserList.sortCreated\": \"Létrehozás dátuma\",\n  \"components.UserList.owner\": \"Tulajdonos\",\n  \"components.UserList.nouserstoimport\": \"Nincs importálható új felhasználó a Plexből.\",\n  \"components.UserList.localLoginDisabled\": \"A <strong>Helyi bejelentkezés engedélyezése</strong> beállítás jelenleg le van tiltva.\",\n  \"components.UserList.edituser\": \"Felhasználói engedélyek szerkesztése\",\n  \"components.UserList.autogeneratepasswordTip\": \"A szerver által generált jelszó elküldése e-mailben a felhasználónak\",\n  \"components.UserList.accounttype\": \"Típus\",\n  \"components.TvDetails.originaltitle\": \"Eredeti cím\",\n  \"components.TvDetails.nextAirDate\": \"Következő adás dátuma\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} perc\",\n  \"components.Setup.setup\": \"Beállítás\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.webAppUrlTip\": \"Opcionálisan átirányíthatja a felhasználókat a szerveren lévő webes alkalmazáshoz a \\\"hosztolt\\\" webes alkalmazás helyett\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Web App</WebAppLink> URL\",\n  \"components.Settings.validationPortRequired\": \"Érvényes portszámot kell megadnia\",\n  \"components.Settings.validationHostnameRequired\": \"Érvényes hosztnevet vagy IP-címet kell megadnia\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Plex szerverlista sikeresen lekérdezve!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Nem sikerült lekérni a Plex szerverek listáját.\",\n  \"components.Settings.toastPlexRefresh\": \"Szerverlista lekérése a Plexből…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"A Plex kapcsolat sikeresen létrejött!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Nem sikerült csatlakozni a Plexhez.\",\n  \"components.Settings.toastPlexConnecting\": \"Csatlakozási kísérlet a Plexhez …\",\n  \"components.Settings.startscan\": \"Szkennelés indítása\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.sonarrsettings\": \"Sonarr beállítások\",\n  \"components.Settings.settingUpPlexDescription\": \"A Plex beállításához megadhatja kézzel az adatokat, vagy kiválaszthat egy <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>-ről elérhető szervert. Nyomja meg a legördülő menü jobb oldalán lévő gombot az elérhető szerverek listájának lekérdezéséhez.\",\n  \"components.Settings.services\": \"Szolgáltatások\",\n  \"components.Settings.serviceSettingsDescription\": \"Az alábbiakban beállíthatja a {serverType} szerver(eke)t. Több {serverType} szervert is csatlakoztathat, de ezek közül csak kettő jelölhető meg alapértelmezettként (egy nem 4K és egy 4K). A rendszergazdák felülbírálhatják az új kérések feldolgozásához használt szervert a jóváhagyás előtt.\",\n  \"components.Settings.serverpresetRefreshing\": \"Szerverek lekérése…\",\n  \"components.Settings.serverpresetManualMessage\": \"Kézi beállítás\",\n  \"components.Settings.serverpresetLoad\": \"Nyomja meg a gombot az elérhető szerverek betöltéséhez\",\n  \"components.Settings.serverpreset\": \"Szerver\",\n  \"components.Settings.serverSecure\": \"biztonságos\",\n  \"components.Settings.serverRemote\": \"távoli\",\n  \"components.Settings.serverLocal\": \"helyi\",\n  \"components.Settings.scanning\": \"Szinkronizálás…\",\n  \"components.Settings.scan\": \"Könyvtárak szinkronizálása\",\n  \"components.Settings.radarrsettings\": \"Radarr beállítások\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.plexsettingsDescription\": \"A Plex szerver beállításainak konfigurálása. A Seerr a Plex könyvtárakat vizsgálja a tartalom elérhetőségének meghatározásához.\",\n  \"components.Settings.plexsettings\": \"Plex beállítások\",\n  \"components.Settings.plexlibrariesDescription\": \"A Seerr által átvizsgált könyvtárak. Állítsa be és mentse el a Plex kapcsolati beállításokat, majd kattintson az alábbi gombra, ha nincsenek könyvtárak.\",\n  \"components.Settings.plexlibraries\": \"Plex könyvtárak\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notrunning\": \"Nem fut\",\n  \"components.Settings.notificationsettings\": \"Értesítési beállítások\",\n  \"components.Settings.notifications\": \"Értesítések\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Értesítési ügynökök konfigurálása és engedélyezése.\",\n  \"components.Settings.noDefaultServer\": \"Legalább egy {serverType} szervert meg kell jelölni alapértelmezettként a {mediaType} kérések feldolgozásához.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Ha csak egyetlen {serverType} szervert használmind a nem 4K, mind a 4K tartalomhoz (vagy ha csak 4K tartalmat tölt le), akkor a {serverType} szervert <strong> NEM </strong> kell 4K szerverként kijelölni.\",\n  \"components.Settings.noDefault4kServer\": \"A 4K {serverType} szervert alapértelmezettként kell megjelölni, hogy a felhasználók 4K {mediaType} kéréseket nyújthassanak be.\",\n  \"components.Settings.menuUsers\": \"Felhasználók\",\n  \"components.Settings.menuServices\": \"Szolgáltatások\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Értesítések\",\n  \"components.Settings.menuLogs\": \"Naplók\",\n  \"components.Settings.menuJobs\": \"Feladatok és gyorsítótár\",\n  \"components.Settings.menuGeneralSettings\": \"Általános\",\n  \"components.Settings.menuAbout\": \"Az oldalról\",\n  \"components.Settings.mediaTypeSeries\": \"sorozat\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.manualscanDescription\": \"Normális esetben ez csak 24 óránként egyszer fut le. A Seerr agresszívebben ellenőrzi a Plex szerver \\\"nemrégiben hozzáadottakat\\\" könyvtárat. Ha ez az első alkalom a Plex konfigurálásában, egyszeri teljes kézi könyvtárellenőrzés ajánlott!\",\n  \"components.Settings.manualscan\": \"Kézi könyvtári beolvasás\",\n  \"components.Settings.librariesRemaining\": \"Fennmaradó könyvtárak: {count}\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.enablessl\": \"SSL használata\",\n  \"components.Settings.email\": \"E-mail\",\n  \"components.Settings.deleteserverconfirm\": \"Biztos, hogy törölni szeretné ezt a szervert?\",\n  \"components.Settings.default4k\": \"Alapértelmezett 4K\",\n  \"components.Settings.default\": \"Alapértelmezett\",\n  \"components.Settings.currentlibrary\": \"Jelenlegi könyvtár: {name}\",\n  \"components.Settings.cancelscan\": \"Beolvasás megszakítása\",\n  \"components.Settings.addsonarr\": \"Sonarr szerver hozzáadása\",\n  \"components.Settings.address\": \"Cím\",\n  \"components.Settings.addradarr\": \"Radarr szerver hozzáadása\",\n  \"components.Settings.activeProfile\": \"Aktív profil\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Ki kell választania egy root mappát\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Ki kell választania egy minőségi profilt\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Érvényes portszámot kell megadnia\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Meg kell adnia a szerver nevét\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Ki kell választania egy nyelvi profilt\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Érvényes hosztnevet vagy IP-címet kell megadnia\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Az alap URL-nek nem lehet vége perjel\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Az alap-URL-nek tartalmaznia kell egy perjelet\",\n  \"components.Settings.SonarrModal.server4k\": \"4K szerver\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"Az URL-nek nem lehet vége perjel\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Érvényes URL-t kell megadnia\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Meg kell adnia egy API-kulcsot\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr kapcsolat sikeresen létrejött!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Nem sikerült csatlakozni a Sonarrhoz.\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Tesztelje a kapcsolatot a címkék betöltéséhez\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Kapcsolat tesztelése a root mappák betöltéséhez\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Kapcsolat teszt a minőségi profilok betöltéséhez\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Kapcsolat tesztelése a nyelvi profilok betöltéséhez\",\n  \"components.Settings.SonarrModal.tags\": \"Cimkék\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Szkennelés engedélyezése\",\n  \"components.Settings.SonarrModal.ssl\": \"SSL használata\",\n  \"components.Settings.SonarrModal.servername\": \"Szerver név\",\n  \"components.Settings.SonarrModal.selecttags\": \"Cimkék kiválasztása\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Válassza ki a root mappát\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Válassza ki a minőségi profilt\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Válassza ki a nyelvi profilt\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Évad mappák\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Globális filmkérési limit\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Lehetővé teszi a felhasználók számára, hogy e-mail címükkel és jelszavukkal jelentkezzenek be\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Helyi bejelentkezés engedélyezése\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Az új felhasználókhoz rendelt kezdeti jogosultságok\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Alapértelmezett engedélyek\",\n  \"components.Settings.SettingsLogs.time\": \"Időbélyegző\",\n  \"components.Settings.SettingsLogs.showall\": \"Minden napló megjelenítése\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Folytatás\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Szünet\",\n  \"components.Settings.SettingsLogs.message\": \"Üzenet\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Ezeket a naplókat közvetlenül a <code>stdout</code>-on keresztül vagy az <code>{appDataPath}/logs/seerr.log</code>-ben is megtekintheti.\",\n  \"components.Settings.SettingsLogs.logs\": \"Naplók\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Napló részletei\",\n  \"components.Settings.SettingsLogs.level\": \"Súlyosság\",\n  \"components.Settings.SettingsLogs.label\": \"\\\"Címke\\\"\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Figyelmeztetés\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Infó\",\n  \"components.Settings.SettingsLogs.filterError\": \"Hiba\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Hibakeresés (Debug)\",\n  \"components.Settings.SettingsLogs.extraData\": \"Kiegészítő adatok\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Másolás a vágólapra\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Naplóüzenet másolása a vágólapra.\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Ismeretlen feladat\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr szkennelés\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Futtatás most\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr szkennelés\",\n  \"components.Settings.SettingsJobsCache.process\": \"Folyamat\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plex \\\"nemrégiben hozzáadott\\\" beolvasása\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plex összes könyvtárának beolvasása\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Jellyfin összes könyvtárának beolvasása\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Jellyfin \\\"nemrégiben hozzáadott\\\" beolvasása\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Következő végrehajtás\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Típus\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} elindult.\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Feladatok és gyorsítótár\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"A Seerr bizonyos karbantartási feladatokat rendszeresen ütemezett feladatként végez, de ezeket az alábbiakban kézzel is elindíthatja. Egy feladat kézi futtatása nem változtatja meg annak ütemezését.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Feladatok\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Feladat neve\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} megszakítva.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Gyorsítótár ürítése\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Letöltési szinkron visszaállítása\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Letöltési szinkron\",\n  \"components.Settings.SettingsJobsCache.command\": \"Parancs\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Feladat megszakítása\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Érték Méret\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Gyorsítótár neve\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Hiányzók\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Kulcsméret\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Összes \\\"API lékérés\\\"\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Találatok\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"A {cachename} gyorsítótár kiürült.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"A Seerr a külső API végpontokhoz intézett kéréseket gyorsítótárba helyezi a teljesítmény optimalizálása és a felesleges API-hívások elkerülése érdekében.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Gyorsítótár\",\n  \"components.Settings.SettingsAbout.version\": \"Verzió\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Naprakész\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Összes kérés\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Teljes média\",\n  \"components.Settings.SettingsAbout.timezone\": \"Időzóna\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Lejárt\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub‑beszélgetések\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Támogatás kérése\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentáció\",\n  \"components.Settings.SettingsAbout.about\": \"Az oldalról\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Megtekintés a GitHubon\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Változásnapló megtekintése\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Verzió változásnapló\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Kiadások\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Megjelenési adatok nem állnak rendelkezésre.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Legújabb\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Jelenlegi\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Ki kell választania egy root mappát\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Ki kell választania egy minőségi profilt\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Érvényes portszámot kell megadnia\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Meg kell adnia a szerver nevét\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Ki kell választania egy minimális elérhetőséget\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Érvényes hosztnevet vagy IP-címet kell megadnia\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Az URL alapja nem végződhet perjelre\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Az alap URL-nek perjellel kell végződnie\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"Az URL-nek nem lehet vége perjel\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Érvényes URL-t kell megadnia\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Meg kell adnia egy API-kulcsot\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"A Radarr kapcsolat sikeresen létrejött!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Nem sikerült csatlakozni a Radarrhoz.\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Tesztelje a kapcsolatot a címkék betöltéséhez\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Kapcsolat tesztelése a gyökérmappák betöltéséhez\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Kapcsolat teszt a minőségi profilok betöltéséhez\",\n  \"components.Settings.RadarrModal.tags\": \"Cimkék\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Szkennelés engedélyezése\",\n  \"components.Settings.RadarrModal.ssl\": \"SSL használata\",\n  \"components.Settings.RadarrModal.servername\": \"Szerver név\",\n  \"components.Settings.RadarrModal.server4k\": \"4K szerver\",\n  \"components.Settings.RadarrModal.selecttags\": \"Cimkék kiválasztása\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Válassza ki a root mappát\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Válassza ki a minőségi profilt\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Válassza ki a minimális elérhetőséget\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Gyökérmappa\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Minőségi profil\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Nincsenek címkék.\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimális elérhetőség\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Gyökérmappák betöltése …\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Minőségi profilok betöltése…\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Címkék betöltése…\",\n  \"components.Settings.RadarrModal.hostname\": \"Hosztnév vagy IP-cím\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Külső URL\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Engedélyezze az automatikus keresést\",\n  \"components.Settings.RadarrModal.editradarr\": \"Radarr szerver szerkesztése\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"A 4K-s Radarr szerver szerkesztése\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Alapértelmezett szerver\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Alapértelmezett 4K szerver\",\n  \"components.Settings.RadarrModal.createradarr\": \"Új Radarr szerver hozzáadása\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Új 4K Radarr szerver hozzáadása\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL-alap\",\n  \"components.Settings.RadarrModal.apiKey\": \"API kulcs\",\n  \"components.Settings.RadarrModal.add\": \"Szerver hozzáadása\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Hozzon létre egy <DiscordWebhookLink>webhook integrációt</DiscordWebhookLink> a Discord szerverén\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook URL-cím\",\n  \"components.Settings.Notifications.validationUrl\": \"Érvényes URL-t kell megadnia\",\n  \"components.Settings.Notifications.validationTypes\": \"Legalább egy értesítési típust ki kell választania\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Érvényes portszámot kell megadnia\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Érvényes hosztnevet vagy IP-címet kell megadnia\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Meg kell adnia egy érvényes PGP privát kulcsot\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"PGP-jelszót kell megadnia\",\n  \"components.Settings.Notifications.validationEmail\": \"Érvényes email címet kell megadnod\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Meg kell adnia egy érvényes chat azonosítót\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Meg kell adnia egy botengedélyezési tokent\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram teszt értesítés elküldve!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Telegram teszt értesítés küldése…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"A Telegram tesztértesítés elküldése sikertelen volt.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Email teszt értesítés elküldve!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Email teszt értesítés küldése…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Az e-mailes tesztértesítés nem sikerült elküldeni.\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord teszt értesítés elküldve!\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Discord teszt értesítés küldése …\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"A Discord tesztértesítés nem sikerült elküldeni.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram értesítés beállítások mentése sikeresen!\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"A Telegram-értesítés beállításait nem sikerült elmenteni.\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP port\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP Hoszt\",\n  \"components.Settings.Notifications.senderName\": \"Küldő neve\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Értesítések küldése hang nélkül\",\n  \"components.Settings.Notifications.sendSilently\": \"Küldés csendben\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Titkosított e-mail üzenetek aláírása az <OpenPgpLink>OpenPGP</OpenPgpLink> segítségével\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP privát kulcs\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {kérés} other {kérés}} maradt\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Titkosított e-mail üzenetek aláírása az <OpenPgpLink>OpenPGP</OpenPgpLink> segítségével\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP jelszó\",\n  \"components.Settings.Notifications.encryptionTip\": \"A legtöbb esetben az Implicit TLS a 465-ös portot, a STARTTLS pedig az 587-es portot használja\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Mindig használja a STARTTLS-t\",\n  \"components.Settings.Notifications.encryptionNone\": \"Nincs\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Használja az Implicit TLS-t\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Használja a STARTTLS-t, ha rendelkezésre áll\",\n  \"components.Settings.Notifications.encryption\": \"Titkosítási módszer\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Az e-mail értesítések beállításai sikeresen mentésre kerültek!\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Az e-mail értesítés beállításait nem sikerült elmenteni.\",\n  \"components.Settings.Notifications.emailsender\": \"Feladó címe\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord értesítés beállítások sikeresen mentve!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"A Discord értesítés beállításait nem sikerült elmenteni.\",\n  \"components.Settings.Notifications.chatIdTip\": \"Indítson egy csevegést a botjával, adja hozzá a <GetIdBotLink>@get_id_bot</GetIdBotLink>, és adja ki a <code>/my_id</code> parancsot\",\n  \"components.Settings.Notifications.chatId\": \"Chat ID\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Lehetővé teszi a felhasználók számára, hogy csevegést indítsanak az ön bot-jával, és beállíthatják saját értesítéseiket\",\n  \"components.Settings.Notifications.botUsername\": \"Bot felhasználónév\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Bot Avatar URL-je\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Hozzon létre egy botot</CreateBotLink> a Seerrrel való használathoz\",\n  \"components.Settings.Notifications.botAPI\": \"Bot engedélyezési token\",\n  \"components.Settings.Notifications.authUser\": \"SMTP felhasználónév\",\n  \"components.Settings.Notifications.authPass\": \"SMTP jelszó\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Önaláírt tanúsítványok engedélyezése\",\n  \"components.Settings.Notifications.agentenabled\": \"Ügynök engedélyezése\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Webhook értesítés beállításai sikeresen mentve!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"A Webhook-értesítés beállításait nem sikerült elmenteni.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook URL-je\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Érvényes URL-t kell megadnia\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Legalább egy értesítési típust ki kell választania\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Meg kell adnia egy érvényes JSON payload-t\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook teszt értesítés elküldve!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Webhook teszt értesítés küldése …\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"A webhook tesztértesítés elküldése sikertelen volt.\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Sablonváltozó súgó\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON payload visszaállítása sikeresen!\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Nincsenek címkék.\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Évad} other {# Évad}}\",\n  \"i18n.showingresults\": \"Eredmények megjelenítése <strong>{from}</strong>-tól/től <strong>{to}</strong>-ig <strong>{total}</strong>-ból/ből\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {évad} other {évad}}\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Az Ön 30 karakteres <UsersGroupsLink>felhasználó vagy csoport azonosítója</UsersGroupsLink>\",\n  \"components.UserProfile.pastdays\": \"{type} (elmúlt {days} nap)\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Általános\",\n  \"components.TvDetails.episodeRuntime\": \"Epizód hossza\",\n  \"components.Settings.hostname\": \"Hosztnév vagy IP-cím\",\n  \"pages.somethingwentwrong\": \"Valami hiba történt\",\n  \"pages.serviceunavailable\": \"A szolgáltatás nem elérhető\",\n  \"pages.pagenotfound\": \"Oldal nem található\",\n  \"pages.internalservererror\": \"Belső kiszolgálóhiba\",\n  \"i18n.view\": \"Nézet\",\n  \"i18n.usersettings\": \"Felhasználói beállítások\",\n  \"i18n.tvshow\": \"Sorozat\",\n  \"i18n.testing\": \"Tesztelés…\",\n  \"i18n.test\": \"Teszt\",\n  \"i18n.status\": \"Állapot\",\n  \"i18n.settings\": \"Beállítások\",\n  \"i18n.saving\": \"Mentés…\",\n  \"i18n.save\": \"Változások mentése\",\n  \"i18n.retrying\": \"Újrapróbálkozás…\",\n  \"i18n.resultsperpage\": \"{pageSize} eredmény megjelenítése oldalanként\",\n  \"i18n.requesting\": \"Kérés folyamatban…\",\n  \"i18n.request4k\": \"Kérés 4K-ban\",\n  \"i18n.previous\": \"Előző\",\n  \"i18n.notrequested\": \"Nincs kérve\",\n  \"i18n.noresults\": \"Nincs találat.\",\n  \"i18n.next\": \"Következő\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.loading\": \"Betöltés…\",\n  \"i18n.canceling\": \"Visszavonás…\",\n  \"i18n.back\": \"Vissza\",\n  \"i18n.areyousure\": \"Biztos vagy benne?\",\n  \"i18n.all\": \"Mind\",\n  \"i18n.advanced\": \"Haladó\",\n  \"components.UserProfile.unlimited\": \"Korlátlan\",\n  \"components.UserProfile.totalrequests\": \"Összes kérés\",\n  \"components.UserProfile.seriesrequest\": \"Sorozatkérések\",\n  \"components.UserProfile.requestsperdays\": \"{limit} maradt\",\n  \"components.UserProfile.recentrequests\": \"Legutóbbi kérések\",\n  \"components.UserProfile.movierequests\": \"Filmkérések\",\n  \"components.UserProfile.limit\": \"{remaining} a {limit}-ből\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Nincs jogosultsága a felhasználó beállításainak módosítására.\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Jogosultságok\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Értesítések\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Jelszó\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"A saját jogosultságait nem módosíthatja.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"A jogosultságok sikeresen mentve!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Valami elromlott a beállítások mentése közben.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Jogosultságok\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"A jelszó túl rövid; minimum 8 karakter hosszú legyen\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Alapértelmezettre visszaállítása\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON adatcsomag\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Engedélyezési fejléc\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Ügynök engedélyezése\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"A webes push-értesítés beállításai sikeresen mentésre kerültek!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"A webes push-értesítés beállításait nem sikerült elmenteni.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Web push teszt értesítés elküldve!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Web push teszt értesítés küldése…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"A webes push tesztértesítés elküldése sikertelen volt.\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"A webes push-értesítések fogadásához a Seerr-nek HTTPS-en keresztül kell működnie.\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Ügynök engedélyezése\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Hozzon létre egy <WebhookLink>bejövő webhook</WebhookLink> integrációt\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook URL-je\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Érvényes URL-t kell megadnia\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Legalább egy értesítési típust ki kell választania\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack teszt értesítés elküldve!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Slack teszt értesítés küldése…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"A Slack tesztértesítés elküldése sikertelen volt.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack értesítés beállításai sikeresen mentve!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"A Slack értesítés beállításait nem sikerült elmenteni.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Érvényes alkalmazási tokent kell megadnia\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Ennek a felhasználónak legalább <strong>{seasons}</strong> fennmaradó évadkérelemmel kell rendelkeznie ahhoz, hogy kérés nyújthasson be ehhez a sorozathoz.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Legalább <strong>{seasons}</strong> fennmaradó évadkérelemmel kell rendelkeznie ahhoz, hogy kérés nyújthasson be ehhez a sorozathoz.\",\n  \"components.RequestModal.pendingapproval\": \"Kérése jóváhagyásra vár.\",\n  \"components.RequestModal.edit\": \"Kérés szerkesztése\",\n  \"components.RequestModal.alreadyrequested\": \"Már kérve\",\n  \"components.RequestModal.QuotaDisplay.season\": \"évad\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"A kérelmek korlátozásainak összefoglalóját a <ProfileLink>profil odlalon</ProfileLink> megtekintheti.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"A kérelmek korlátozásainak összefoglalóját a <ProfileLink>profil oldalon</ProfileLink> megtekintheti.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Nem maradt elég szezon kérés\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {film}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Ennek a felhasználónak <strong>{limit}</strong> {type} kérése van minden <strong>{days}</strong> naponta.\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Cimkék kiválasztása\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Cimkék\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Kérve mint\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Nyelvprofil\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Kérve\",\n  \"components.RequestList.RequestItem.requested\": \"Kérve\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} {user} által\",\n  \"components.RequestList.RequestItem.modified\": \"Módosított\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} Nem található\",\n  \"components.RequestList.RequestItem.editrequest\": \"Kérés szerkesztése\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Kérés törlése\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Kérés visszavonása\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} nem található\",\n  \"components.RequestCard.failedretry\": \"Hiba történt a kérés újbóli próbálásakor.\",\n  \"components.RequestCard.deleterequest\": \"Kérés törlése\",\n  \"components.RegionSelector.regionServerDefault\": \"Alap ({region})\",\n  \"components.RegionSelector.regionDefault\": \"Minden régió\",\n  \"components.QuotaSelector.unlimited\": \"Korlátlan\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {évad} other {évad}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {film}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {nap} other {nap}}\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Született\",\n  \"components.PersonDetails.alsoknownas\": \"Úgy is ismert mint : {names}\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Engedélyt ad a többi felhasználó kérésének megtekintésére.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Engedélyt ad nem 4k-s sorozatok kéréséhez.\",\n  \"components.PermissionEdit.requestTv\": \"Sorozatok kérése\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Engedélyt ad nem 4K-s filmek igényléséhez.\",\n  \"components.PermissionEdit.requestMovies\": \"Filmek kérése\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Automatikus elfogadást biztosít 4k sorozat kérésekhez.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Automatikus jóváhagyás 4k sorozatok\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Adjon automatikus jóváhagyást a 4K-s filmkérelmekhez.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"4K filmek automatikus jóváhagyása\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Automatikus jóváhagyás biztosítása minden 4K kérelemhez.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Automatikus jóváhagyás 4k\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Értesítést kap, ha más felhasználók új médiakéréseket nyújtanak be, amelyek jóváhagyást igényelnek.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Értesítést kap, ha a média kéréseket nem sikerült hozzáadni a Radarrhoz vagy a Sonarrhoz.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Értesítést kap, amikor a média kérését visszautasították.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Értesítést kap, amikor elérhetővé válnak a kérései.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Értesítést kap, ha a média kérelmeket jóváhagyják.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Értesítést kap, amikor más felhasználók új médiakéréseket nyújtanak be, amelyeket a rendszer automatikusan jóváhagy.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Értesítési típusok\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Értesítések küldése amikor a felhasználók olyan új média kéréseket nyújtanak be, amelyek automatikusan jóvá vannak hagyva.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Kérés automatikusan jóváhagyva\",\n  \"components.MovieDetails.showmore\": \"Mutass többet\",\n  \"components.MovieDetails.showless\": \"Mutass kevesebbet\",\n  \"components.MovieDetails.originaltitle\": \"Eredeti cím\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr stabil verzió\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr fejlesztői verzió\",\n  \"components.Layout.VersionStatus.outofdate\": \"Lejárt\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} mögött\",\n  \"components.Layout.UserDropdown.settings\": \"Beállítások\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Megjelenítési nyelv\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Minden nyelv\",\n  \"components.LanguageSelector.languageServerDefault\": \"Alap ({language})\",\n  \"components.DownloadBlock.estimatedtime\": \"Becsült {time}\",\n  \"components.Discover.upcomingtv\": \"Hamarosan megjelenő sorozatok\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Sorozat műfajok\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Sorozat műfajok\",\n  \"components.Discover.StudioSlider.studios\": \"Stúdiók\",\n  \"components.Discover.NetworkSlider.networks\": \"Hálózatok\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Filmműfajok\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Filmműfajok\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Sorozatok\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Sorozatok\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} Filmek\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} Sorozat\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Filmek\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} Filmek\",\n  \"components.CollectionDetails.requestcollection4k\": \"Gyűjtemény kérése 4k-ban\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"A <code>{appDataPath}</code> kötet nincs megfelelően csatlakoztatva. A tároló leállításakor vagy újraindításakor minden adat törlődik.\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Gyökérmappa\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Minőségi profil\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Nincsenek címkék.\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Gyökérmappák betöltése …\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Minőségi profilok betöltése…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Nyelvi profilok betöltése …\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Címkék betöltése…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Nyelvprofil\",\n  \"components.Settings.SonarrModal.hostname\": \"Hosztnév vagy IP-cím\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Külső URL\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Engedélyezze az automatikus keresést\",\n  \"components.Settings.SonarrModal.editsonarr\": \"A Sonarr szerver szerkesztése\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"A 4K-s Sonarr szerver szerkesztése\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Alapértelmezett szerver\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Alapértelmezett 4K szerver\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Új Sonarr szerver hozzáadása\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Új 4K Sonarr szerver hozzáadása\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL-alap\",\n  \"components.Settings.SonarrModal.apiKey\": \"API-kulcs\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime root mappa\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime minőség profil\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime nyelvi profil\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime címkék\",\n  \"components.Settings.SonarrModal.add\": \"Szerver hozzáadása\",\n  \"components.Settings.SettingsUsers.users\": \"Felhasználók\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Globális és alapértelmezett felhasználói beállítások konfigurálása.\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Felhasználói beállítások\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Globális sorozat kérési limit\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"A felhasználói beállítások sikeresen mentve!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Valami elromlott a beállítások mentése közben.\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Lehetővé teszi a {mediaServerName} felhasználók számára, hogy első importálás nélkül jelentkezzenek be\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Engedélyezze az új {mediaServerName} bejelentkezést\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} per {quotaDays} {days}</quotaUnits>\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Napi <strong>{limit}</strong> {type} kérés engedélyezett minden <strong>{days}</strong> naponta.\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Ügynök engedélyezése\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Meg kell adnia egy érvényes felhasználói vagy csoportos kulcsot\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Legalább egy értesítési típust ki kell választania\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Felhasználói vagy csoportkulcs\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover teszt értesítés elküldve!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Pushover teszt üzenet küldése …\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover tesztüzenet elküldése nem sikerült.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover értesítési beállítások sikeresen mentve!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushover az értesítési beállításokat nem sikerült menteni.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Ügynök engedélyezése\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Alkalmazás regisztrálása</ApplicationRegistrationLink> a Seerr használatára\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Alkalmazás API Token\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Legalább egy értesítési típust ki kell választania\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Meg kell adnia egy hozzáférési tokent (acces token)\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Elküldtük a Pushbullet teszt értesítését!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Pushbullet teszt értesítés küldése …\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"A pushbullet teszt értesítését nem sikerült elküldeni.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"A Pushbullet értesítési beállításainak mentése sikeresen megtörtént!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"A Pushbullet értesítési beállításainak mentése nem sikerült.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Ügynök engedélyezése\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Hozzon létre egy Tokent a <PushbulletSettingsLink>Fiók beállításokba</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Hozzáférési Token (Access Token)\",\n  \"components.Search.search\": \"Keresés\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Meg kell adnia egy jelszót\",\n  \"components.ResetPassword.validationpasswordminchars\": \"A jelszó túl rövid; minimum 8 karakter hosszú legyen\",\n  \"components.ResetPassword.validationpasswordmatch\": \"a jelszavaknak egyezniük kell\",\n  \"components.ResetPassword.validationemailrequired\": \"Meg kell adnia egy érvényes e-mail címet\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"A jelszó visszaállítása sikeres volt!\",\n  \"components.ResetPassword.resetpassword\": \"Jelszó visszaállítása\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Jelszó-visszaállító linket küldünk a megadott e-mail címre, ha az érvényes felhasználóhoz van társítva.\",\n  \"components.ResetPassword.passwordreset\": \"Jelszó visszaállítás\",\n  \"components.ResetPassword.password\": \"Jelszó\",\n  \"components.ResetPassword.gobacklogin\": \"Vissza a bejelentkező lapra\",\n  \"components.ResetPassword.emailresetlink\": \"Email visszaállítási link\",\n  \"components.ResetPassword.email\": \"Email cím\",\n  \"components.ResetPassword.confirmpassword\": \"Jelszó megerősítése\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.closeissue\": \"Probléma lezárása\",\n  \"components.IssueDetails.closeissueandcomment\": \"Lezárás hozzászólással\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Valami hiba történt a probléma elküldése során.\",\n  \"components.IssueDetails.play4konplex\": \"Lejátszás 4K-ban {mediaServerName}-n\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Probléma megtekintése\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Ez visszafordíthatatlanul eltávolítja az összes adatot ehhez a {mediaType}-hez, beleértve a kéréseket is. Ha ez az elem létezik a {mediaServerName} könyvtárában, a médiainformáció a következő beolvasás során újra létrejön.\",\n  \"components.IssueDetails.commentplaceholder\": \"Hozzászólás írása…\",\n  \"components.IssueDetails.comments\": \"Hozzászólások\",\n  \"components.IssueDetails.deleteissue\": \"Probléma törlése\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Biztos, hogy ki akarja törölni ezt a problémát?\",\n  \"components.IssueDetails.episode\": \"{episodeNumber}. Epizód\",\n  \"components.IssueDetails.issuepagetitle\": \"Probléma\",\n  \"components.IssueDetails.issuetype\": \"Típus\",\n  \"components.IssueDetails.lastupdated\": \"Utoljára frissítve\",\n  \"components.IssueDetails.leavecomment\": \"Hozzászólás\",\n  \"components.IssueDetails.nocomments\": \"Nincsenek hozzászólások.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} bejelentve {relativeTime} {username} által\",\n  \"components.IssueDetails.openin4karr\": \"Megnyitás 4K-ban itt: {arr}\",\n  \"components.IssueDetails.playonplex\": \"Lejátszás {mediaServerName}-n\",\n  \"components.IssueDetails.problemepisode\": \"Érintett epizód\",\n  \"components.IssueDetails.problemseason\": \"Érintett évad\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Újranyitás hozzászólással\",\n  \"components.IssueDetails.season\": \"{seasonNumber}. Évad\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"A probléma leírása sikeresen szerkesztve!\",\n  \"components.IssueDetails.toaststatusupdated\": \"A probléma állapota sikeresen frissítve!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Valami hiba történt a probléma állapotának frissítése közben.\",\n  \"components.IssueList.IssueItem.issuetype\": \"Típus\",\n  \"components.IssueList.IssueItem.opened\": \"Bejelentve\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} {user} által\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Érintett epizód\",\n  \"components.IssueList.showallissues\": \"Minden probléma mutatása\",\n  \"components.IssueList.sortModified\": \"Utoljára módosítva\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Minden epizód\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Minden évad\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"{episodeNumber}. Epizód\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extrák\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Érintett epizód\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Érintett évad\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Kérjük, adjon részletes magyarázatot a felmerült problémára.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Probléma bejelentése\",\n  \"components.IssueModal.CreateIssueModal.season\": \"{seasonNumber}. Évad\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Hiba jelentése\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Adnia kell egy leírást\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Mi a probléma?\",\n  \"components.IssueModal.issueAudio\": \"Hang\",\n  \"components.IssueModal.issueOther\": \"Egyéb\",\n  \"components.IssueModal.issueSubtitles\": \"Felirat\",\n  \"components.IssueModal.issueVideo\": \"Kép\",\n  \"components.Layout.Sidebar.issues\": \"Problémák\",\n  \"components.ManageSlideOver.alltime\": \"Mindenkori\",\n  \"components.ManageSlideOver.downloadstatus\": \"Letöltések\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Speciális\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Adatok törlése\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Megoldatlan Problémák\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K Média\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Nincsenek kérések.\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Média\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Kérések\",\n  \"components.ManageSlideOver.manageModalTitle\": \"{mediaType} Kezelése\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Megjelölés 4K-ban elérhetőként\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Az összes évad megjelölése 4K-ban elérhetőként\",\n  \"components.ManageSlideOver.markavailable\": \"Megjelölés elérhetőként\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Az összes évad megjelölése elérhetőként\",\n  \"components.ManageSlideOver.openarr\": \"Megnyitás itt: {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Megnyitás 4K-ban itt: {arr}\",\n  \"components.ManageSlideOver.opentautulli\": \"Megnyitás itt: Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Elmúlt {days, number} Napban\",\n  \"components.ManageSlideOver.tvshow\": \"sorozat\",\n  \"components.MovieDetails.streamingproviders\": \"Jelenleg streamelhető\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Értesítést kap, ha az Ön által jelentett problémákhoz új hozzászólások érkeznek.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Értesítést kap, ha más felhasználók problémákat jelentenek.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Értesítést kap, ha az Ön által bejelentett problémákat újra megnyitják.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Értesítést kap, ha az Ön által bejelentett problémák megoldódnak.\",\n  \"components.IssueDetails.IssueComment.edit\": \"Hozzászólás szerkesztése\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Biztos, hogy ki akarja törölni ezt a hozzászólást?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Hozzászólás törlése\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Közzétéve {relativeTime} {username} által\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Probléma törlése\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Közzétéve {relativeTime} {username} által (Szerkesztve)\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Leírás szerkesztése\",\n  \"components.IssueDetails.allepisodes\": \"Minden epizód\",\n  \"components.IssueDetails.reopenissue\": \"Probléma újranyitása\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Valami hiba történt a probléma törlése során.\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Állapot\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Ismeretlen\",\n  \"components.IssueList.issues\": \"Problémák\",\n  \"components.IssueList.IssueItem.viewissue\": \"Probléma megtekintése\",\n  \"components.IssueDetails.IssueDescription.description\": \"Leírás\",\n  \"components.IssueDetails.allseasons\": \"Minden évad\",\n  \"components.IssueDetails.openinarr\": \"Megnyitás itt: {arr}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Valami hiba történt a probléma leírásának szerkesztése közben.\",\n  \"components.IssueDetails.toastissuedeleted\": \"A probléma sikeresen törölve!\",\n  \"components.IssueDetails.unknownissuetype\": \"Ismeretlen\",\n  \"components.IssueList.sortAdded\": \"Legfrissebb\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Be kell írnia egy üzenetet\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Probléma jelentve\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Probléma újranyitva\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Engedélyt ad média problémák kezelésére.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Valami hiba történt a feladat mentése közben.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Alkalmazás API Token\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Ügynök engedélyezése\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"A Gotify teszt értesítést nem sikerült elküldeni.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Gotify teszt értesítés küldése…\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Legalább egy értesítési típust ki kell választania\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Érvényes URL-t kell megadnia\",\n  \"i18n.open\": \"Megnyitva\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Hozzáférési Token\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify értesítési beállítások sikeresen mentve!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"A <FindDiscordIdLink>többjegyű azonosítószám</FindDiscordIdLink>, amely az Ön Discord felhasználói fiókjához kapcsolódik\",\n  \"components.Settings.RadarrModal.released\": \"Megjelent\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Hozzon létre egy tokent a <PushbulletSettingsLink>Fiókbeállításokban</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Egy érvényes Discord felhasználói azonosítót kell megadnia\",\n  \"components.RequestModal.selectmovies\": \"Film(ek) Kiválasztása\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord Felhasználó ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"A Pushbullet értesítési beállításai sikeresen mentve lettek!\",\n  \"components.ManageSlideOver.playedby\": \"Lejátszotta\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Értesítést kap, ha más felhasználók hozzászólnak a problémákhoz.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Értesítést kap, ha más felhasználók újranyitják a problémákat.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Értesítést kap, ha más felhasználók megoldják a problémákat.\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Értesítések küldése, ha a problémákhoz új hozzászólások érkeznek.\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Értesítések küldése a problémák újranyitásakor.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Engedélyt ad média problémák bejelentésére.\",\n  \"components.PermissionEdit.manageissues\": \"Problémák Kezelése\",\n  \"components.PermissionEdit.createissues\": \"Problémák Bejelentése\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Engedélyt ad más felhasználók által bejelentett média problémák megtekintésére.\",\n  \"components.Settings.tautulliApiKey\": \"API Kulcs\",\n  \"components.Settings.tautulliSettings\": \"Tautulli Beállítások\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Valami hiba történt a Tautulli beállítások mentése közben.\",\n  \"components.Settings.urlBase\": \"Alap URL\",\n  \"components.Settings.validationUrl\": \"Érvényes URL-t kell megadnia\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Az Alap URL perjellel kell, hogy kezdődjön\",\n  \"components.Settings.validationUrlTrailingSlash\": \"Az URL-nek nem szabad perjellel végződnie\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Csatorna címke\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"A Pushover értesítési beállításait nem sikerült elmenteni.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"A Pushover értesítési beállításai sikeresen mentve lettek!\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Értesítések küldése problémák megoldása esetén.\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Értesítések küldése problémák bejelentésekor.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Probléma megoldva\",\n  \"components.RequestModal.approve\": \"Kérés Jóváhagyása\",\n  \"i18n.resolved\": \"Megoldva\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Mozikban\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Feladat módosítása\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Új gyakoriság\",\n  \"components.RequestBlock.languageprofile\": \"Nyelv Profil\",\n  \"components.RequestModal.requestApproved\": \"Kérés <strong>{title}</strong> elfogadva!\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"A Gotify értesítési beállításait nem sikerült elmenteni.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify teszt értesítés elküldve!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Alkalmazás Token\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Szerver URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Meg kell adnia egy alkalmazás tokent\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"Az URL nem végződhet perjellel\",\n  \"components.Settings.Notifications.enableMentions\": \"Említések Engedélyezése\",\n  \"components.Settings.RadarrModal.announced\": \"Bejelentve\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Adatkönyvtár\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Ön a Seerr <code>fejlesztői</code> ágát futtatja, ami csak azoknak ajánlott, akik hozzájárulnak a fejlesztéshez vagy segítenek a tesztelésben.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Feladat sikeresen szerkesztve!\",\n  \"components.Settings.tautulliSettingsDescription\": \"Opcionálisan megadhatja a Tautulli szerver beállításait. Seerr lekérdezi a Plex média megtekintési előzményeinek adatait a Tautulliból.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli beállítások sikeresen mentve!\",\n  \"components.Settings.validationApiKey\": \"Meg kell adnia egy API-kulcsot\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"Az Alap URL-nek nem szabad perjellel végződnie\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"A Pushbullet értesítési beállításait nem sikerült elmenteni.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Meg kell adnia egy hozzáférési tokent\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Érvényes alkalmazás tokent kell megadnia\",\n  \"components.UserProfile.recentlywatched\": \"Mostanában Nézett\",\n  \"i18n.importing\": \"Importálás…\",\n  \"i18n.import\": \"Importálás\",\n  \"components.PermissionEdit.viewissues\": \"Problémák Megtekintése\",\n  \"components.Settings.externalUrl\": \"Külső URL\",\n  \"components.MovieDetails.physicalrelease\": \"Fizikai kiadás\",\n  \"components.MovieDetails.digitalrelease\": \"Digitális kiadás\",\n  \"components.RequestCard.cancelrequest\": \"Kérés visszavonása\",\n  \"components.RequestCard.declinerequest\": \"Kérelem elutasítása\",\n  \"components.RequestCard.editrequest\": \"Kérelem szerkesztése\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"A figyelőlistád\",\n  \"components.PermissionEdit.autorequest\": \"Automatikus kérés\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"A kérelem automatikusan elküldve\",\n  \"components.MovieDetails.reportissue\": \"Probléma bejelentése\",\n  \"components.PermissionEdit.autorequestMovies\": \"Filmek automatikus kérése\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Hozzászólás a hibajegyhez\",\n  \"components.PermissionEdit.autorequestSeries\": \"Automatikus kérés sorozatok\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Sorozatkérések\",\n  \"components.MovieDetails.managemovie\": \"Film kezelése\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes közönségpontszám\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB felhasználói pontszám\",\n  \"components.RequestBlock.delete\": \"Kérelem törlése\",\n  \"components.RequestBlock.edit\": \"Kérelem szerkesztése\",\n  \"components.RequestBlock.approve\": \"Kérelem jóváhagyása\",\n  \"components.RequestBlock.decline\": \"Kérelem elutasítása\",\n  \"components.RequestBlock.lastmodifiedby\": \"Utoljára módosította\",\n  \"components.RequestBlock.requestdate\": \"Igénylés dátuma\",\n  \"components.RequestCard.approverequest\": \"Kérelem jóváhagyása\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Filmkérések\",\n  \"components.Layout.UserDropdown.requests\": \"Kérések\",\n  \"components.RequestModal.requestcollectiontitle\": \"Gyűjtemény kérése\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Jelenlegi gyakoriság\",\n  \"components.Settings.restartrequiredTooltip\": \"A Seerr-t újra kell indítani, hogy e beállítás módosításai életbe lépjenek\",\n  \"components.StatusBadge.managemedia\": \"{mediaType} kezelése\",\n  \"components.StatusBadge.openinarr\": \"Nyitás itt: {arr}\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Kérjük, kattintson az alábbi gombra az alkalmazás újratöltéséhez.\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} Nem található\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Hiba történt az évadadatok lekérésekor.\",\n  \"components.StatusBadge.playonplex\": \"Lejátszás {mediaServerName}-en\",\n  \"components.TvDetails.rtaudiencescore\": \"Rotten Tomatoes közönségpontszám\",\n  \"components.TvDetails.seasonstitle\": \"Évadok\",\n  \"components.TvDetails.seasonnumber\": \"{seasonNumber} Évad\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB felhasználói pontszám\",\n  \"components.UserProfile.emptywatchlist\": \"Itt jelennek meg a <PlexWatchlistSupportLink>Plex figyelőlistájához</PlexWatchlistSupportLink> hozzáadott médiák.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Felhasználói vagy csoportkulcs\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Frissítve\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"A(z) <strong>{title}</strong> probléma jelentése sikeresen elküldve!\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Adjon engedélyt a nemrég hozzáadott médialista megtekintéséhez.\",\n  \"components.MovieDetails.theatricalrelease\": \"Színházi kiadás\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Értesítést kap, amikor új médiakérések kerülnek automatikusan továbbításra a Figyelőlistáján szereplő elemekre.\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex figyelőlista szinkronizálása\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Filmek automatikus kérése a <PlexWatchlistSupportLink>Plex figyelőlistán keresztül</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Automatikus sorozat kérés\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Filmek automatikus kérése\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Sorozatok automatikus kérése a <PlexWatchlistSupportLink>Plex figyelőlistán keresztül</PlexWatchlistSupportLink>\",\n  \"components.PermissionEdit.viewwatchlists\": \"{mediaServerName} figyelőlisták megtekintése\",\n  \"components.Settings.experimentalTooltip\": \"A beállítás engedélyezése váratlan alkalmazási viselkedést eredményezhet\",\n  \"components.Settings.deleteServer\": \"Törölje a {serverType} szervert\",\n  \"components.StatusChecker.reloadApp\": \"{applicationTitle} újratöltése\",\n  \"components.StatusChecker.restartRequired\": \"Szerver újraindítása szükséges\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Kérjük, indítsa újra a szervert a frissített beállítások alkalmazásához.\",\n  \"components.TitleCard.cleardata\": \"Adatok törlése\",\n  \"components.UserProfile.plexwatchlist\": \"Plex figyelőlista\",\n  \"components.TvDetails.manageseries\": \"Sorozatok kezelése\",\n  \"components.Settings.advancedTooltip\": \"A beállítás helytelen konfigurálása a funkció meghibásodását eredményezheti\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex figyelőlista\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Részletek megtekintése\",\n  \"components.TvDetails.reportissue\": \"Probléma bejelentése\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Engedély adása más felhasználók {mediaServerName} figyelőlistájának megtekintéséhez.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Az Ön 30 karakteres <UsersGroupsLink>felhasználó- vagy csoportazonosítója</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Meg kell adnia egy érvényes felhasználói vagy csoportkulcsot\",\n  \"components.Discover.plexwatchlist\": \"A figyelőlistád\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Nem találtunk megfelelőt ehhez a sorozathoz.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Film kérése 4K-ban\",\n  \"components.RequestModal.requestmovietitle\": \"Film kérése\",\n  \"components.RequestModal.requestseries4ktitle\": \"Sorozat kérése 4K-ban\",\n  \"components.Discover.emptywatchlist\": \"Itt jelennek meg a <PlexWatchlistSupportLink>Plex figyelőlistájához</PlexWatchlistSupportLink> hozzáadott médiák.\",\n  \"components.RequestModal.requestseriestitle\": \"Sorozat kérelem\",\n  \"components.PermissionEdit.autorequestDescription\": \"Engedély a nem 4K médiakérések automatikus beküldésére a Plex Watchlisten keresztül.\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Engedély adása nem 4K-s filmekre vonatkozó kérelmek automatikus benyújtására a Plex figyelőlistán keresztül.\",\n  \"components.AirDateBadge.airedrelative\": \"Adásba került {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Adás {relativeTime}\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Adjon engedélyt a nem 4K sorozatokra vonatkozó kérelmek automatikus benyújtására a Plex figyelőlistán keresztül.\",\n  \"components.RequestModal.requestseasons4k\": \"{seasonCount} évad kérése 4K-ban\",\n  \"components.TitleCard.tmdbid\": \"TMDB azonosító\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Epizód} other {# Epizód}}\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatomérő\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Minden {jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Minden {jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}\",\n  \"components.PermissionEdit.viewrecent\": \"Nemrég hozzáadott megtekintése\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB azonosító\",\n  \"components.MovieDetails.productioncountries\": \"Gyártás {countryCount, plural, one {országa} other {országa}}\",\n  \"components.TvDetails.productioncountries\": \"Gyártás {countryCount, plural, one {országa} other {országa}}\",\n  \"components.UserList.newplexsigninenabled\": \"Az <strong>Új Plex bejelentkezés engedélyezése</strong> beállítás jelenleg engedélyezve van. A könyvtár-hozzáféréssel rendelkező Plex-felhasználókat nem kell importálni a bejelentkezéshez.\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatomérő\",\n  \"components.RequestBlock.requestedby\": \"Kérte\",\n  \"components.RequestModal.requestmovies\": \"Kérés {count} {count, plural, one {Movie} other {Movies}}\",\n  \"components.RequestModal.requestmovies4k\": \"Kérés {count} {count, plural, one {Movie} other {Movies}} 4K-ban\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Alkalmazás regisztrálása</ApplicationRegistrationLink> a(z) {applicationTitle} alkalmazáshoz\",\n  \"components.RequestCard.tmdbid\": \"TMDB azonosító\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB azonosító\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB azonosító\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB azonosító\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Gyűjtemény kérés 4K-ban\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Szerkesztett csúszka és mentett felfedezés testreszabási beállítások.\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Képgyorsítótár\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Gyorsítótár teljes mérete\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Csúszka neve\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Első adás dátuma növekvő\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Népszerűség csökkenően\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Képgyorsítótár tisztítása\",\n  \"i18n.restartRequired\": \"Újraindítás szükséges\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB értékelés növekvő\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Aktív szűrők törlése\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Stúdiók keresése…\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Megjelenés dátuma csökkenő sorrendben\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Adja meg a TMDB hálózati azonosítót\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Alkalmazás elnevezése\",\n  \"components.Discover.CreateSlider.addfail\": \"Nem sikerült új csúszkát létrehozni.\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Népszerűség növekvően\",\n  \"components.Discover.CreateSlider.needresults\": \"Legalább 1 eredménynek kell lennie.\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Egyéni csúszka létrehozása\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Népszerűség növekvően\",\n  \"components.Discover.CreateSlider.editSlider\": \"Csúszka szerkesztése\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Meg kell adnia egy adatértéket.\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Első adás dátuma csökkenő\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Sorozat\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Nem sikerült törölni a csúszkát.\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"TMDB Studio ID megadása\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Képgyorsítótár engedélyezése\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Népszerűség csökkenően\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Műfajok keresése…\",\n  \"components.Discover.CreateSlider.editfail\": \"Nem sikerült szerkeszteni a csúszkát.\",\n  \"components.Discover.CreateSlider.starttyping\": \"Gépelés megkezdése a kereséshez.\",\n  \"components.Discover.FilterSlideover.filters\": \"Szűrők\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Kapcsolja be a láthatóságot\",\n  \"components.Discover.CreateSlider.addSlider\": \"Csúszka hozzáadása\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Képek gyorsítótárban\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Adjon meg egy keresési lekérdezést\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Adjon meg egy TMDB kulcsszóazonosítót\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Filmek\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Meg kell adnia a címet.\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Megjelenés dátuma növekvő sorrendben\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Értesítési hang\",\n  \"components.Discover.CreateSlider.nooptions\": \"Nincs eredmény.\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Kulcsszavak keresése…\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Új csúszkát hozott létre, és elmentette a felfedezés testreszabási beállításait.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"A csúszka sikeresen törölve.\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmek\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Adjon meg egy TMDB műfajazonosítót\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Távolítsa el\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"A hozzáadott média a <PlexWatchlistSupportLink>Plex figyelőlistáján</PlexWatchlistSupportLink> elérhető.\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Sorzoat\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB értékelés csökkenő\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Cím (A-Z) növekvő\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Cím (Z-A) csökkenő\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Értékelések {minValue} és {maxValue} között\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB felhasználói szavazatok száma\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Megjelenési dátum\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Szavazatok száma {minValue} és {maxValue} között\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Eredeti nyelv\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"A figyelőlistád\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Nemrég hozzáadott\",\n  \"components.Discover.moviegenres\": \"Filmműfajok\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Cím (A-Z) növekvő\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Cím (Z-A) csökkenő\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB értékelés növekvő\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB értékelés csökkenő\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Első adás dátuma\",\n  \"components.Discover.FilterSlideover.genres\": \"Műfajok\",\n  \"components.Discover.FilterSlideover.keywords\": \"Kulcsszavak\",\n  \"components.Discover.FilterSlideover.runtime\": \"Műsoridő\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} percnyi műsoridő\",\n  \"components.Discover.FilterSlideover.studio\": \"Stúdió\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB felhasználói értékelés\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streaming szolgáltatók\",\n  \"components.Discover.resetsuccess\": \"A felfedezés testreszabási beállításainak visszaállítása sikeresen megtörtént.\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: {seasonNumber}. Évad {episodeNumber}. Rész\",\n  \"components.Login.username\": \"Felhasználónév\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Soron következő sorozatok\",\n  \"components.Discover.createnewslider\": \"Új csúszka létrehozása\",\n  \"components.Discover.FilterSlideover.status\": \"Állapot\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Az email cím hibás.\",\n  \"components.Login.invalidurlerror\": \"Nem lehet a {mediaServerName} szerverhez kapcsolódni.\",\n  \"components.Discover.customizediscover\": \"Felfedezés testreszabása\",\n  \"components.Login.adminerror\": \"Egy adminisztrátor fiókot kell használnod a belépéshez.\",\n  \"components.Login.back\": \"Ugorj Vissza\",\n  \"components.Discover.studios\": \"Stúdiók\",\n  \"components.Discover.FilterSlideover.from\": \"-Tól/től\",\n  \"components.Discover.FilterSlideover.to\": \"Ig\",\n  \"components.Discover.networks\": \"Hálózatok\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmek\",\n  \"components.Layout.Sidebar.browsetv\": \"Sorozatok\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Egy email cím szükséges.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Jelszó szükséges.\",\n  \"components.Login.credentialerror\": \"A felhasználónév vagy a jelszó hibás.\",\n  \"components.Login.description\": \"Mivel ez az első belépésed a {applicationName}-be, egy valós email címet kell megadnod.\",\n  \"components.Login.enablessl\": \"SSL használata\",\n  \"components.Login.initialsignin\": \"Csatlakozás\",\n  \"components.Login.initialsigningin\": \"Csatlakozás folyamatban…\",\n  \"components.Login.loginwithapp\": \"Belépés {appName}-el\",\n  \"components.Login.noadminerror\": \"Nem található adminisztrátor a szerveren.\",\n  \"components.Login.orsigninwith\": \"Vagy belépés ezzel\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.save\": \"Hozzáadás\",\n  \"components.Login.saving\": \"Hozzáadás folyamatban…\",\n  \"components.Login.servertype\": \"Szerver Típus\",\n  \"components.Login.signinwithjellyfin\": \"Használd a {mediaServerName} fiókodat\",\n  \"components.Login.title\": \"Email hozzáadása\",\n  \"components.Login.urlBase\": \"URL Törzs\",\n  \"components.Login.validationEmailFormat\": \"Érvénytelen email\",\n  \"components.Login.validationEmailRequired\": \"Meg kell adnia egy e-mail címet\",\n  \"components.Discover.resetfailed\": \"Hiba történt a felfedezés testreszabási beállításainak visszaállításakor.\",\n  \"components.Discover.resettodefault\": \"Alapértelmezett beállítások visszaállítása\",\n  \"components.Discover.resetwarning\": \"Összes csúszka visszaállítása alapértelmezettre. Ez a saját csúszkákat is törli!\",\n  \"components.Discover.stopediting\": \"Szerkesztés leállítása\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB filmműfaja\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB sorozat kulcsszó\",\n  \"components.MovieDetails.watchlistError\": \"Valami probléma történt. Kérjük, próbálkozzon újra.\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Értesítési hang\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNS-gyorsítótár\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Globális DNS-gyorsítótár statisztika\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Aktív cím\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Kor\",\n  \"components.Settings.SettingsMain.apikey\": \"API kulcs\",\n  \"components.Settings.tip\": \"Tipp\",\n  \"components.TitleCard.watchlistCancel\": \"A <strong>{title}</strong> figyelőlistája törölve lett.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Jelszó\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Hozzáadás…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"{mediaServerName}-fiók összekapcsolása\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Streamelési régió\",\n  \"i18n.completed\": \"Befejezve\",\n  \"i18n.deleted\": \"Törölve\",\n  \"i18n.collection\": \"Gyűjtemény\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Szál/téma azonosító\",\n  \"components.MovieDetails.addtowatchlist\": \"Hozzáadás figyelőlistához\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Az elérhető médiát elrejti a felfedező oldalakról, de a keresési eredményekből nem\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Poszter beágyazása\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Streamelési régió\",\n  \"components.Selector.inProduction\": \"Gyártásban\",\n  \"components.Discover.tmdbsearch\": \"TMDB keresés\",\n  \"components.Settings.Notifications.embedPoster\": \"Poszter beágyazása\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Automatikusan hozzáad egy további címkét a kérelmező felhasználói azonosítójával és megjelenített nevével\",\n  \"components.Settings.failed\": \"Nem működik\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.operational\": \"Működés\",\n  \"components.Settings.valueRequired\": \"Meg kell adnia egy értéket.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Előfizetés törlése\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Aktív szűrő} other {# Aktív szűrő}}\",\n  \"components.Settings.timeout\": \"Határidő\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Aktív szűrő} other {# Aktív szűrő}}\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL megadása szükséges\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.MovieDetails.downloadstatus\": \"Letöltési állapot\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Ismeretlen cím\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Nincs elérhető opció\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Válasszon egy tanúsítványt\",\n  \"components.Selector.ended\": \"Véget ért\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Prioritás\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Ügynök engedélyezése\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Érvényes Discord Role ID-t kell megadnia\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Szolgáltatás kiválasztása\",\n  \"components.Settings.OverrideRuleModal.service\": \"Szolgáltatás\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Hosztnév\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"DNS-gyorsítótár ürítése\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Találati arány\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4 tartalék\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Felhasználói avatarok\",\n  \"components.Settings.SettingsMain.general\": \"Általános\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Elérhető média elrejtése\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Proxy megkerülése helyi címek esetében\",\n  \"components.Settings.apiKey\": \"API kulcs\",\n  \"components.Settings.invalidurlerror\": \"Nem lehet csatlakozni a {mediaServerName} szerverhez.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Elfelejtett jelszó URL\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Hiba történt a {mediaServerName} beállítások mentése közben.\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Nem található könyvtár\",\n  \"components.Settings.menuNetwork\": \"Hálózat\",\n  \"components.Settings.metadataProviderSettings\": \"Metaadat-szolgáltató\",\n  \"components.Settings.metadataSettingsSaved\": \"Metaadat-szolgáltató beállítások mentve\",\n  \"components.Settings.no\": \"Nem\",\n  \"components.Settings.nooptions\": \"Nincs találat.\",\n  \"components.Settings.notTested\": \"Nem tesztelt\",\n  \"components.Settings.searchKeywords\": \"Kulcsszavak keresése…\",\n  \"components.Settings.settings\": \"Beállítások\",\n  \"components.Settings.starttyping\": \"Gépelés megkezdése a kereséshez.\",\n  \"components.Settings.syncing\": \"Szinkronizálás\",\n  \"components.Settings.yes\": \"Igen\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> sikeresen törölve a figyelőlistáról!\",\n  \"components.TvDetails.Season.noepisodes\": \"Az epizódok listája nem érhető el.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> sikeresen hozzáadva a figyelőlistához!\",\n  \"components.UserList.importfromJellyfin\": \"{mediaServerName} felhasználók importálása\",\n  \"components.UserList.importfromJellyfinerror\": \"Hiba történt a/az {mediaServerName} felhasználók importja során.\",\n  \"components.UserList.username\": \"Felhasználónév\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Létrehozva\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Mentés…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"A webes push-értesítés ki lett kapcsolva.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Ismeretlen\",\n  \"components.UserProfile.localWatchlist\": \"{username} figyelőlistája\",\n  \"components.Setup.back\": \"Ugrás vissza\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"A szál/téma azonosítójának pozitív egész számnak kell lennie\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"A webes push-értesítés beállításait nem sikerült elmenteni.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"A webes push-értesítés beállításai sikeresen mentésre kerültek!\",\n  \"components.MovieDetails.removefromwatchlist\": \"Eltávolítás a figyelőlistáról\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Műfajok\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Címke kiválasztása\",\n  \"components.Settings.save\": \"Módosítások mentése\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} sikeresen importálva!\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Nincs {mediaServerName} felhasználó, akit importálni lehetne.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Motor\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Epizód} other {Epizód}}\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Összekapcsolt fiókok\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"A webes push-értesítés engedélyezve.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"típus\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Valami rosszul sült el a felhasználói előfizetés törlése közben.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Előfizetés törölve.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Operációs rendszer\",\n  \"components.Login.validationservertyperequired\": \"Kérjük, válasszon szerver típust\",\n  \"components.Login.validationusernamerequired\": \"Felhasználónév szükséges\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Ezzel véglegesen eltávolítja a {mediaType}-t az {arr} mappából, beleértve az összes fájlt.\",\n  \"components.ManageSlideOver.removearr\": \"Eltávolítás {arr} -ból\",\n  \"components.ManageSlideOver.removearr4k\": \"Eltávolítás 4K {arr} -ból\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Válasszon ki egy metaadat-szolgáltatót\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB felhasználói pontszám – szavazatok: {formattedCount}\",\n  \"components.MovieDetails.openradarr\": \"Film megnyitása Radarr-ban\",\n  \"components.MovieDetails.openradarr4k\": \"Film megnyitása 4K Radarr-ban\",\n  \"components.MovieDetails.play\": \"Lejátszás a {mediaServerName} -en/in\",\n  \"components.MovieDetails.play4k\": \"4K lejátszás a {mediaServerName} -en/in\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> sikeresen eltávolítva a figyelőlistáról!\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> sikeresen hozzáadva a figyelőlistához!\",\n  \"components.RequestCard.unknowntitle\": \"Ismeretlen cím\",\n  \"components.RequestList.RequestItem.profileName\": \"Profil\",\n  \"components.RequestList.RequestItem.removearr\": \"Eltávolítás {arr}-ból\",\n  \"components.RequestList.sortDirection\": \"Rendezés irányának váltása\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"A tanúsítványok betöltése sikertelen\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Maximális értékelés\",\n  \"components.Selector.CertificationSelector.minRating\": \"Minimális értékelés\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Kezdje el begépelni a keresett kifejezést.\",\n  \"components.Selector.canceled\": \"Elkaszálva\",\n  \"components.Selector.nooptions\": \"Nincs találat.\",\n  \"components.Selector.pilot\": \"Pilot\",\n  \"components.Selector.planned\": \"Tervezett\",\n  \"components.Selector.returningSeries\": \"Visszatérő sorozat\",\n  \"components.Selector.searchGenres\": \"Válasszon műfajokat…\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Műfaj\",\n  \"components.Selector.searchKeywords\": \"Kulcsszavak keresése…\",\n  \"components.Selector.searchStatus\": \"Állapot kiválasztása...\",\n  \"components.Selector.searchStudios\": \"Stúdiók keresése…\",\n  \"components.Selector.searchUsers\": \"Felhasználók kiválasztása…\",\n  \"components.Selector.showless\": \"Kevesebb mutatása\",\n  \"components.Selector.starttyping\": \"Gépelés megkezdése a kereséshez.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Be kell állítania egy prioritási számot\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Az Ntfy értesítési beállítások mentése nem sikerült.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Ntfy értesítési beállítások sikeresen mentve!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Jelszó\",\n  \"components.Selector.showmore\": \"Mutass többet\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Ntfy teszt értesítés küldése nem sikerült.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"NTFY tesztértesítés küldése…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"NTFY tesztértesítés elküldve!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Token hitelesítés\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Topic\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Szerver gyökér URL-je\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Felhasználónév\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Felhasználónév + jelszó hitelesítés\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Meg kell adnia egy topic-ot\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Érvényes URL-címet kell megadnia\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Legalább egy értesítési típust ki kell választania\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Eszköz alapértelmezett\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"URL-változók támogatása\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"A rendelkezésre álló változók a webhook sablonváltozók szakaszban szerepelnek\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"A tesztértesítési URL {testUrl} helyett a tényleges webhook URL-re van beállítva.\",\n  \"components.Settings.Notifications.messageThreadId\": \"Szál/Téma azonosító\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"A szál/téma azonosítójának pozitív egész számnak kell lennie\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Értesítési szerepkör azonosító\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"A webhook üzenetben megemlítendő szerepkör azonosító. Hagyja üresen, ha letiltani szeretné az említéseket\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Feltételek\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Meghatározza a paraméterek módosításának alkalmazása előtti feltételeket. A szabályok alkalmazásához minden mezőt érvényesíteni kell (AND művelet). A mező akkor tekinthető érvényesnek, ha bármelyik tulajdonsága megfelel (OR művelet).\",\n  \"components.Settings.OverrideRuleModal.create\": \"Szabály létrehozása\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Új felülírási szabály\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Megkerülési szabály szerkesztése\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Kulcsszavak\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Nyelvek\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Nincsenek címkék.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Minőségi profil\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Gyökérmappa\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Minőségi profil kiválasztása\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Gyökérmappa kiválasztása\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Beállítások\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Határozza meg, hogy mely beállítások változnak meg, ha a fenti feltételek teljesülnek.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Címkék\",\n  \"components.Settings.OverrideRuleModal.users\": \"Felhasználók\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Feltételek\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Kulcsszavak\",\n  \"components.Settings.OverrideRuleTile.language\": \"Nyelv\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Minőségi profil\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Gyökérmappa\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Beállítások\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Címkék\",\n  \"components.Settings.OverrideRuleTile.users\": \"Felhasználók\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Média elérhetőség szinkronizálása\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"A Seerr gyorsítótárba helyezi a DNS-kereséseket a teljesítmény optimalizálása és a felesleges API-hívások elkerülése érdekében.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Az adatok az összes DNS-gyorsítótár-bejegyzésből származnak.\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"{hostname} DNS-gyorsítótár kiürítve.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Találatok\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Hibák\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Találatok\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Ha a beállításokban engedélyezve van, a Seerr proxyként működik és előre konfigurált külső forrásokból származó képeket tárol a gyorsítótárban. A gyorsítótárban tárolt képek a konfigurációs mappába kerülnek. A fájlokat az <code>{appDataPath}/cache/images</code> mappában találja meg.\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Hibák\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex Token frissítése\",\n  \"components.Settings.SettingsJobsCache.size\": \"Méret\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"API kulcs a vágólapra másolva.\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Alkalmazás URL-címe\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Külső forrásból származó képek gyorsítótárazása (jelentős mennyiségű lemezterületet igényel)\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Felfedezés régiója\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Tartalom szűrése regionális elérhetőség szerint\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Különkiadás epizódok kérésének engedélyezése\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Általános beállítások\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"A Seerr globális és alapértelmezett beállításainak konfigurálása.\",\n  \"components.Settings.SettingsMain.locale\": \"Megjelenítési nyelv\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Tartalom szűrése eredeti nyelv szerint\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Részenkénti sorozatkérések engedélyezése\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"A streaming oldalak megjelenítése regionális elérhetőség szerint\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Valami probléma történt az új API-kulcs generálása közben.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Új API kulcs generálása sikeres!\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Hiba történt a beállítások mentése közben.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Beállítások sikeresen elmentve!\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Meg kell adnia az alkalmazás címét\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Érvényes URL-címet kell megadnia\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"Az URL nem végződhet perjeljel\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Érvényes URL-címet kell megadnia\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"Az URL nem végződhet perjeljel\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube URL\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"A YouTube-videók alap URL-je, ha saját YouTube-instanciát használ.\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"CSRF védelem bekapcsolása\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"NE kapcsolja be ezt a beállítást, ha nem tudja, mit csinál!\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Külső API-hozzáférés beállítása csak olvashatóra (HTTPS szükséges)\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNS-gyorsítótár\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"DNS-gyorsítótár maximális TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"DNS-gyorsítótár minimális TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"NE kapcsolja be ezt a funkciót, ha problémái vannak a DNS-feloldással\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"A DNS-feloldás gyorsítótárazásának bekapcsolása a teljesítmény optimalizálása és a felesleges API-hívások elkerülése érdekében\",\n  \"components.Settings.SettingsNetwork.docs\": \"dokumentáció\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Elsőként az IPv4 feloldás kikényszerítése\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Kényszerítse a Seerr-t, hogy először az IPv4-címeket oldja fel IPv6 helyett\",\n  \"components.Settings.SettingsNetwork.network\": \"Hálózat\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"A konténer/rendszer hálózati paramétereit kell használni ezek helyett a beállítások helyett. További információkért lásd a {docs} dokumentumot.\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Hálózati beállítások\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"A Seerr példányának hálózati beállításainak konfigurálása.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Proxy által figyelmen kívül hagyott címek\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Használja a „,” szimbólumot elválasztónak, és a „*.” szimbólumot helyettesítő karakterként az aldomainekhez\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) proxy\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Proxy hosztnév\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Proxy jelszó\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Proxy port\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"SSL használata proxyhoz\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Proxy felhasználónév\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Hiba történt a beállítások mentése közben.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"A beállítások mentése sikeresen megtörtént!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Proxy támogatás engedélyezése\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Lehetővé teszi a Seerr számára, hogy helyesen regisztrálja a proxy mögötti ügyfél IP-címeket\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Érvényes portot kell megadnia\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Bejelentkezési módszerek\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Felhasználói bejelentkezési módszerek beállítása.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"{mediaServerName} bejelentkezés engedélyezése\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Lehetővé teszi a felhasználók számára, hogy {mediaServerName} fiókjukkal jelentkezzenek be\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Anime sorozat típusa\",\n  \"components.Settings.SonarrModal.seriesType\": \"Sorozat típusa\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Kérések címkézése\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Kérések címkézése\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Automatikusan hozzáad egy további címkét a kérelmező felhasználói azonosítójával és megjelenített nevével\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Az összes kiválasztott metaadat-szolgáltató működőképes\",\n  \"components.Settings.animeMetadataProvider\": \"Anime metaadat-szolgáltató\",\n  \"components.Settings.chooseProvider\": \"Válasszon metaadat-szolgáltatókat a különböző tartalomtípusokhoz\",\n  \"components.Settings.clickTest\": \"Kattintson a „Teszt” gombra, ha ellenőrizni szeretné a metaadat-szolgáltatókkal való kapcsolatot\",\n  \"components.Settings.connectionTestFailed\": \"A kapcsolat tesztje sikertelen volt\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"A metaadat-szolgáltató beállítások mentése sikertelen\",\n  \"components.Settings.general\": \"Általános\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} nem egy TMDB kulcsszó.\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName} beállítások\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Opcionálisan beállíthatja a {mediaServerName} szerver belső és külső végpontjait. A legtöbb esetben a külső URL eltér a belső URL-től. A {mediaServerName} bejelentkezéshez egyéni jelszó-visszaállítási URL is beállítható, ha egy másik jelszó-visszaállítási oldalra szeretne átirányítani. Megváltoztathatja a Jellyfin API kulcsot is, amelyet korábban automatikusan generált.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"A {mediaServerName} beállítások mentése sikeresen megtörtént!\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Az automatikus könyvtárcsoportosítással történő egyéni hitelesítés nem támogatott\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Valami probléma történt a könyvtárak szinkronizálása közben\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName} könyvtárak\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"A {mediaServerName} könyvtárak a címeket keresik. Ha nincs könyvtár a listában, kattintson az alábbi gombra.\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName} beállítások\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Adja meg a {mediaServerName} szerver beállításait. A {mediaServerName} átvizsgálja a {mediaServerName} könyvtárakat, hogy megnézze, milyen tartalom áll rendelkezésre.\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normális esetben ez csak 24 óránként egyszer fut le. A Seerr agresszívebben ellenőrzi az Ön {mediaServerName} szerverének \\\"nemrégiben hozzáadottakat\\\" könyvtárat. Ha az első alkalom állítja be a Seerr-t, egyszeri teljes kézi könyvtárellenőrzés ajánlott!\",\n  \"components.Settings.manualscanJellyfin\": \"Kézi könyvtárbeolvasás\",\n  \"components.Settings.menuMetadataProviders\": \"Metaadat-szolgáltatók\",\n  \"components.Settings.metadataProviderSelection\": \"Metaadatok szolgáltatójának kiválasztása\",\n  \"components.Settings.metadataSettings\": \"Metaadatok szolgáltatójának beállításai\",\n  \"components.Settings.noSpecialCharacters\": \"A beállítás a TMDB kulcsszóazonosítók vesszővel elválasztott listájának kell lennie, és nem kezdődhet vagy végződhet vesszővel.\",\n  \"components.Settings.providerStatus\": \"Metaadat-szolgáltatói státusz\",\n  \"components.Settings.saving\": \"Mentés…\",\n  \"components.Settings.scanbackground\": \"A beolvasás háttérben fog futni. Addig is folytathatja a beállítási folyamatot.\",\n  \"components.Settings.seriesMetadataProvider\": \"Sorozat metaadat-szolgáltató\",\n  \"components.Settings.syncJellyfin\": \"Könyvtárak szinkronizálása\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"A TVDB nem működik, kérjük, válasszon másik metaadat-szolgáltatót\",\n  \"components.Setup.configemby\": \"Emby beállítása\",\n  \"components.Setup.configjellyfin\": \"Jellyfin beállítása\",\n  \"components.Setup.configplex\": \"Plex beállítása\",\n  \"components.Setup.configuremediaserver\": \"Médiszerver beállítása\",\n  \"components.Setup.librarieserror\": \"Az érvényesítés sikertelen. Kérjük, kapcsolja be újra a könyvtárakat a folytatáshoz.\",\n  \"components.Setup.servertype\": \"Válassza ki a szerver típusát\",\n  \"components.Setup.signin\": \"Bejelentkezés\",\n  \"components.Setup.signinWithEmby\": \"Adja meg az Emby szerverének adatait\",\n  \"components.Setup.signinWithJellyfin\": \"Adja meg a Jellyfin szerverének adatait\",\n  \"components.Setup.signinWithPlex\": \"Adja meg a Plex szerverének adatait\",\n  \"components.Setup.subtitle\": \"Kezdje azzal, hogy kiválasztja a médiaszerverét\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.TitleCard.addToWatchList\": \"Hozzáadás a figyelőlistához\",\n  \"components.TitleCard.watchlistError\": \"Valami probléma történt. Kérjük, próbálkozzon újra.\",\n  \"components.TvDetails.addtowatchlist\": \"Hozzáadás figyelőlistához\",\n  \"components.TvDetails.play\": \"Lejátszás {mediaServerName}-n\",\n  \"components.TvDetails.play4k\": \"4K lejátszás {mediaServerName}-n\",\n  \"components.TvDetails.streamingproviders\": \"Jelenleg streamelhető\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> sikeresen eltávolítva a figyelőlistáról!\",\n  \"components.TvDetails.watchlistError\": \"Valami probléma történt. Kérjük, próbálkozzon újra.\",\n  \"components.UserList.importfrommediaserver\": \"{mediaServerName} felhasználók importálása\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName} felhasználó\",\n  \"components.UserList.newJellyfinsigninenabled\": \"Az <strong>Új {mediaServerName} bejelentkezés engedélyezése</strong> beállítás jelenleg engedélyezve van. A könyvtárhoz hozzáféréssel rendelkező {mediaServerName} felhasználókat nem kell importálni a bejelentkezéshez.\",\n  \"components.UserList.validationUsername\": \"Szükséges egy felhasználónév megadása\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Írja be {mediaServerName} hitelesítő adatait, hogy összekapcsolja fiókját az {applicationName} alkalmazással.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Ez a fiók már összekapcsolva van egy {applicationName} felhasználóval\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Nem lehet csatlakozni a {mediaServerName} szerverhez a hitelesítő adataival\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Ismeretlen hiba lépett fel\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Egy jelszót mindenképp meg kell adni\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Link\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Felhasználónév\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Egy felhasználónevet mindenképp meg kell adni\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Felfedezés régiója\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Tartalom szűrése regionális elérhetőség szerint\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Böngésző\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Nem lehet csatlakozni a Plexhez a hitelesítő adataival\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Ország kiválasztása\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Évad} other {Évad}}\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Aktív szűrő} other {# Aktív szűrő}}\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {lejátszás} other {lejátszás}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName} felhasználó\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Módosítások mentése\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"A streaming oldalak megjelenítése regionális elérhetőség szerint\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Ez az e-mail cím már foglalt!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Egy másik felhasználó már használja ezt a felhasználónevet. Be kell állítania egy e-mail címet\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Érvényes e-mail cím szükséges\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"E-mail cím szükséges\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"A kapcsolt fiók nem törölhető.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Ismeretlen hiba történt\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Összekapcsolt fiókok\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Az alábbi külső fiókok a {applicationName} fiókjával vannak összekötve.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Nincs külső fiókja, amely a fiókjához lenne kapcsolva.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Nincs jogosultsága módosítani ennek a felhasználónak a kapcsolt fiókjait.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Ez a fiók már összekapcsolva van egy Plex felhasználóval\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Eszköz\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Web push letiltása\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Valami probléma történt a web push letiltása közben.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Web push engedélyezése\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Valami probléma történt a web push engedélyezése közben.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Eszközök kezelése\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Nincsenek megjelenítendő web push-értesítés előfizetések.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Eszköz alapértelmezett\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Minden {jobScheduleDays, plural, one {nap} other {{jobScheduleDays} days}}\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Poszter beágyazása\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> sikeresen hozzáadva a figyelőlistához!\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Poszter beágyazása\",\n  \"components.Settings.addrule\": \"Új felülírási szabály\",\n  \"components.Settings.overrideRules\": \"Felülírási szabályok\",\n  \"components.Settings.overrideRulesDescription\": \"A felülírási szabályok lehetővé teszik olyan tulajdonságok megadását, amelyek helyettesítésre kerülnek, ha egy kérés megfelel a szabálynak.\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Ha a csoportos csevegésében engedélyezve vannak a témák, itt megadhatja a szál/téma azonosítóját\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Felhasználói email megadása kötelező\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"A TMDB nem működik, kérjük, válasszon másik metaadat-szolgáltatót\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Poszter beágyazása\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Felülírási szabály sikeresen létrehozva!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Felülírási szabály sikeresen frissítve!\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Ezen szabály alkalmazása a kiválasztott szolgáltatásra.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Minden {jobScheduleSeconds, plural, one {másodperc} other {{jobScheduleSeconds} másodperc}}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Ha a csoportos csevegésében engedélyezve vannak a témák, itt megadhatja egy szál/téma azonosítóját\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Legalább egy hitelesítési metódust ki kell választania.\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Hiányzók\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Felfedezés nyelve\",\n  \"components.TvDetails.removefromwatchlist\": \"Eltávolítás figyelőlistáról\",\n  \"i18n.specials\": \"Különkiadások\",\n  \"components.Discover.FilterSlideover.certification\": \"Tartalombesorolás\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB film kulcsszó\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"Az URL-bázisnak kezdő perjellel kell rendelkeznie\",\n  \"components.Login.validationPortRequired\": \"Érvényes portszámot kell megadnia\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Hiba leírás\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB filmstreaming szolgáltatások\",\n  \"components.Discover.tmdbstudio\": \"TMDB Stúdió\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB sorozat műfaja\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TV streaming szolgáltatások\",\n  \"components.Discover.tvgenres\": \"Sorozat műfajok\",\n  \"components.Discover.updatesuccess\": \"Frissítettük a felfedezés testreszabási beállításait.\",\n  \"components.Login.validationhostformat\": \"Érvényes URL szükséges\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"Az URL-alap nem végződhet perjellel\",\n  \"components.Login.validationUrlTrailingSlash\": \"Az URL nem végződhet perjellel\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Kulcsszavak kizárása\",\n  \"components.Discover.tmdbnetwork\": \"TMDB hálózat\",\n  \"components.Login.validationemailformat\": \"Érvényes e-mail cím szükséges\",\n  \"components.Discover.updatefailed\": \"Hiba történt a felfedezés testreszabási beállításainak frissítésekor.\",\n  \"components.Login.emailtooltip\": \"A címnek nem kell a {mediaServerName} példányhoz tartoznia.\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"A Seerr-ről\",\n  \"components.Settings.SettingsAbout.contribute\": \"Járulj hozzá\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Seerr támogatása\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Érvényes maximális TTL‑értéket kell megadnia\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Érvényes minimális TTL‑értéket kell megadnia\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Aktív előfizetés\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Nem sikerült csatlakozni a(z) {services} szolgáltatáshoz. Egyes információk nem érhetők el.\",\n  \"components.RequestList.unableToConnect\": \"Nem sikerült csatlakozni a(z) {services} szolgáltatáshoz. Egyes információk nem érhetők el.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Még nem lett gyorsítótárazva egyetlen DNS‑lekérdezés sem.\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Az összes kimenő HTTP/HTTPS kérés egy proxy szerveren (host/port) keresztül legyen továbbítva. Nem engedélyezi a HTTPS-, SSL- vagy tanúsítványbeállításokat.\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> is a tiltólistán.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Tiltólistán szereplő média kezelése.\",\n  \"components.Blocklist.blocklistdate\": \"dátum\",\n  \"components.Blocklist.blocklistedby\": \"{date}, {user} által\",\n  \"components.Blocklist.blocklistsettings\": \"Tiltólista beállítások\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Tiltólistázott címkék\",\n  \"components.Blocklist.filterManual\": \"Kézi\",\n  \"components.Blocklist.mediaName\": \"Név\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb Id\",\n  \"components.Blocklist.mediaType\": \"Típus\",\n  \"components.Blocklist.showAllBlocklisted\": \"Tiltólistázott médiák megjelenítése\",\n  \"components.Layout.Sidebar.blocklist\": \"Tiltólista\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Engedély adása média tiltólistázásához.\",\n  \"components.PermissionEdit.manageblocklist\": \"Tiltólista kezelése\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Engedély adása a tiltólistázott média kezelésére.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Tiltólistára tett média megtekintése.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Engedély adása tiltólistára tett média megjelenítésére.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Tiltólistázott címkék feldolgozása\",\n  \"component.BlocklistBlock.blocklistdate\": \"Tiltólistára tétel dátuma\",\n  \"component.BlocklistBlock.blocklistedby\": \"Tiltólistára tette\",\n  \"i18n.removefromBlocklist\": \"Eltávolítás tiltólistáról\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> sikeresen eltávolításra került a tiltólistáról.\",\n  \"i18n.blocklistError\": \"Hiba történt. Próbálja újra.\",\n  \"i18n.addToBlocklist\": \"Hozzáadás tiltólistához\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Nincs mit másolni\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Biztosan törölni szeretné a tiltólistázott címkéket?\",\n  \"components.PermissionEdit.blocklistedItems\": \"Média tiltólistára tétele.\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Tiltólista tartalom címkékkel\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Tiltólistázott tartalom korlátozása címkénként\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"A \\\"Tiltólistázott címkék feldolgozása\\\" feladat ennyi oldalt fog tiltólistára tenni minden egyes rendezésnél. A nagyobb szám pontosabb tiltólistát eredményez, de több tárhelyet igényel.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"A Tiltólistázott címkék feldolgozása feladat automatikusan tiltólistára teszi a címkékkel ellátott tartalmakat\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Tiltólistázott elemek elrejtése\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"A tiltólistára tett elemek elrejtése a felfedező oldalakról minden olyan felhasználó számára, aki rendelkezik a ‘Tiltólista kezelése’ jogosultsággal\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Alább illessze be a tiltólista címkekonfigurációját.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Tiltólista címkekonfiguráció importálása\",\n  \"components.Settings.blocklistedTagsText\": \"Tiltólistázott címkék\",\n  \"components.Settings.copyBlocklistedTags\": \"A tiltólistázott címkék a vágólapra másolva.\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Tiltólista címkekonfiguráció másolása\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Tiltólista címkekonfiguráció importálása\",\n  \"i18n.blocklist\": \"Tiltólista\",\n  \"i18n.blocklistDuplicateError\": \"A(z) \\\\<strong>{title}\\\\</strong> már tiltólistára került.\",\n  \"i18n.blocklistSuccess\": \"A(z) \\\\<strong>{title}\\\\</strong> sikeresen tiltólistára került.\",\n  \"i18n.blocklisted\": \"Tiltólistázott\",\n  \"component.BlocklistModal.blocklisting\": \"Tiltólistázás\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"API‑kérés időtúllépés\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"A maximális várakozási idő (másodpercben) a külső szolgáltatások – például a Radarr vagy a Sonarr – válaszára. Állítsa 0-ra, ha nem szeretne időkorlátot.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Érvényes időkorlát‑értéket kell megadnia\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Új Évadok Figyelése\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Prioritás\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"1 és 5 közötti prioritást kell megadnia\",\n  \"components.Discover.timeWindowDay\": \"Napi\",\n  \"components.Discover.timeWindowWeek\": \"Heti\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Eltávolítás\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Nem használható egyszerre az Authorization fejléc és az egyedi Authorization fejléc. Kérjük, távolítsa el az egyiket.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Minden fejlécnek kell, hogy legyen neve és értéke\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Fejléc neve\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Egyéni HTTP-fejlécek hozzáadása a webhook kérésekhez\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Fejléc értéke\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Fejléc hozzáadása\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Egyedi fejlécek\"\n}\n"
  },
  {
    "path": "src/i18n/locale/it.json",
    "content": "{\n  \"components.Discover.recentrequests\": \"Richieste recenti\",\n  \"components.Discover.recentlyAdded\": \"Aggiunti di recente\",\n  \"components.Discover.populartv\": \"Serie popolari\",\n  \"components.Discover.popularmovies\": \"Film popolari\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Impostazioni delle notifiche via posta elettronica salvate con successo!\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Impossibile salvare le impostazioni delle notifiche via posta elettronica.\",\n  \"components.Settings.Notifications.emailsender\": \"Indirizzo del mittente\",\n  \"components.Settings.address\": \"Indirizzo\",\n  \"components.Settings.SonarrModal.ssl\": \"Usa SSL\",\n  \"components.Settings.SonarrModal.port\": \"Porta\",\n  \"components.Settings.SonarrModal.hostname\": \"Hostname o indirizzo IP\",\n  \"components.Settings.SettingsAbout.version\": \"Versione\",\n  \"components.Settings.RadarrModal.ssl\": \"Usa SSL\",\n  \"components.Settings.RadarrModal.port\": \"Porta\",\n  \"components.Settings.RadarrModal.hostname\": \"Hostname o indirizzo IP\",\n  \"components.Settings.Notifications.agentenabled\": \"Abilita Agente\",\n  \"components.Search.searchresults\": \"Risultati di ricerca\",\n  \"components.RequestModal.selectseason\": \"Seleziona stagioni\",\n  \"components.RequestModal.seasonnumber\": \"Stagione {number}\",\n  \"components.RequestModal.season\": \"Stagione\",\n  \"components.RequestModal.requestadmin\": \"Questa richiesta sarà approvata automaticamente.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> richiesto con successo!\",\n  \"components.RequestModal.requestCancel\": \"Richiesta per <strong>{title}</strong> eliminata.\",\n  \"components.RequestModal.numberofepisodes\": \"Nº di episodi\",\n  \"components.RequestModal.cancel\": \"Cancella la richiesta\",\n  \"components.RequestList.requests\": \"Richieste\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Stagione} other {Stagioni}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Stagione} other {Stagioni}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Stagione} other {Stagioni}}\",\n  \"components.PersonDetails.ascharacter\": \"come {character}\",\n  \"components.PersonDetails.appearsin\": \"Comparse\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studio}}\",\n  \"components.MovieDetails.similar\": \"Titoli simili\",\n  \"components.MovieDetails.runtime\": \"{minutes} minuti\",\n  \"components.MovieDetails.revenue\": \"Incassi\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Data di rilascio} other {Date di rilascio}}\",\n  \"components.MovieDetails.recommendations\": \"Consigliati\",\n  \"components.MovieDetails.overviewunavailable\": \"Trama non disponibile.\",\n  \"components.MovieDetails.overview\": \"Trama\",\n  \"components.MovieDetails.originallanguage\": \"Lingua originale\",\n  \"components.MovieDetails.cast\": \"Cast\",\n  \"components.MovieDetails.budget\": \"Budget\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Cast completo\",\n  \"components.Layout.UserDropdown.signout\": \"Esci\",\n  \"components.Layout.Sidebar.users\": \"Utenti\",\n  \"components.Layout.Sidebar.settings\": \"Impostazioni\",\n  \"components.Layout.Sidebar.requests\": \"Richieste\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Cerca film e serie\",\n  \"components.Discover.upcomingmovies\": \"Film in uscita\",\n  \"components.Discover.upcoming\": \"Film in uscita\",\n  \"components.Discover.trending\": \"Di tendenza\",\n  \"components.UserList.deleteconfirm\": \"Sei sicuro di voler rimuovere questo utente? Tutti le richieste verranno rimosse permanentemente.\",\n  \"components.UserList.created\": \"Unito\",\n  \"components.UserList.admin\": \"Amministratore\",\n  \"components.UserList.role\": \"Ruolo\",\n  \"components.UserList.plexuser\": \"Utente Plex\",\n  \"components.UserList.deleteuser\": \"Elimina l'utente\",\n  \"components.UserList.userlist\": \"Elenco utenti\",\n  \"components.UserList.userdeleteerror\": \"Qualcosa è andato storto nel rimuovere l'utente.\",\n  \"components.UserList.userdeleted\": \"Utente rimosso con successo!\",\n  \"components.UserList.user\": \"Utente\",\n  \"components.UserList.totalrequests\": \"Richieste\",\n  \"i18n.declined\": \"Rifiutato\",\n  \"i18n.decline\": \"Rifiuta\",\n  \"i18n.cancel\": \"Annulla\",\n  \"i18n.available\": \"Disponibile\",\n  \"i18n.approved\": \"Approvato\",\n  \"i18n.approve\": \"Approva\",\n  \"i18n.unavailable\": \"Non disponibile\",\n  \"i18n.tvshows\": \"Serie\",\n  \"i18n.processing\": \"Elaborazione\",\n  \"i18n.pending\": \"In sospeso\",\n  \"i18n.partiallyavailable\": \"Parzialmente disponibile\",\n  \"i18n.movies\": \"Film\",\n  \"i18n.deleting\": \"Eliminazione…\",\n  \"i18n.delete\": \"Elimina\",\n  \"pages.oops\": \"Ops\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Cartella principale\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Seleziona una cartella principale\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Seleziona un profilo qualità\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Seleziona la disponibilità minima\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Profilo qualità\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Disponibilità minima\",\n  \"components.Settings.RadarrModal.editradarr\": \"Modifica server Radarr\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Server predefinito\",\n  \"components.Settings.RadarrModal.apiKey\": \"Chiave API\",\n  \"components.Settings.RadarrModal.add\": \"Aggiungi un server\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Impossibile salvare le impostazioni di Discord.\",\n  \"components.RequestModal.requestfrom\": \"La richiesta di {username} è in attesa di approvazione.\",\n  \"components.RequestModal.pendingrequest\": \"Richiesta in sospeso\",\n  \"components.Layout.Sidebar.dashboard\": \"Esplora\",\n  \"components.TvDetails.cast\": \"Cast\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Cast completo della serie\",\n  \"components.Setup.welcome\": \"Benvenuti in Seerr\",\n  \"components.Settings.validationPortRequired\": \"È necessario fornire un numero di porta valido\",\n  \"components.Settings.validationHostnameRequired\": \"È necessario fornire un valido hostname o indirizzo IP\",\n  \"components.Settings.startscan\": \"Avvia la scansione\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.radarrsettings\": \"Impostazioni Radarr\",\n  \"components.Settings.plexsettings\": \"Impostazioni Plex\",\n  \"components.Settings.notrunning\": \"Non in esecuzione\",\n  \"components.Settings.notificationsettings\": \"Impostazioni delle notifiche\",\n  \"components.Settings.menuServices\": \"Servizi\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Notifiche\",\n  \"components.Settings.menuLogs\": \"Registri\",\n  \"components.Settings.menuGeneralSettings\": \"Generali\",\n  \"components.Settings.menuAbout\": \"Info\",\n  \"components.Settings.manualscan\": \"Scansione manuale della libreria\",\n  \"components.Settings.librariesRemaining\": \"Biblioteche rimanenti: {count}\",\n  \"components.Settings.hostname\": \"Hostname o indirizzo IP\",\n  \"components.Settings.deleteserverconfirm\": \"Sei sicuro/a di voler eliminare questo server?\",\n  \"components.Settings.default4k\": \"4K predefinito\",\n  \"components.Settings.default\": \"Predefinito\",\n  \"components.Settings.currentlibrary\": \"Libreria corrente: {name}\",\n  \"components.Settings.cancelscan\": \"Annulla l'analisi\",\n  \"components.Settings.addsonarr\": \"Aggiungi un server Sonarr\",\n  \"components.Settings.addradarr\": \"Aggiungi un server Radarr\",\n  \"components.Settings.activeProfile\": \"Profilo attivo\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"È necessario selezionare una cartella principale\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"È necessario selezionare un profilo di qualità\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"È necessario fornire un numero di porta valido\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"È necessario dare un nome di server\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"È necessario fornire un hostname o un indirizzo IP valido\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"È necessario fornire una chiave API\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Testa la connessione per caricare le cartelle\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Testa la connessione per caricare profili di qualità\",\n  \"components.Settings.SonarrModal.servername\": \"Nome server\",\n  \"components.Settings.SonarrModal.server4k\": \"Server 4K\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Seleziona una cartella principale\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Seleziona un profilo qualità\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Cartelle stagione\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Cartella principale\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Profilo qualità\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Caricamento delle cartelle…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Caricamento profili qualità…\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Modifica server Sonarr\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Server predefinito\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Aggiungi un nuovo server Sonarr\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL di base\",\n  \"components.Settings.SonarrModal.apiKey\": \"Chiave API\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Cartella principale anime\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Profilo qualità anime\",\n  \"components.Settings.SonarrModal.add\": \"Aggiungi un server\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Totale richieste\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Media totali\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Discussioni su GitHub\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Ottieni aiuto\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"È necessario selezionare una cartella principale\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"È necessario selezionare un profilo di qualità\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"È necessario fornire un numero di porta valido\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"È necessario fornire un nome al server\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"È necessario selezionare una disponibilità minima\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"È necessario fornire un hostname o un indirizzo IP valido\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"È necessario fornire una chiave API\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Connessione a Radarr stabilita con successo!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Impossibile connettersi a Radarr.\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Testa la connessione per caricare le cartelle\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Testa la connessione per caricare i profili qualità\",\n  \"components.Settings.RadarrModal.servername\": \"Nome server\",\n  \"components.Settings.RadarrModal.server4k\": \"Server 4K\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Caricamento delle cartelle…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Caricamento profili di qualità…\",\n  \"components.Settings.RadarrModal.createradarr\": \"Aggiungi un nuovo server Radarr\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL di base\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL webhook\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"È necessario fornire un numero di porta valido\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"È necessario fornire un hostname o un indirizzo IP valido\",\n  \"components.Settings.Notifications.smtpPort\": \"Porta SMTP\",\n  \"components.Settings.Notifications.smtpHost\": \"Host SMTP\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Impostazioni di Discord salvate con successo!\",\n  \"components.Settings.Notifications.authUser\": \"Nome utente SMTP\",\n  \"components.Settings.Notifications.authPass\": \"Password SMTP\",\n  \"components.RequestModal.requestseasons\": \"Richiedi {seasonCount} {seasonCount, plural, one {Stagione} other {Stagioni}}\",\n  \"components.TvDetails.similar\": \"Serie simili\",\n  \"components.TvDetails.showtype\": \"Tipo di serie\",\n  \"components.TvDetails.recommendations\": \"Consigliati\",\n  \"components.TvDetails.overviewunavailable\": \"Trama non disponibile.\",\n  \"components.TvDetails.overview\": \"Trama\",\n  \"components.TvDetails.originallanguage\": \"Lingua originale\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Rete} other {Reti}}\",\n  \"components.Setup.finishing\": \"Finalizzazione…\",\n  \"components.Settings.menuJobs\": \"Processi & Cache\",\n  \"components.Setup.signinMessage\": \"Comincia facendo l'accesso\",\n  \"components.Settings.sonarrsettings\": \"Impostazioni Sonarr\",\n  \"components.Settings.plexsettingsDescription\": \"Configura le impostazioni per il tuo server Plex. Seerr scansiona le tue librerie Plex per determinare la disponibilità dei contenuti.\",\n  \"components.Settings.plexlibrariesDescription\": \"Le librerie che Seerr scansiona per i titoli. Configura e salva le impostazioni di connessione Plex, quindi fai clic sul pulsante qui sotto se non sono elencate librerie.\",\n  \"components.Settings.plexlibraries\": \"Librerie Plex\",\n  \"components.Settings.manualscanDescription\": \"Normalmente, questo verrà eseguito solo una volta ogni 24 ore. Seerr controllerà il server Plex per i nuovi aggiunti in modo più aggressivo. Se è la prima volta che configuri Plex, si consiglia di eseguire una scansione manuale completa della libreria!\",\n  \"components.Settings.port\": \"Porta\",\n  \"components.Setup.configureservices\": \"Configura i servizi\",\n  \"components.Setup.finish\": \"Termina la configurazione\",\n  \"components.Setup.continue\": \"Continua\",\n  \"pages.returnHome\": \"Ritorna alla pagina iniziale\",\n  \"i18n.close\": \"Chiudi\",\n  \"components.Settings.SettingsAbout.timezone\": \"Fuso Orario\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Visualizza su GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Visualizza il registro modifiche\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Registro cambiamenti\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Versioni\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Dati di versione non sono momentaneamente disponibili.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Versione più recente\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Versione attuale\",\n  \"components.UserList.importfromplexerror\": \"Qualcosa è andato storto nell'importare gli utenti Plex.\",\n  \"components.UserList.importfromplex\": \"Importa utenti Plex\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> {userCount, plural, one {utente} other {utenti}} Plex {userCount, plural, one {importato} other {importati}} correttamente!\",\n  \"components.TvDetails.viewfullcrew\": \"Vedi troupe completa\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Troupe completa serie\",\n  \"components.PersonDetails.crewmember\": \"Troupe\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Troupe completa\",\n  \"components.MovieDetails.viewfullcrew\": \"Vedi troupe completa\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Consenti i certificati autofirmati\",\n  \"components.TvDetails.firstAirDate\": \"Prima data di messa in onda\",\n  \"components.CollectionDetails.requestcollection\": \"Richiedi raccolta\",\n  \"components.CollectionDetails.overview\": \"Trama\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Film\",\n  \"components.TvDetails.watchtrailer\": \"Guarda il trailer\",\n  \"components.MovieDetails.watchtrailer\": \"Guarda il trailer\",\n  \"i18n.requested\": \"Richiesto\",\n  \"components.RequestList.RequestItem.failedretry\": \"Qualcosa è andato storto nel riprovare la richiesta.\",\n  \"i18n.retry\": \"Riprova\",\n  \"i18n.failed\": \"Fallito\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Impostazioni di Slack salvate con successo!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Impossibile salvare le impostazioni di Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Abilita Agente\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"È necessario fornire un ID della discussione valido\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Devi fornire un token di autorizzazione del bot\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Impostazioni di Telegram salvate con successo!\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Impossibile salvare le impostazioni di Telegram.\",\n  \"components.Settings.Notifications.senderName\": \"Nome del mittente\",\n  \"components.Settings.Notifications.chatId\": \"ID chat\",\n  \"components.Settings.Notifications.botAPI\": \"Token di autorizzazione bot\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentazione\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Invia notifiche quando gli utenti presentano nuove richieste di media che richiedono approvazione.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Richiesta in attesa di approvazione\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Invia notifiche quando le richieste non vengono aggiunte a Radarr o Sonarr.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Elaborazione della richiesta non riuscita\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Invia notifiche quando i media richiesti diventano disponibili.\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Invia notifiche quando le richieste sono approvate manualmente.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Richiesta approvata\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Richiesta disponibile\",\n  \"i18n.request\": \"Richiedi\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"È necessario fornire una chiave utente o di gruppo valida\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"È necessario fornire un token di applicazione valido\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Chiave utente o di gruppo\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Impostazioni di Pushover salvate con successo!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Impossibile salvare le impostazioni di Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Abilita Agente\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token API applicazione\",\n  \"components.RequestList.sortModified\": \"Ultima modifica\",\n  \"components.RequestList.sortAdded\": \"Più recente\",\n  \"components.RequestList.showallrequests\": \"Mostra tutte le richieste\",\n  \"components.RequestButton.declinerequest4k\": \"Rifiuta la richiesta 4K\",\n  \"components.RequestButton.declinerequest\": \"Rifiuta la richiesta\",\n  \"components.RequestButton.decline4krequests\": \"Rifiuta {requestCount, plural, one {Richiesta 4K} other {{requestCount} Richieste 4K}}\",\n  \"components.RequestButton.approverequests\": \"Approva {requestCount, plural, one {Richiesta} other {{requestCount} Richieste}}\",\n  \"components.RequestButton.approverequest4k\": \"Approva richiesta 4K\",\n  \"components.RequestButton.approverequest\": \"Approva la richiesta\",\n  \"components.RequestButton.approve4krequests\": \"Approva {requestCount, plural, one {Richiesta 4K} other {{requestCount} Richieste 4K}}\",\n  \"components.UserList.creating\": \"Creazione…\",\n  \"components.UserList.createlocaluser\": \"Crea un utente locale\",\n  \"components.UserList.create\": \"Crea\",\n  \"components.UserList.autogeneratepassword\": \"Genera automaticamente la password\",\n  \"components.UserList.password\": \"Password\",\n  \"components.UserList.localuser\": \"Utente locale\",\n  \"components.UserList.usercreatedsuccess\": \"Utente creato correttamente!\",\n  \"components.UserList.usercreatedfailed\": \"Qualcosa è andato storto nel creare l'utente.\",\n  \"components.UserList.validationpasswordminchars\": \"La password è troppo corta; deve avere un minimo di 8 caratteri\",\n  \"components.UserList.passwordinfodescription\": \"Configura un URL dell'applicazione e abilita le notifiche via e-mail per consentire la generazione automatica della password.\",\n  \"components.UserList.email\": \"Indirizzo e-mail\",\n  \"components.RequestButton.viewrequest4k\": \"Visualizza la richiesta 4K\",\n  \"components.RequestButton.viewrequest\": \"Visualizza la richiesta\",\n  \"components.RequestButton.requestmore4k\": \"Richiedi di più in 4K\",\n  \"components.RequestButton.requestmore\": \"Richiedi di più\",\n  \"components.Login.validationpasswordrequired\": \"È necessario fornire una password\",\n  \"components.Login.validationemailrequired\": \"È necessario fornire un indirizzo e-mail valido\",\n  \"components.Login.signinwithoverseerr\": \"Usa il tuo account {applicationTitle}\",\n  \"components.Login.password\": \"Password\",\n  \"components.Login.loginerror\": \"Qualcosa è andato storto durante il tentativo di accesso.\",\n  \"components.Login.email\": \"Indirizzo e-mail\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Guida per variabili di modello\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Abilita Agente\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Intestazione di autorizzazione\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Vedi altro\",\n  \"components.RequestBlock.server\": \"Server di destinazione\",\n  \"components.RequestBlock.rootfolder\": \"Cartella principale\",\n  \"components.RequestBlock.profilechanged\": \"Profilo Qualità\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Invia notifiche quando i media richiesti vengono rifiutati.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Richiesta rifiutata\",\n  \"i18n.experimental\": \"Sperimentale\",\n  \"i18n.edit\": \"Modifica\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Impostazioni di Webhook salvate con successo!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Impossibile salvare le impostazioni di Webhook.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL del webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"È necessario fornire un payload JSON valido\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"Payload JSON reimpostato correttamente!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Ripristino delle impostazioni predefinite\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Payload JSON\",\n  \"components.RequestModal.requestedited\": \"Richiesta di <strong>{title}</strong> modificata correttamente!\",\n  \"components.RequestModal.requestcancelled\": \"Richiesta per <strong>{title}</strong> eliminata.\",\n  \"components.RequestModal.pending4krequest\": \"Richiesta 4K in sospeso\",\n  \"components.RequestModal.errorediting\": \"Qualcosa è andato storto durante la modifica della richiesta.\",\n  \"components.RequestModal.autoapproval\": \"Approvazione automatica\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Cartella principale\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Profilo di qualità\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Server di destinazione\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Standard)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Questa serie è un anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avanzate\",\n  \"components.RequestButton.declinerequests\": \"Rifiuta {requestCount, plural, one {Richiesta} other {{requestCount} Richieste}}\",\n  \"components.RequestBlock.requestoverrides\": \"Aggiramenti della richiesta\",\n  \"components.UserList.bulkedit\": \"Modifica collettiva\",\n  \"components.UserList.userssaved\": \"Permessi salvati con successo!\",\n  \"components.PermissionEdit.users\": \"Gestisci gli utenti\",\n  \"components.PermissionEdit.request4kTv\": \"Richiedi serie in 4K\",\n  \"components.PermissionEdit.request4kMovies\": \"Rechiedi film in 4K\",\n  \"components.PermissionEdit.managerequests\": \"Gestisci Richieste\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Approva Automaticamente le Serie\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Approva Automaticamente i Film\",\n  \"components.PermissionEdit.autoapprove\": \"Approvazione automatica\",\n  \"components.PermissionEdit.advancedrequest\": \"Richieste avanzate\",\n  \"components.PermissionEdit.adminDescription\": \"Accesso amministratore completo. Aggira tutti gli altri permessi.\",\n  \"components.PermissionEdit.admin\": \"Amministratore\",\n  \"components.Login.signinwithplex\": \"Usa il tuo account Plex\",\n  \"components.Login.signinheader\": \"Accedi per continuare\",\n  \"components.Login.signingin\": \"Accesso in corso…\",\n  \"components.Login.signin\": \"Accedi\",\n  \"components.MovieDetails.markavailable\": \"Segna come disponibile\",\n  \"components.MovieDetails.mark4kavailable\": \"Segna come disponibile in 4K\",\n  \"components.Login.forgotpassword\": \"Password dimenticata?\",\n  \"components.Discover.discover\": \"Esplora\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Il volume <code>{appDataPath}</code> non è configurato correttamente. Tutte le modifiche apportate saranno perse quando il container verrà interrotto o riavviato.\",\n  \"components.Settings.serverpresetLoad\": \"Premi il pulsante per caricare i server disponibili\",\n  \"components.Settings.serverpreset\": \"Server\",\n  \"components.Settings.serverRemote\": \"remoto\",\n  \"components.Settings.serverLocal\": \"locale\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Configura e abilita gli agenti di notifica.\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"È necessario selezionare un profilo lingua\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"L'URL di base non deve terminare con una barra obliqua\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"L'URL di base deve avere una barra obliqua\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"L'URL non deve terminare con una barra obliqua\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"È necessario fornire un URL valido\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Connessione a Sonarr stabilita con successo!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Impossibile connettersi a Sonarr.\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Profilo lingua anime\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Verifica la connessione per caricare i profili della lingua\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Abilita Scansione\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Seleziona il profilo della lingua\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Caricamento dei profili di lingua…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Profilo lingua\",\n  \"components.Settings.SonarrModal.externalUrl\": \"URL esterno\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Esegui ora\",\n  \"components.Settings.SettingsJobsCache.process\": \"Processo\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Prossima esecuzione\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tipo\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} avviato.\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr esegue alcune attività di manutenzione come lavori programmati regolarmente, ma possono anche essere attivati manualmente qui sotto. Eseguire manualmente un lavoro non altererà la sua programmazione.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Processi\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Nome processo\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} annullato.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Svuota cache\",\n  \"components.Settings.SettingsJobsCache.command\": \"Comando\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Annulla processo\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Dimensione valore\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Nome cache\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Mancanti\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Dimensione chiave\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Chiavi totali\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Chiamate\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} cache svuotata.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr memorizza nella cache le richieste agli endpoint API esterni per ottimizzare le prestazioni e evitare chiamate API non necessarie.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"L'URL di base non deve terminare con una barra obliqua\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"L'URL di base deve avere una barra obliqua\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"L'URL non deve terminare con una barra obliqua\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"È necessario fornire un URL valido\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Abilita Scansione\",\n  \"components.Settings.RadarrModal.externalUrl\": \"URL esterno\",\n  \"components.Settings.Notifications.validationEmail\": \"È necessario fornire un indirizzo e-mail valido\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"È necessario fornire un URL valido\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"È necessario fornire un URL valido\",\n  \"components.Search.search\": \"Cerca\",\n  \"components.ResetPassword.validationemailrequired\": \"È necessario fornire un indirizzo e-mail valido\",\n  \"components.ResetPassword.validationpasswordrequired\": \"È necessario fornire una password\",\n  \"components.ResetPassword.validationpasswordminchars\": \"La password è troppo corta; dovrebbe avere un minimo di 8 caratteri\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Le password devono coincidere\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"La password è stata reimpostata con successo!\",\n  \"components.ResetPassword.resetpassword\": \"Reimposta la password\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Un collegamento per reimpostare la password sarà inviato all'indirizzo e-mail fornito se è associato a un utente valido.\",\n  \"components.ResetPassword.password\": \"Password\",\n  \"components.ResetPassword.gobacklogin\": \"Ritorna alla pagina di accesso\",\n  \"components.ResetPassword.emailresetlink\": \"Invia un link di recupero via e-mail\",\n  \"components.ResetPassword.email\": \"Indirizzo e-mail\",\n  \"components.ResetPassword.confirmpassword\": \"Conferma la password\",\n  \"components.RequestModal.requesterror\": \"Qualcosa è andato storto durante l'invio della richiesta.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Non siamo riusciti a trovare una corrispondenza per questa serie. Seleziona la corrispondenza corretta dall'elenco seguente.\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Richiedi come\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Profilo lingua\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Concede il permesso di visualizzare le richieste di altri utenti.\",\n  \"components.PermissionEdit.viewrequests\": \"Visualizza le richieste\",\n  \"components.PermissionEdit.usersDescription\": \"Concede il permesso di gestire gli utenti. Gli utenti con questo permesso non possono modificare gli utenti con privilegio di Amministratore, o concederlo.\",\n  \"components.PermissionEdit.requestDescription\": \"Concedere l'autorizzazione per richiedere media non 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Concede l'autorizzazione per richiedere serie in 4K.\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Concede l'autorizzazione per richiedere film in 4K.\",\n  \"components.PermissionEdit.request4kDescription\": \"Concede l'autorizzazione per richiedere media in 4K.\",\n  \"components.PermissionEdit.request4k\": \"Richiesta 4K\",\n  \"components.PermissionEdit.request\": \"Richiesta\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Concede il permesso di gestire le richieste. Tutte le richieste fatte da un utente con questo permesso sono automaticamente approvate.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Concede l'approvazione automatica per le richieste di serie non in 4K.\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Concede l'approvazione automatica per le richieste di film non in 4K.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Concede l'approvazione automatica per tutte le richieste non in 4K.\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Concede il permesso di modificare opzioni di richiesta avanzate.\",\n  \"i18n.advanced\": \"Avanzato\",\n  \"components.UserList.validationEmail\": \"Email richiesta\",\n  \"components.UserList.users\": \"Utenti\",\n  \"components.Setup.setup\": \"Impostazione\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Elenco dei server Plex recuperato con successo!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Impossibile recuperare l'elenco dei server Plex.\",\n  \"components.Settings.toastPlexRefresh\": \"Recupero dell'elenco dei server da Plex…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Connessione a Plex stabilita con successo!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Impossibile connettersi a Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"Tentativo di connessione a Plex…\",\n  \"components.Settings.serverpresetRefreshing\": \"Recupero di server…\",\n  \"components.Settings.serverpresetManualMessage\": \"Configurazione manuale\",\n  \"components.TvDetails.nextAirDate\": \"Prossima data di messa in onda\",\n  \"components.Settings.settingUpPlexDescription\": \"Per impostare Plex, potete inserire i dati manualmente o selezionare un server recuperato da <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Premi il pulsante a destra del menu a tendina per recuperare la lista di server disponibili.\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Invia notifiche senza suono\",\n  \"components.Settings.Notifications.sendSilently\": \"Invia silenziosamente\",\n  \"components.UserList.sortCreated\": \"Data di unione\",\n  \"components.UserList.sortRequests\": \"Conteggio richieste\",\n  \"components.UserList.sortDisplayName\": \"Nome da mostrare\",\n  \"components.PermissionEdit.autoapprove4k\": \"Auto-approva 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Concede l'approvazione automatica per le richieste di film in 4K.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Auto-approva i film in 4K\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Concede l'approvazione automatica per le richieste di serie in 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Auto-approva le serie in 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Concede l'approvazione automatica per tutte le richieste 4K.\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profilo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Impostazioni Notifiche\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"Il <FindDiscordIdLink>numero ID a più cifre</FindDiscordIdLink> associato all'account utente\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID utente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Impostazioni salvate con successo!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Qualcosa è andato storto nel salvare le impostazioni.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Utente Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Utente locale\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Impostazioni generali\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Nome da mostrare\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Modifica le impostazioni\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Visualizza profilo\",\n  \"components.UserList.userfail\": \"Qualcosa è andato storto durante il salvataggio dei permessi.\",\n  \"components.UserList.edituser\": \"Modifica le autorizzazioni dell'utente\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"È necessario fornire un token di accesso\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Impostazioni di Pushover salvate correttamente!\",\n  \"components.Layout.UserDropdown.settings\": \"Impostazioni\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Impossibile salvare le impostazioni di Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Abilita Agente\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Token di accesso\",\n  \"components.UserProfile.recentrequests\": \"Richieste Recenti\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Autorizzazioni\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notifiche\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Generali\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Password\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Permessi salvati correttamente!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Qualcosa è andato storto nel salvare le impostazioni.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Autorizzazioni\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"La password è troppo corta; deve avere un minimo di 8 caratteri\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"È necessario fornire una nuova password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"È necessario fornire la password attuale\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Le password devono coincidere\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"È necessario confermare la nuova password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Password salvata correttamente!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Qualcosa è andato storto durante il salvataggio della password.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nuova password\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Password attuale\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Conferma la password\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"È necessario fornire un ID utente valido\",\n  \"components.CollectionDetails.requestcollection4k\": \"Richiedi Raccolta in 4K\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Ricerca per Regione\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Lingua da scoprire\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.email\": \"Email\",\n  \"components.RegionSelector.regionDefault\": \"Tutte le regioni\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtra i contenuti in base alla disponibilità della regione\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtra i contenuti per lingua originale\",\n  \"components.Discover.upcomingtv\": \"Serie in uscita\",\n  \"components.RegionSelector.regionServerDefault\": \"Predefinito ({region})\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Non hai il permesso di modificare la password di questo utente.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Utente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Ruolo\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Proprietario\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Amministratore\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Tipo di account\",\n  \"components.UserList.owner\": \"Proprietario\",\n  \"components.UserList.accounttype\": \"Tipo\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Serie di {network}\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Film di {genre}\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Reimposta sincronizzazione di scaricamento\",\n  \"i18n.loading\": \"Caricamento…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"È necessario fornire un ID chat valido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Inizia una chat</TelegramBotLink>, aggiungi <GetIdBotLink>@get_id_bot</GetIdBotLink>, ed esegui il comando <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID chat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Invia notifiche senza suono\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Invia silenziosamente\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Stagione} other {# Stagioni}}\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Task sconosciuto\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Scarica sincronizzazione\",\n  \"components.Settings.Notifications.botUsername\": \"Username del Bot\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Serie di {genre}\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Film di {studio}\",\n  \"components.Settings.scanning\": \"Sincronizzazione…\",\n  \"components.Settings.scan\": \"Sincronizza Librerie\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Scansione Sonarr\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Scansione Radarr\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Scansione aggiunti di recente su Plex\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Scansione completa della libreria di Plex\",\n  \"components.Settings.Notifications.validationUrl\": \"È necessario fornire un URL valido\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL avatar bot\",\n  \"components.RequestList.RequestItem.requested\": \"Richiesto\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} da {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Modificato\",\n  \"components.Discover.StudioSlider.studios\": \"Studi\",\n  \"components.Discover.NetworkSlider.networks\": \"Reti\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Serie in {language}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Film in {language}\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID utente: {userid}\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Iscritto/a dal {joindate}\",\n  \"components.Settings.menuUsers\": \"Utenti\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Configura le impostazioni utente globali e predefinite.\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Impostazioni Utente\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Impostazioni utente salvate correttamente!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Qualcosa è andato storto durante il salvataggio delle impostazioni.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Abilita Accesso Locale\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Autorizzazioni Predefinite\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Invia notifiche quando gli utenti presentano nuove richieste che vengono approvate automaticamente.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Richiesta approvata automaticamente\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Chiave privata PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Firma i messaggi di posta elettronica crittografati utilizzando <OpenPgpLink> OpenPGP </OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPassword\": \"Password PGP\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Generi Serie\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Generi film\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Non hai l'autorizzazione per modificare le impostazioni di questo utente.\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Non è possibile modificare le proprie autorizzazioni.\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minuti\",\n  \"components.TvDetails.episodeRuntime\": \"Durata di un episodio\",\n  \"components.RequestModal.alreadyrequested\": \"Già richiesto\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Generi serie\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Generi film\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Firma i messaggi di posta elettronica crittografati utilizzando <OpenPgpLink> OpenPGP </OpenPgpLink>\",\n  \"pages.somethingwentwrong\": \"Qualcosa è andato storto\",\n  \"pages.serviceunavailable\": \"Servizio non disponibile\",\n  \"pages.pagenotfound\": \"Pagina non trovata\",\n  \"pages.internalservererror\": \"Errore interno del server\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"i18n.usersettings\": \"Impostazioni utente\",\n  \"i18n.settings\": \"Impostazioni\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Qualcosa è andato storto durante il salvataggio della password. La password attuale è stata inserita correttamente?\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notifiche\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Generali\",\n  \"components.Settings.services\": \"Servizi\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Notifiche\",\n  \"components.Settings.SettingsLogs.logs\": \"Registri\",\n  \"components.Settings.SettingsUsers.users\": \"Utenti\",\n  \"components.Settings.SettingsLogs.time\": \"Data e ora\",\n  \"components.Settings.SettingsLogs.showall\": \"Mostra tutti i registri\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Riprendi\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pausa\",\n  \"components.Settings.SettingsLogs.message\": \"Messaggio\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Puoi anche visualizzare questi registri direttamente tramite <code>stdout</code>, o in <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.level\": \"Gravità\",\n  \"components.Settings.SettingsLogs.label\": \"Etichetta\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Attenzione\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.SettingsLogs.filterError\": \"Errore\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Debug\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Processi e cache\",\n  \"components.Settings.SettingsAbout.about\": \"Info\",\n  \"components.ResetPassword.passwordreset\": \"Reimposta la password\",\n  \"components.Settings.enablessl\": \"Usa SSL\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Dettagli registro\",\n  \"components.Settings.SettingsLogs.extraData\": \"Dati aggiuntivi\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Copia negli appunti\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Messaggio di registro copiato negli appunti.\",\n  \"components.UserList.nouserstoimport\": \"Non ci sono utenti Plex da importare.\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Data di nascita {birthdate}\",\n  \"components.PersonDetails.alsoknownas\": \"Altri nomi: {names}\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"components.MovieDetails.originaltitle\": \"Titolo Originale\",\n  \"i18n.view\": \"Vista\",\n  \"i18n.tvshow\": \"Serie\",\n  \"i18n.testing\": \"Test in corso…\",\n  \"i18n.test\": \"Test\",\n  \"i18n.status\": \"Stato\",\n  \"i18n.showingresults\": \"Mostrando <strong>{from}</strong> a <strong>{to}</strong> di <strong>{total}</strong> risultati\",\n  \"i18n.resultsperpage\": \"Mostra {pageSize} risultati per pagina\",\n  \"i18n.saving\": \"Salvando…\",\n  \"i18n.save\": \"Salva Modifiche\",\n  \"i18n.requesting\": \"Richiesta in corso…\",\n  \"i18n.request4k\": \"Richiedi in 4K\",\n  \"i18n.previous\": \"Precedente\",\n  \"i18n.notrequested\": \"Non Richiesto\",\n  \"i18n.noresults\": \"Nessun risultato.\",\n  \"i18n.next\": \"Avanti\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.canceling\": \"Annullamento…\",\n  \"i18n.back\": \"Indietro\",\n  \"i18n.areyousure\": \"Sei sicuro?\",\n  \"i18n.all\": \"Tutti\",\n  \"components.UserProfile.unlimited\": \"Illimitato\",\n  \"components.UserProfile.totalrequests\": \"Richieste Totali\",\n  \"components.UserProfile.seriesrequest\": \"Richieste Serie\",\n  \"components.UserProfile.requestsperdays\": \"{limit, plural, one {rimanente} other {rimanenti}}\",\n  \"components.UserProfile.pastdays\": \"{type} (ultimi {days} giorni)\",\n  \"components.UserProfile.movierequests\": \"Richieste Film\",\n  \"components.UserProfile.limit\": \"{remaining} di {limit}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Limite Richiesta Serie\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Limite Richiesta Film\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Ignora Limite Globale\",\n  \"components.TvDetails.originaltitle\": \"Titolo Originale\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Limite Globale Richiesta Serie\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Limite Globale Richiesta Film\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {stagione} other {stagioni}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"stagione\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Questo utente deve avere almeno <strong>{seasons}</strong> {seasons, plural, one {richiesta rimanente} other {richieste rimanenti}} per poter richiedere questa serie.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Devi avere almeno <strong>{seasons}</strong> {seasons, plural, one {richiesta rimanente} other {richieste rimanenti}} per poter richiedere questa serie.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {richiesta rimanente} other {richieste rimanenti}}\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Puoi vedere un riassunto sui limiti di questo utente nella sua <ProfileLink>pagina profilo</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Puoi vedere un riepilogo dei tuoi limiti nella <ProfileLink>pagina del tuo profilo</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Non rimangono abbastanza stagioni da richiedere\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {film}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Questo utente è autorizzato a richiedere <strong>{limit}</strong> {type} ogni <strong>{days}</strong> giorni.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Puoi richiedere <strong>{limit}</strong> {type} ogni <strong>{days}</strong> giorni.\",\n  \"components.QuotaSelector.unlimited\": \"Illimitato\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Tutte le lingue\",\n  \"components.LanguageSelector.languageServerDefault\": \"Predefinito ({language})\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Verifica la connessione per caricare i tag\",\n  \"components.Settings.SonarrModal.tags\": \"Tag\",\n  \"components.Settings.SonarrModal.selecttags\": \"Seleziona i tag\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Nessun tag.\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Caricamento tag…\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Modifica server Sonarr 4K\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Server 4K predefinito\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Aggiungi un nuovo server Sonarr 4K\",\n  \"components.Settings.SonarrModal.animeTags\": \"Tag Anime\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Verifica la connessione per caricare i tag\",\n  \"components.Settings.RadarrModal.tags\": \"Tag\",\n  \"components.Settings.RadarrModal.selecttags\": \"Seleziona i tag\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Nessun tag.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Caricamento tag…\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Modifica server Radarr 4K\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Server 4K predefinito\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Aggiungi un nuovo server Radarr 4K\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Tag\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Seleziona i tag\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Nessun tag.\",\n  \"components.Layout.VersionStatus.outofdate\": \"Non aggiornato\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {versione} other {versioni}} indietro\",\n  \"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.\",\n  \"components.Settings.noDefaultServer\": \"Almeno un server {serverType} deve essere contrassegnato come predefinito affinché le richieste {mediaType} possano essere processate.\",\n  \"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} <strong>NON</strong> dovrebbe essere designato come server 4K.\",\n  \"components.Settings.mediaTypeSeries\": \"serie\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Aggiornato\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Non aggiornato\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"È necessario fornire una chiave privata PGP valida\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"È necessario fornire una password PGP\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Consenti inoltre agli utenti di avviare una chat con il tuo bot e configurare le proprie notifiche personali\",\n  \"components.RequestModal.pendingapproval\": \"La richiesta è in attesa di approvazione.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} non trovato\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Elimina Richiesta\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Annulla Richiesta\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} non trovato\",\n  \"components.RequestCard.deleterequest\": \"Elimina Richiesta\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Tipi di Notifica\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Sviluppo di Seerr\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stabile\",\n  \"i18n.retrying\": \"Nuovo tentativo in corso …\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Il tuo account attualmente non ha una password impostata. Configura una password qui sotto per abilitare l'accesso come \\\"utente locale\\\" usando il tuo indirizzo email.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Questo account utente attualmente non ha una password impostata. Configura una password qui sotto per permettere a questo account di accedere come \\\"utente locale.\\\"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"È necessario fornire una chiave pubblica PGP valida\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Impostazioni di Telegram salvate con successo!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Impossibile salvare le impostazioni di Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Crittografa i messaggi di posta elettronica usando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Chiave pubblica PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Impostazioni Email salvate con successo!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Impossibile salvare le impostazioni Email.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Impostazioni di Discord salvate con successo!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Impossibile salvare le impostazioni di Discord.\",\n  \"components.UserList.usercreatedfailedexisting\": \"L'indirizzo e-mail fornito è già in uso da un altro utente.\",\n  \"components.UserList.autogeneratepasswordTip\": \"Invia una password generata automaticamente all'utente via e-mail\",\n  \"components.Settings.serverSecure\": \"sicuro\",\n  \"components.RequestModal.edit\": \"Modifica Richiesta\",\n  \"components.RequestList.RequestItem.editrequest\": \"Modifica Richiesta\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Abilita Ricerca Automatica\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Abilita Ricerca Automatica\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Notifiche Web\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Lingua di visualizzazione\",\n  \"components.Settings.webpush\": \"Notifica Web\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Impostazioni di notifica web salvate con successo!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Impossibile salvare le impostazioni di notifica web.\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Abilita Agente\",\n  \"components.Settings.noDefault4kServer\": \"Un server 4K {serverType} deve essere contrassegnato come predefinito per permettere agli utenti di inviare richieste 4K {mediaType}.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.PermissionEdit.requestTvDescription\": \"Concedere l'autorizzazione per richiedere serie non 4K.\",\n  \"components.PermissionEdit.requestTv\": \"Richiedi Serie\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Concedere il permesso di richiedere film non in 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Richiedi Film\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Invio notifica di prova webhook…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Invio notifica di prova webhook non riuscito.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Notifica di prova web push inviata!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Invio notifica di prova web push…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Impossibile inviare la notifica di prova Web push.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Notifica di prova con Slack inviata!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Invio della notifica di prova con Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Invio della notifica di prova Slack non riuscito.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Notifica di prova Pushover inviata!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Invio notifica di prova Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Impossibile inviare la notifica di prova Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Notifica di prova Pushbullet inviata!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Invio notifica di prova Pushbullet …\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Invio della notifica di prova Pushbullet non riuscito.\",\n  \"components.DownloadBlock.estimatedtime\": \"Stimato {time}\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Usa TLS Implicito\",\n  \"components.Settings.Notifications.encryptionTip\": \"Solitamente, TLS Implicito usa la porta 465 e STARTTLS usa la porta 587\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Usa sempre STARTTLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"Nessuna\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Usa STARTTLS se disponibile\",\n  \"components.Settings.Notifications.encryption\": \"Metodo di crittografia\",\n  \"components.Settings.Notifications.chatIdTip\": \"Inizia una chat con il tuo bot, aggiungi <GetIdBotLink>@get_id_bot</GetIdBotLink>, ed emetti il comando <code>/my_id</code>\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Crea un bot</CreateBotLink> per l'uso con Seerr\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Notifica Webhook di prova inviata!\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Crea un'integrazione <WebhookLink>Incoming Webhook</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Il tuo identificatore <UsersGroupsLink>utente o gruppo</UsersGroupsLink> di 30 caratteri\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registra un'applicazione</ApplicationRegistrationLink> per l'uso con Seerr\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Crea un token dalle tue <PushbulletSettingsLink>Impostazioni account</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Invio della notifica di prova Discord non riuscito.\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Crea un <DiscordWebhookLink>integrazione webhook</DiscordWebhookLink> nel server\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Notifica di prova con Telegram inviata!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Invio notifica di prova con Telegram…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Impossibile inviare notifica di prova con Telegram.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Notifica email di prova inviata!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Invio notifica email di prova…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Impossibile inviare la notifica email di prova.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Invio della notifica Discord di prova…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Notifica Discord di prova inviata!\",\n  \"components.UserList.localLoginDisabled\": \"L'impostazione <strong>Abilita Accesso Locale</strong> è attualmente disabilitata.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Predefinito ({language})\",\n  \"components.Settings.webAppUrlTip\": \"Indirizza opzionalmente gli utenti alla web app sul tuo server invece che alla web app \\\"ospitata\\\"\",\n  \"components.Settings.webAppUrl\": \"URL <WebAppLink>Web App</WebAppLink>\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Permetti agli utenti di {mediaServerName} di accedere senza essere prima importati\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Abilita nuovo accesso con {mediaServerName}\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Per ricevere notifiche push web, Seerr deve essere servito tramite HTTPS.\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Richiesto\",\n  \"components.RequestCard.failedretry\": \"Qualcosa è andato storto nel riprovare la richiesta.\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Consenti agli utenti di accedere utilizzando la mail e la password\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Permessi assegnati ai nuovi utenti\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {stagione} other {stagioni}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {film}}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {giorno} other {giorni}}\",\n  \"components.Settings.Notifications.validationTypes\": \"È necessario selezionare almeno un tipo di notifica\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"È necessario selezionare almeno un tipo di notifica\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"È necessario selezionare almeno un tipo di notifica\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"È necessario selezionare almeno un tipo di notifica\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"È necessario selezionare almeno un tipo di notifica\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Ricevi una notifica quando altri utenti presentano nuove richieste che richiedono l'approvazione.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Ricevi una notifica quando le richieste non vengono aggiunte a Radarr o Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Ricevi una notifica quando le tue richieste vengono rifiutate.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Ricevi una notifica quando le tue richieste diventano disponibili.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Ricevi una notifica quando le tue richieste vengono approvate.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Ricevi una notifica quando altri utenti inviano nuove richieste che vengono approvate automaticamente.\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Lingua Interfaccia\",\n  \"components.MovieDetails.showmore\": \"Mostra di più\",\n  \"components.MovieDetails.showless\": \"Mostra meno\",\n  \"components.TvDetails.streamingproviders\": \"Ora in streaming su\",\n  \"components.MovieDetails.streamingproviders\": \"Ora in streaming su\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.IssueComment.edit\": \"Modifica commento\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Inviato {relativeTime} da{username}\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Devi inserire un messaggio\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Elimina segnalazione\",\n  \"components.IssueDetails.comments\": \"Commenti\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Qualcosa è andato storto durante la modifica della descrizione.\",\n  \"components.IssueDetails.closeissue\": \"Chiudi segnalazione\",\n  \"components.IssueDetails.closeissueandcomment\": \"Chiudi con un commento\",\n  \"components.IssueDetails.deleteissue\": \"Elimina segnalazione\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Sei sicuro di voler eliminare questa segnalazione?\",\n  \"components.IssueDetails.issuepagetitle\": \"Segnalazione\",\n  \"components.IssueDetails.issuetype\": \"Tipo\",\n  \"components.IssueDetails.problemepisode\": \"Episodio coinvolto\",\n  \"components.IssueDetails.problemseason\": \"Stagione coinvolta\",\n  \"components.IssueDetails.unknownissuetype\": \"Sconosciuto\",\n  \"components.IssueDetails.toastissuedeleted\": \"Segnalazione eliminata con successo!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Qualcosa è andato storto durante l'eliminazione della segnalazione.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Stato segnalazione aggiornato correttamente!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Qualcosa è andato storto durante l'aggiornamento dello stato della segnalazione.\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Episodio coinvolto\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Episodio coinvolto\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Stagione coinvolta\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Qualcosa è andato storto durante l'invio della segnalazione.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Segnalazione per <strong>{title}</strong> inviata correttamente!\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Devi fornire una descrizione\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Qual è il problema?\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueModal.issueOther\": \"Altro\",\n  \"components.IssueModal.issueSubtitles\": \"Sottotitolo\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.ManageSlideOver.markavailable\": \"Segna come disponibile\",\n  \"components.ManageSlideOver.tvshow\": \"serie tv\",\n  \"components.IssueDetails.IssueDescription.description\": \"Descrizione\",\n  \"components.IssueList.IssueItem.viewissue\": \"Visualizza segnalazione\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Sei sicuro di voler eliminare questo commento?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Elimina commento\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Inviato {relativeTime} da {username} (Modificato)\",\n  \"components.IssueDetails.leavecomment\": \"Commento\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Modifica descrizione\",\n  \"components.IssueDetails.allepisodes\": \"Tutti gli episodi\",\n  \"components.IssueDetails.allseasons\": \"Tutte le stagioni\",\n  \"components.IssueDetails.episode\": \"Episodio {episodeNumber}\",\n  \"components.IssueDetails.lastupdated\": \"Ultimo aggiornamento\",\n  \"components.IssueDetails.nocomments\": \"Nessun commento.\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Stato\",\n  \"components.IssueDetails.season\": \"Stagione {seasonNumber}\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tipo\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Sconosciuto\",\n  \"components.IssueList.sortModified\": \"Ultima modifica\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episodio {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Tutti gli episodi\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Tutte le stagioni\",\n  \"components.IssueList.issues\": \"Segnalazioni\",\n  \"components.IssueList.sortAdded\": \"Più recente\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Descrizione della segnalazione modificata con successo!\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Fornisci una descrizione dettagliata del problema riscontrato.\",\n  \"components.IssueList.showallissues\": \"Mostra tutte le segnalazioni\",\n  \"components.IssueDetails.reopenissue\": \"Riapri segnalazione\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Riapri con un commento\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Segnala un problema\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Stagione {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Invia segnalazione\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Visualizza segnalazione\",\n  \"components.Layout.Sidebar.issues\": \"Segnalazioni\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Pulisci dati\",\n  \"components.ManageSlideOver.downloadstatus\": \"Downloads\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Nessuna richiesta.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Richieste\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Gestisci {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Segna come disponibile in 4K\",\n  \"components.IssueDetails.openinarr\": \"Apri in {arr}\",\n  \"components.IssueDetails.playonplex\": \"Guarda su {mediaServerName}\",\n  \"components.ManageSlideOver.openarr\": \"Apri in {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Apri in 4K {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Guarda in 4K su Plex\",\n  \"components.IssueDetails.openin4karr\": \"Apri in 4k {arr}\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Episodio} other {Episodi}}\",\n  \"components.PermissionEdit.createissuesDescription\": \"Concedi il permesso di segnalare problemi con i contenuti.\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Stagione} other {Stagioni}}\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Segnalazioni aperte\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extra\",\n  \"components.PermissionEdit.manageissues\": \"Gestisci segnalazioni\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Ricevi una notifica quando altri utenti commentano nella segnalazione.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Commenti segnalazione\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Invia notifiche quando le segnalazioni ricevono nuovi commenti.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} aperto {relativeTime} da {username}\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} da {user}\",\n  \"components.PermissionEdit.viewissues\": \"Guarda segnalazione\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Concedi permesso per gestire le segnalazioni del contenuto.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Qualcosa è andato storto nel salvataggio del job.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Ricevi una notifica quando una segnalazione riceve nuovi commenti.\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modifica Job\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Ogni {jobScheduleHours, plural, one {ora} other {{jobScheduleHours} ore}}\",\n  \"components.IssueList.IssueItem.opened\": \"Aperto\",\n  \"components.PermissionEdit.createissues\": \"Segnala problemi\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Ottieni una notifica quando altri utenti segnalano dei problemi.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Ricevi una notifica quando le tue segnalazioni vengono risolte.\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Concedi l'autorizzazione per visualizzare le segnalazioni sui media effettuati da altri utenti.\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Nuova frequenza\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Ogni {jobScheduleMinutes, plural, one {minuto} other {{jobScheduleMinutes} minuti}}\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Job modificato correttamente!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Impossibile salvare le impostazioni Pushover.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Impostazioni Pushover salvate con successo!\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Questo rimuoverà irreversibilmente tutti i dati per questo {mediaType}, incluse eventuali richieste. Se questo elemento esiste nella tua libreria {mediaServerName}, le informazioni multimediali verranno ricreate durante la scansione successiva.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problema Segnalato\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Invia una notifica quando un problema viene segnalato.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problema risolto\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Invia una notifica quando un problema viene risolto.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Token di accesso\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"API Token applicazione\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Chiave utente o di un gruppo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Crea un token dalle tue <PushbulletSettingsLink>Impostazioni Account</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Impostazioni di Pushbullet salvate con successo!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Impossibile salvare le impostazioni di Pushbullet.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registra un applicazione</ApplicationRegistrationLink> per usarla con {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"La tua stringa di 30 caratteri <UsersGroupsLink>per identificare utente o un gruppo</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Devi fornire un access token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Devi fornire un application token valido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Devi fornire una chiave utente o di gruppo valida\",\n  \"i18n.resolved\": \"Risolto\",\n  \"i18n.open\": \"Aperto\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Stai eseguendo il ramo <code>develop</code> di Seerr, ciò è consigliato solo per coloro che contribuiscono allo sviluppo o assistono con i test più avanzati.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Ricevi una notifica quanto le segnalazioni vengono riaperte da altri utenti.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Ricevi una notifica quanto le segnalazioni vengono risolte da altri utenti.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Segnalazione Riaperta\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Invia una notifica quando le segnalazioni vengono riaperte.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Ricevi una notifica quanto le tue segnalazioni vengono riaperte.\",\n  \"components.RequestModal.requestseasons4k\": \"Richiedi {seasonCount} {seasonCount, plural, one {Stagione} other {Stagioni}} in 4K\",\n  \"components.RequestModal.selectmovies\": \"Film selezionati\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {Paese} other {Paesi}} di produzione\",\n  \"components.TvDetails.productioncountries\": \"{countryCount, plural, one {Paese} other {Paesi}} di produzione\",\n  \"components.RequestModal.requestmovies\": \"Richiedi {count} {count, plural, one {Film} other {Films}}\",\n  \"components.RequestModal.requestmovies4k\": \"Richiedi {count} {count, plural, one {Film} other {Films}} in 4K\",\n  \"components.IssueDetails.commentplaceholder\": \"Aggiungi un commento…\",\n  \"components.RequestModal.requestApproved\": \"Richiesta di <strong>{title}</strong> approvata!\",\n  \"components.RequestModal.approve\": \"Approva richiesta\",\n  \"components.Settings.RadarrModal.announced\": \"Annunciato\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Al cinema\",\n  \"components.Settings.RadarrModal.released\": \"Rilasciato\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Abilita agente\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Server URL\",\n  \"i18n.import\": \"Importa\",\n  \"components.ManageSlideOver.alltime\": \"Sempre\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Media\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Media 4K\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Segna tutte le stagioni disponibili in 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Segna tutte le stagioni disponibili\",\n  \"components.ManageSlideOver.opentautulli\": \"Apri in Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Ultimi {days, number} Giorni\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {riproduzione} other {riproduzioni}}\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Impossibile salvare le impostazioni di notifica di Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Impossibile inviare la notifica di prova Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Invio notifica di prova Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Notifica di prova Gotify inviata!\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Devi fornire un application token\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Devi selezionare almeno un tipo di notifica\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Devi fornire un URL valido\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"L'URL non deve terminare con una barra obliqua\",\n  \"components.Settings.urlBase\": \"URL di base\",\n  \"components.Settings.externalUrl\": \"URL esterno\",\n  \"components.Settings.tautulliApiKey\": \"Chiave API\",\n  \"components.Settings.tautulliSettings\": \"Impostazioni di Tautulli\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Impostazioni di Tautulli salvate con successo!\",\n  \"components.Settings.validationApiKey\": \"Devi fornire una chiave API\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"L’URL di base deve contenere una barra obliqua\",\n  \"components.Settings.validationUrlTrailingSlash\": \"L'URL non deve terminare con una barra obliqua\",\n  \"components.UserList.newplexsigninenabled\": \"L'impostazione <strong>Abilita nuovo accesso Plex</strong> è attualmente abilitata. Gli utenti Plex con accesso alla libreria non devono essere importati per accedere.\",\n  \"i18n.importing\": \"Importazione…\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avanzato\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Impostazioni di notifica Gotify salvate correttamente!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token applicazione\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Qualcosa è andato storto durante il salvataggio delle impostazioni di Tautulli.\",\n  \"components.Settings.Notifications.enableMentions\": \"Abilita menzioni\",\n  \"components.UserProfile.recentlywatched\": \"Visto di recente\",\n  \"components.Settings.validationUrl\": \"Devi fornire un URL valido\",\n  \"components.Settings.tautulliSettingsDescription\": \"Configura facoltativamente le impostazioni per il tuo server Tautulli. Seerr recupera i dati della cronologia di visione dei tuoi media Plex da Tautulli.\",\n  \"components.ManageSlideOver.playedby\": \"Riprodotto da\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"L'URL di base non deve terminare con una barra obliqua\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Tag del canale\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"È necessario fornire un ID Utente Discord valido\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID Utente Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Il <FindDiscordIdLink>numero ID a più cifre</FindDiscordIdLink> associato al tuo account utente Discord\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Cartella applicazione\",\n  \"components.RequestBlock.languageprofile\": \"Lingua Profilo\",\n  \"components.MovieDetails.digitalrelease\": \"Uscita versione digitale\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"La tua lista\",\n  \"components.Discover.plexwatchlist\": \"La tua lista da guardare Plex\",\n  \"components.PermissionEdit.autorequest\": \"Richiesta automatica\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex Watchlist\",\n  \"components.MovieDetails.managemovie\": \"Gestisci Film\",\n  \"components.MovieDetails.physicalrelease\": \"Uscita versione fisica\",\n  \"components.MovieDetails.theatricalrelease\": \"Uscita nelle sale\",\n  \"components.MovieDetails.reportissue\": \"Segnala un problema\",\n  \"components.Discover.CreateSlider.addSlider\": \"Aggiungi Slider\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Cerca parole chiave…\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Cerca generi…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Cerca studi…\",\n  \"components.Discover.CreateSlider.nooptions\": \"Nessun risultato.\",\n  \"components.AirDateBadge.airedrelative\": \"Trasmesso {relativeTime}\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Nome Slider\",\n  \"components.Discover.CreateSlider.starttyping\": \"Inizia a scrivere per cercare.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Devi inserire un valore di dati.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Devi inserire un titolo.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Film\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Impossibile eliminare slider.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Slider eliminato correttamente.\",\n  \"components.Discover.createnewslider\": \"Crea nuovo Slider\",\n  \"components.AirDateBadge.airsrelative\": \"In onda {relativeTime}\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# filtro attivo} other {# filtri attivi}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Film\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popolarità Crescente\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Data di Uscita Crescente\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popolarità Decrescente\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Data di Uscita Decrescente\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Titolo (A-Z) Crescente\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Titolo (Z-A) Decrescente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Voto TMDB Crescente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Voto TMDB Decrescente\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Serie\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Data messa in onda Crescente\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Data messa in onda Decrescente\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popolarità Crescente\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popolarità Decrescente\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Crea Slider Personalizzato\",\n  \"components.Discover.CreateSlider.addfail\": \"Impossibile creare un nuovo slider.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Modifica Slider\",\n  \"components.Discover.CreateSlider.editfail\": \"Impossibile modificare lo slider.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Modifica slider e salva le impostazioni di ricerca personalizzate.\",\n  \"components.Discover.CreateSlider.needresults\": \"Devi avere almeno 1 risultato.\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Fornire un TMDB Keyword ID\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Fornire un TMDB Genre ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Fornire un TMDB Network ID\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Fornire una query di ricerca\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Fornire un TMDB Studio ID\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Attiva/disattiva visibilità\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Rimuovi\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Aggiunti di recente\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {#filtro attivo} other {# filtri attivi}}\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Titolo (A-Z) Crescente\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Numero di voti tra {minValue} e {maxValue}\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB Film Parola chiave\",\n  \"components.Discover.tmdbsearch\": \"TMDB Cerca\",\n  \"components.Discover.tvgenres\": \"Serie Generi\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB Film Servizi di streaming\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Richieste Film\",\n  \"components.Layout.Sidebar.browsetv\": \"Serie\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Richieste Serie\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"I media aggiunti alla tua <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> appariranno qui.\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB Film Genere\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB Serie Genere\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB Serie Parola chiave\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB Punteggio Decrescente\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Resetta Filtri Attivi\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtri\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Data messa in onda\",\n  \"components.Discover.FilterSlideover.from\": \"Da\",\n  \"components.Discover.FilterSlideover.genres\": \"Generi\",\n  \"components.Discover.FilterSlideover.keywords\": \"Parole chiave\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Lingua Originale\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Punteggi tra {minValue} e {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Data di rilascio\",\n  \"components.Discover.FilterSlideover.runtime\": \"Durata\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minuti durata\",\n  \"components.Discover.FilterSlideover.to\": \"A\",\n  \"components.Discover.customizediscover\": \"Personalizza Esplora\",\n  \"components.Layout.UserDropdown.requests\": \"Richieste\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Stagione {seasonNumber} Episodio {episodeNumber}\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"La tua Plex Watchlist\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Titolo (Z-A) Decrescente\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB Punteggio Crescente\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Servizi di streaming\",\n  \"components.Discover.emptywatchlist\": \"I media aggiunti alla tua <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> appariranno qui.\",\n  \"components.Layout.Sidebar.browsemovies\": \"Film\",\n  \"components.Selector.showmore\": \"Mostra di più\",\n  \"components.Selector.starttyping\": \"Inizia a digitare per cercare.\",\n  \"components.Settings.SettingsMain.apikey\": \"Chiave API\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Titolo applicazione\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Impostazioni generali\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Nascondi media disponibili\",\n  \"components.Settings.SettingsMain.locale\": \"Lingua interfaccia\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Lingua ricerca\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtra contenuti per lingua originale\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Nuova chiave API generata con successo!\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Qualcosa è andato storto durante il salvataggio delle impostazioni.\",\n  \"components.StatusBadge.managemedia\": \"Gestisci {mediaType}\",\n  \"components.StatusBadge.playonplex\": \"Riproduci su {mediaServerName}\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} aggiornato\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Qualcosa è andato storto durante il recupero dei dati della stagione.\",\n  \"components.TvDetails.reportissue\": \"Segnala un problema\",\n  \"components.TvDetails.seasonnumber\": \"Stagione {seasonNumber}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Richiedi automaticamente i film presenti nella tua <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"i18n.collection\": \"Collezione\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Sincronizza Plex Watchlist\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Qualcosa è andato storto durante la generazione di una nuova chiave API.\",\n  \"components.TvDetails.manageseries\": \"Gestisci Serie\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Mostra Dettagli\",\n  \"components.Selector.searchKeywords\": \"Ricerca parole chiave…\",\n  \"components.Selector.searchGenres\": \"Seleziona generi…\",\n  \"components.Selector.showless\": \"Mostra meno\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL applicazione\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Devi fornire un titolo dell'applicazione\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Devi fornire un URL valido\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr deve essere riavviato per rendere effettive le modifiche\",\n  \"components.TitleCard.tvdbid\": \"ID TheTVDB\",\n  \"components.UserProfile.emptywatchlist\": \"I media aggiunti alla tua <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> appariranno qui.\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"i18n.restartRequired\": \"Riavvio necessario\",\n  \"components.Selector.nooptions\": \"Nessun risultato.\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Clicca il bottone sottostante per ricaricare l'applicazione.\",\n  \"components.StatusChecker.reloadApp\": \"Ricarica {applicationTitle}\",\n  \"components.StatusChecker.restartRequired\": \"Riavvio del server necessario\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} non trovato\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Impostazioni salvate con successo!\",\n  \"components.UserProfile.plexwatchlist\": \"Plex Watchlist\",\n  \"components.TvDetails.seasonstitle\": \"Stagioni\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Richiedi automaticamente le serie presenti nella tua <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"components.Discover.moviegenres\": \"Film per genere\",\n  \"components.RequestModal.requestseries4ktitle\": \"Richiedi serie in 4K\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Richiedi film in 4K\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Voto utenti TMDB\",\n  \"components.StatusBadge.openinarr\": \"Apri su {arr}\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Tipo serie anime\",\n  \"components.Settings.SonarrModal.seriesType\": \"Tipo serie TV\",\n  \"components.RequestModal.requestmovietitle\": \"Richiedi film\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Numero voti utenti TMDB\",\n  \"components.RequestModal.requestseriestitle\": \"Richiedi serie\",\n  \"components.Login.adminerror\": \"Devi utilizzare un account amministratore per accedere.\",\n  \"components.Login.description\": \"Poiché è il tuo primo accesso a {applicationName}, è necessario aggiungere un'email valida.\",\n  \"components.Login.emailtooltip\": \"L'indirizzo non deve essere associato alla tua istanza di {mediaServerName}.\",\n  \"components.Login.enablessl\": \"Usa SSL\",\n  \"components.Login.hostname\": \"URL di {mediaServerName}\",\n  \"components.Login.initialsignin\": \"Connetti\",\n  \"components.Login.invalidurlerror\": \"Impossibile connettersi al server {mediaServerName}.\",\n  \"components.Login.port\": \"Porta\",\n  \"components.Login.save\": \"Aggiungi\",\n  \"components.Login.saving\": \"Aggiungendo…\",\n  \"components.Login.signinwithjellyfin\": \"Usa il tuo account {mediaServerName}\",\n  \"components.Login.title\": \"Aggiungi Email\",\n  \"components.Login.urlBase\": \"Base URL\",\n  \"components.Login.username\": \"Nome utente\",\n  \"components.Login.validationEmailRequired\": \"Devi fornire un'email\",\n  \"components.Login.validationPortRequired\": \"Devi fornire un numero di porta valido\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"L'URL di base non deve terminare con una barra finale\",\n  \"components.Login.validationUrlTrailingSlash\": \"L'URL non deve terminare con una barra finale\",\n  \"components.Login.validationemailformat\": \"È richiesta un'email valida\",\n  \"components.Login.validationhostformat\": \"È richiesta un'URL valida\",\n  \"components.Login.validationhostrequired\": \"È richiesta l'URL di {mediaServerName}\",\n  \"components.ManageSlideOver.removearr\": \"Rimuovi da {arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"Rimuovi da 4K {arr}\",\n  \"components.MovieDetails.addtowatchlist\": \"Aggiungi alla lista di visione\",\n  \"components.MovieDetails.downloadstatus\": \"Stato del download\",\n  \"components.MovieDetails.imdbuserscore\": \"Punteggio utente IMDb: {formattedCount}\",\n  \"components.MovieDetails.openradarr\": \"Apri il film in Radarr\",\n  \"components.MovieDetails.removefromwatchlist\": \"Rimuovi dalla lista di visione\",\n  \"components.MovieDetails.rtaudiencescore\": \"Punteggio del pubblico di Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatometro di Rotten Tomatoes\",\n  \"components.MovieDetails.tmdbuserscore\": \"Punteggio Utente TMDB\",\n  \"components.MovieDetails.watchlistError\": \"Qualcosa è andato storto. Riprova.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> aggiunto alla lista di visione con successo!\",\n  \"components.PermissionEdit.autorequestMovies\": \"Richiesta automatica dei film\",\n  \"components.PermissionEdit.autorequestSeries\": \"Richiesta automatica di serie\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Concedi il permesso per inviare automaticamente richieste per serie non 4K tramite Plex Watchlist.\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Concedi il permesso per visualizzare l'elenco dei media aggiunti di recente.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Visualizza le liste di controllo di {mediaServerName}\",\n  \"components.RequestBlock.approve\": \"Approva la richiesta\",\n  \"components.RequestBlock.decline\": \"Rifiuta la richiesta\",\n  \"components.RequestBlock.delete\": \"Elimina la richiesta\",\n  \"components.RequestBlock.edit\": \"Modifica la richiesta\",\n  \"components.RequestBlock.lastmodifiedby\": \"Ultima modifica da\",\n  \"components.RequestBlock.requestedby\": \"Richiesto da\",\n  \"components.RequestCard.cancelrequest\": \"Annulla richiesta\",\n  \"components.RequestCard.declinerequest\": \"Rifiuta richiesta\",\n  \"components.RequestCard.editrequest\": \"Modifica richiesta\",\n  \"components.RequestCard.tmdbid\": \"ID TMDB\",\n  \"components.RequestCard.tvdbid\": \"ID TheTVDB\",\n  \"components.RequestCard.unknowntitle\": \"Titolo sconosciuto\",\n  \"components.RequestList.RequestItem.profileName\": \"Profilo\",\n  \"components.RequestList.RequestItem.tvdbid\": \"ID TheTVDB\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Titolo sconosciuto\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Richiedi Collezione in 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Richiedi Collezione\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Predefinito del dispositivo\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Sincronizzazione della disponibilità dei media\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Frequenza Attuale\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Ogni {jobScheduleSeconds, plural, one {secondo} other {{jobScheduleSeconds} secondi}}\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Pulizia della cache delle immagini\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Cache delle immagini\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Immagini memorizzate nella cache\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Dimensione totale della cache\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Scansione completa della libreria Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Scansione degli elementi aggiunti di recente di Jellyfin\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Abilita la cache delle immagini\",\n  \"components.Settings.SettingsMain.general\": \"General\",\n  \"components.Login.credentialerror\": \"Il nome utente o la password sono errati.\",\n  \"components.Login.initialsigningin\": \"Connessione in corso…\",\n  \"components.MovieDetails.openradarr4k\": \"Apri il film in 4K Radarr\",\n  \"components.MovieDetails.play\": \"Riproduci su {mediaServerName}\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Richiesta inviata automaticamente\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Richiedi email utente\",\n  \"components.Discover.resetfailed\": \"Si è verificato un errore nel ripristino delle impostazioni di personalizzazione della scoperta.\",\n  \"components.Login.validationEmailFormat\": \"Email non valida\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Questo rimuoverà in modo irreversibile questo {mediaType} da {arr}, inclusi tutti i file.\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> rimosso dalla lista di visione con successo!\",\n  \"components.PermissionEdit.viewrecent\": \"Visualizza Aggiunti Recenti\",\n  \"components.RequestBlock.requestdate\": \"Data della richiesta\",\n  \"components.RequestCard.approverequest\": \"Approva richiesta\",\n  \"components.Selector.searchStudios\": \"Cerca studi…\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Aggiungi automaticamente un'etichetta aggiuntiva con l'ID utente e il nome visualizzato del richiedente\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"L'URL di base deve avere una barra iniziale\",\n  \"components.MovieDetails.play4k\": \"Riproduci in 4K su {mediaServerName}\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Ricevi notifiche quando nuove richieste di media vengono inviate automaticamente per gli elementi nella tua lista di visione.\",\n  \"components.PermissionEdit.autorequestDescription\": \"Concedi il permesso per inviare automaticamente richieste per media non-4K tramite la Plex Watchlist.\",\n  \"components.Discover.updatefailed\": \"Qualcosa è andato storto durante l'aggiornamento delle impostazioni di personalizzazione della scoperta.\",\n  \"components.Login.validationusernamerequired\": \"È richiesto un nome utente\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Concedi il permesso per inviare automaticamente richieste di film non 4K tramite Plex Watchlist.\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Concedi il permesso per visualizzare le liste di controllo di {mediaServerName} di altri utenti.\",\n  \"components.RequestList.RequestItem.tmdbid\": \"ID TMDB\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Suono di notifica\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Cache le immagini provenienti da fonti esterne (richiede una quantità significativa di spazio su disco)\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Configura le impostazioni globali e predefinite per Seerr.\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Non siamo riusciti a trovare una corrispondenza per questa serie.\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Tagga richieste\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Quando abilitato nelle impostazioni, Seerr farà da proxy e memorizzerà nella cache le immagini provenienti da fonti esterne preconfigurate. Le immagini memorizzate nella cache vengono salvate nella tua cartella di configurazione. Puoi trovare i file in `<code>{appDataPath}/cache/images</code>`.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Creato un nuovo cursore e salvato le impostazioni di personalizzazione della scoperta.\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"Serie {keywordTitle}\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Filtro Attivo} other {# Filtri Attivi}}\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.networks\": \"Reti\",\n  \"components.Discover.resetsuccess\": \"Impostazioni di personalizzazione della scoperta ripristinate con successo.\",\n  \"components.Discover.resettodefault\": \"Ripristina predefiniti\",\n  \"components.Discover.resetwarning\": \"Ripristina tutti i cursori ai predefiniti. Questo eliminerà anche eventuali cursori personalizzati!\",\n  \"components.Discover.stopediting\": \"Interrompi modifica\",\n  \"components.Discover.studios\": \"Studi\",\n  \"components.Discover.tmdbnetwork\": \"Rete TMDB\",\n  \"components.Discover.tmdbstudio\": \"Studio TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Servizi di Streaming TV TMDB\",\n  \"components.Discover.updatesuccess\": \"Impostazioni di personalizzazione della scoperta aggiornate.\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"L'indirizzo email non è valido.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"È necessario un indirizzo email.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"È richiesta una password.\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Consenti richieste parziali di serie\",\n  \"components.Login.back\": \"Torna Indietro\",\n  \"components.Settings.Notifications.webhookRoleId\": \"ID ruolo di notifica\",\n  \"components.Settings.Notifications.messageThreadId\": \"Thread/ID Argomento\",\n  \"components.Setup.configplex\": \"Configura Plex\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Questo account è già collegato ad un utente Plex\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Se nella tua chat di gruppo sono abilitati gli argomenti, puoi specificare qui l'ID di un thread/argomento\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Richiedi automaticamente i film\",\n  \"components.Selector.canceled\": \"Cancellato\",\n  \"components.Selector.inProduction\": \"In Produzione\",\n  \"components.Discover.FilterSlideover.status\": \"Stato\",\n  \"components.RequestList.RequestItem.removearr\": \"Rimuovi da {arr}\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Impossible connettersi a Plex usando le tue credenziali\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Serie in arrivo\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"L'ID del ruolo da menzionare nel messaggio webhook. Lasciare vuoto per disabilitare le menzioni\",\n  \"components.Login.validationservertyperequired\": \"Seleziona un tipo di server\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"L'ID del thread/argomento deve essere un numero intero positivo\",\n  \"components.RequestList.sortDirection\": \"Cambia direzione di ordinamento\",\n  \"components.Login.loginwithapp\": \"Login con {appName}\",\n  \"components.Login.noadminerror\": \"Non è stato trovato nessun amministratore nel server.\",\n  \"components.Login.orsigninwith\": \"O fai l'accesso con\",\n  \"components.Login.servertype\": \"Tipo Server\",\n  \"components.Selector.ended\": \"Terminato\",\n  \"components.Selector.pilot\": \"Pilota\",\n  \"components.Selector.planned\": \"Pianificato\",\n  \"components.Selector.returningSeries\": \"Serie Ricorrente\",\n  \"components.Selector.searchStatus\": \"Seleziona stato...\",\n  \"components.Selector.searchUsers\": \"Seleziona utenti…\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"È necessario fornire un ID ruolo Discord valido\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Condizioni\",\n  \"components.Setup.signinWithPlex\": \"Inserisci le tue credenziali di Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Richiedi automaticamente le serie\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Seleziona cartella principale\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Specifica le condizioni prima di applicare le modifiche ai parametri. Ogni campo deve essere convalidato affinché le regole possano essere applicate (operazione AND). Un campo è considerato verificato se una qualsiasi delle sue proprietà corrisponde (operazione OR).\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Seleziona profilo di qualità\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Regola di sostituzione aggiornata con successo!\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Specifica quali impostazioni verranno modificate quando saranno soddisfatte le condizioni sopra indicate.\",\n  \"components.Settings.OverrideRuleModal.create\": \"Crea regola\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Nuova regola di sostituzione\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Modifica regola di sostituzione\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Generi\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Parole Chiave\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Lingue\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Nessun tag.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Profilo di qualità\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Cartella Principale\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Regola di sostituzione creata con successo!\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Seleziona servizio\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Seleziona i tag\",\n  \"components.Settings.OverrideRuleModal.service\": \"Servizio\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Applica questa regola al servizio selezionato.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Impostazioni\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleModal.users\": \"Utenti\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Condizioni\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Genere\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Parole chiave\",\n  \"components.Settings.OverrideRuleTile.language\": \"Lingua\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Profilo di qualità\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Cartella Principale\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Impostazioni\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleTile.users\": \"Utenti\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Token di aggiornamento Plex\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filtra i contenuti in base alla disponibilità della regione\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Ricerca per Regione\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Mostra i siti di streaming in base alla disponibilità della regione\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Consenti richieste di episodi speciali\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Avatar degli utenti\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Regione di streaming\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Si è verificato un errore durante il salvataggio delle impostazioni.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Ricerca per Regione\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"Non abilitare questa impostazione se non sei sicuro di ciò che stai facendo!\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> aggiunto alla lista con successo!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Suono di notifica\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Se vuoi, puoi configurare gli endpoint interni ed esterni per il tuo server {mediaServerName}. Di solito, l'URL esterno è diverso da quello interno. Puoi anche impostare un URL personalizzato per reimpostare la password di accesso a {mediaServerName}, se vuoi reindirizzare a una pagina diversa per reimpostare la password. Puoi anche cambiare la chiave API Jellyfin, che è stata generata automaticamente in precedenza.\",\n  \"components.Settings.jellyfinsettings\": \"Impostazioni {mediaServerName}\",\n  \"components.Settings.scanbackground\": \"La scansione verrà eseguita in background. Nel frattempo è possibile continuare con la procedura di configurazione.\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Account Collegati\",\n  \"components.Settings.syncing\": \"Sincronizzando\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Riavvia il server per applicare le impostazioni aggiornate.\",\n  \"components.TvDetails.rtaudiencescore\": \"Punteggio del pubblico su Rotten Tomatoes\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> rimosso dalla lista con successo!\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"È necessario utilizzare i parametri di rete del proprio container/sistema anziché queste impostazioni. Per ulteriori informazioni, consultare i {docs}.\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {utente} other {utenti}} importati con successo!\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Aggiungi automaticamente un tag aggiuntivo con l'ID utente e il nome visualizzato del richiedente\",\n  \"components.Settings.deleteServer\": \"Elimina Server {serverType}\",\n  \"components.Settings.overrideRulesDescription\": \"Le regole di sostituzione consentono di specificare le proprietà che verranno sostituite se una richiesta corrisponde alla regola.\",\n  \"components.UserList.newJellyfinsigninenabled\": \"L'impostazione <strong>Abilita nuovo accesso {mediaServerName}</strong> è attualmente abilitata. Gli utenti {mediaServerName} con accesso alla libreria non devono essere importati per poter effettuare l'accesso.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Thread/ID Argomento\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"È necessario selezionare almeno un metodo di autenticazione.\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Aggiungi tag alle richieste\",\n  \"components.Settings.invalidurlerror\": \"Impossibile connettersi al server {mediaServerName}.\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Configura le impostazioni per il tuo server {mediaServerName}. {mediaServerName} esegue la scansione delle tue librerie {mediaServerName} per vedere quali contenuti sono disponibili.\",\n  \"components.Setup.librarieserror\": \"Convalida non riuscita. Attivare nuovamente le librerie per continuare.\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Episodio} other {# Episodi}}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Impossibile connettersi a {mediaServerName} utilizzando le credenziali fornite\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Impossibile eliminare l'account collegato.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Non hai il permesso di modificare gli account collegati a questo utente.\",\n  \"components.Settings.overrideRules\": \"Regole di sostituzione\",\n  \"components.Settings.save\": \"Salva Modifiche\",\n  \"components.Settings.saving\": \"Salvando…\",\n  \"components.Setup.signinWithEmby\": \"Inserisci le tue credenziali Emby\",\n  \"components.TitleCard.addToWatchList\": \"Aggiungi alla lista\",\n  \"components.TvDetails.removefromwatchlist\": \"Rimuovi dalla Lista\",\n  \"components.Setup.signin\": \"Accedi\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Nessuna libreria trovata\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Abilita Protezione CSRF\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Imposta l'accesso API esterno in sola lettura (richiede HTTPS)\",\n  \"components.Settings.SettingsNetwork.docs\": \"documentazione\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Forza prima la risoluzione IPv4\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Forza Seerr a risolvere prima gli indirizzi IPv4 invece di quelli IPv6\",\n  \"components.Settings.SettingsNetwork.network\": \"Rete\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Impostazioni di Rete\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Configura le impostazioni di rete per la tua istanza Seerr.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Indirizzi Proxy Ignorati\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Utilizza “,” come separatore e “*.” come carattere jolly per i sottodomini\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Bypassare il Proxy per gli Indirizzi Locali\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"Proxy HTTP(S)\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Nome Host Proxy\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Password del Proxy\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Porta del Proxy\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Usa SSL per il Proxy\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Username del Proxy\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Impostazioni salvate con successo!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Abilita Supporto Proxy\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Consenti a Seerr di registrare correttamente gli indirizzi IP dei client dietro un proxy\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"È necessario fornire una porta valida\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Metodi di Login\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Configura i metodi di accesso per gli utenti.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Abilita accesso tramite {mediaServerName}\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Consenti agli utenti di accedere utilizzando il proprio account {mediaServerName}\",\n  \"components.Settings.addrule\": \"Nuova regola di sostituzione\",\n  \"components.Settings.advancedTooltip\": \"Una configurazione errata di questa impostazione può causare dei malfunzionamenti\",\n  \"components.Settings.apiKey\": \"Chiave API\",\n  \"components.Settings.experimentalTooltip\": \"L'attivazione di questa impostazione può causare un comportamento imprevisto dell'applicazione\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"URL Password dimenticata\",\n  \"components.Settings.jellyfinSettings\": \"Impostazioni {mediaServerName}\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Si è verificato un errore durante il salvataggio delle impostazioni di {mediaServerName}.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"Impostazioni {mediaServerName} salvate con successo!\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Autenticazione personalizzata con raggruppamento automatico delle librerie non supportata\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Si è verificato un errore durante la sincronizzazione delle librerie\",\n  \"components.Settings.jellyfinlibraries\": \"Librerie di {mediaServerName}\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"Le librerie {mediaServerName} cercano i titoli. Se non sono elencate librerie, fare clic sul pulsante sottostante.\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalmente, questa operazione viene eseguita una volta ogni 24 ore. Seerr controllerà in modo più aggressivo gli elementi aggiunti di recente al tuo server {mediaServerName}. Se è la prima volta che configuri Seerr, ti consigliamo di eseguire una scansione manuale completa della libreria!\",\n  \"components.Settings.manualscanJellyfin\": \"Scansione Libreria Manuale\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.menuNetwork\": \"Rete\",\n  \"components.Settings.syncJellyfin\": \"Sincronizza Librerie\",\n  \"components.Settings.timeout\": \"Tempo scaduto\",\n  \"components.Settings.tip\": \"Suggerimento\",\n  \"components.Setup.back\": \"Torna indietro\",\n  \"components.Setup.configemby\": \"Configura Emby\",\n  \"components.Setup.configjellyfin\": \"Configura Jellyfin\",\n  \"components.Setup.configuremediaserver\": \"Configura Media Server\",\n  \"components.Setup.servertype\": \"Scegli il tipo di server\",\n  \"components.Setup.signinWithJellyfin\": \"Inserisci le tue credenziali Jellyfin\",\n  \"components.Setup.subtitle\": \"Inizia scegliendo il tuo media server\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.TitleCard.cleardata\": \"Cancella dati\",\n  \"components.TitleCard.watchlistCancel\": \"Lista per <strong>{title}</strong> eliminata.\",\n  \"components.TitleCard.watchlistError\": \"Qualcosa è andato storto. Riprova.\",\n  \"components.TvDetails.Season.noepisodes\": \"Elenco episodi non disponibile.\",\n  \"components.TvDetails.addtowatchlist\": \"Aggiungi alla Lista\",\n  \"components.TvDetails.play\": \"Riproduci su {mediaServerName}\",\n  \"components.TvDetails.play4k\": \"Riproduci in 4K su {mediaServerName}\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> rimosso dalla lista  con successo!\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomatometer di Rotten Tomatoes\",\n  \"components.TvDetails.tmdbuserscore\": \"Punteggio utente TMDB\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> aggiunto alla lista con successo!\",\n  \"components.UserList.importfromJellyfin\": \"Importa utenti da {mediaServerName}\",\n  \"components.UserList.importfromJellyfinerror\": \"Si è verificato un errore durante l'importazione degli utenti da {mediaServerName}.\",\n  \"components.UserList.mediaServerUser\": \"Utente {mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Password\",\n  \"components.TvDetails.watchlistError\": \"Qualcosa è andato storto. Riprova.\",\n  \"components.UserList.importfrommediaserver\": \"Importa utenti da {mediaServerName}\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Non ci sono utenti {mediaServerName} da importare.\",\n  \"components.UserList.username\": \"Nome Utente\",\n  \"components.UserList.validationUsername\": \"È necessario fornire un nome utente\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Inserisci le credenziali {mediaServerName} per collegare il tuo account a {applicationName}.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Questo account è già collegato a un utente {applicationName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Si è verificato un errore sconosciuto\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"È necessario fornire una password\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Collega\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Aggiungendo…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Collega Account {mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Nome Utente\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"È necessario fornire un nome utente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Filtra i contenuti in base alla disponibilità della regione\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Utente {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Salva Modifiche\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Salvando…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Regione di streaming\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Mostra i siti di streaming in base alla disponibilità della regione\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Questo indirizzo e-mail è già stato utilizzato!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Un altro utente ha già questo nome utente. Devi impostare un indirizzo e-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"È richiesta un'email valida\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Email richiesta\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Si è verificato un errore sconosciuto\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Account Collegati\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Questi account esterni sono collegati al tuo account {applicationName}.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Non hai alcun account esterno collegato al tuo account.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Predefinito del dispositivo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Se nella tua chat di gruppo sono abilitati gli argomenti, puoi specificare qui l'ID di un thread/argomento\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"L'ID del thread/argomento deve essere un numero intero positivo\",\n  \"components.UserProfile.localWatchlist\": \"Lista di {username}\",\n  \"i18n.specials\": \"Speciali\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"L'URL non deve terminare con una barra \\\"/\\\" finale\",\n  \"components.Discover.FilterSlideover.certification\": \"Classificazione contenuti\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Parole chiavi escluse\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Descrizione del problema\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Seleziona un provider di metadati\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Impossibile caricare le certificazioni\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Voto massimo\",\n  \"components.Selector.CertificationSelector.minRating\": \"Voto minimo\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Nessuna opzione disponibile\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Scegli un ente certificatore\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Seleziona un paese\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Inizia a digitare per cercare.\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Priorità\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"È necessario impostare un numero di priorità\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Abilita Agente\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Poster incluso\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Salvataggio impostazioni notifiche Ntfy fallito.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Salvataggio impostazioni notifiche Ntfy effettuato con successo!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Password\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Test invio notifica Ntfy fallito.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Invio test notifica Ntfy…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Notifica di test Ntfy inviata!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Autenticazione tramite token\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Argomento\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"URL di root del server\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Nome utente\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Autenticazione tramite Nome utente + Password\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Devi fornire un argomento\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Devi fornire un URL valido\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Devi selezionare almeno una tipologia di notifica\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Includi Poster\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Includi Poster\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Supporta le variabili URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Le variabili disponibili sono documentate nella sezione delle variabili del template del webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"La URL del test di notifica è impostata a {testURL} invece che sull'effettivo URL del webhook.\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Includi Poster\",\n  \"components.Settings.Notifications.embedPoster\": \"Includi Poster\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"Cache DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr memorizza le richieste DNS per ottimizzare le performance ed evitare chiamate API non necessarie.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Statistiche cache DNS globale\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Queste statistiche sono aggregate tra tutte le voci presenti nella cache DNS.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Indirizzo attivo\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Età\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"La memoria dei dns per {hostname} è stata svuotata.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Richieste dalla memoria\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Richieste non in memoria\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Nome host\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Ogni {jobScheduleDays, plural, one {giorno} other {{jobScheduleDays} giorni}}\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Fallimenti\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Svuota memoria DNS\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Tasso di successo\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Successi\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"Ripiega su IPv4\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Mancati\",\n  \"components.Settings.SettingsJobsCache.size\": \"Dimensione\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"Chiave API copiata negli appunti.\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Nascondi i media disponibili dalla pagine di esplorazione, ma non dai risultati di ricerca\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Devi fornire un URL valido\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"La URL non può terminare con \\\"/\\\"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"ULR Youtube\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"URL base per i video di YouTube se stai usando un'istanza self-hosted di YouTube.\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"Memoria DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"TTL massimo della memoria DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"TTL minimo della memoria DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"NON abilitare questo se stai avendo problemi con le richieste DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Abilita la memorizzazione delle richieste DNS per ottimizzare le performance ed evitare richieste API non necessarie\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Tutti i fornitori di metadata selezionati sono operativi\",\n  \"components.Settings.animeMetadataProvider\": \"Fornitore metadata per Anime\",\n  \"components.Settings.chooseProvider\": \"Scegli i fornitori di metadata per le differenti tipologie di contenuti\",\n  \"components.Settings.clickTest\": \"Clicca il bottone \\\"Test\\\" per controllare la connessione ai fornitori di metadata\",\n  \"components.Settings.connectionTestFailed\": \"Connessione di prova fallita\",\n  \"components.Settings.failed\": \"Non funziona\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Salvataggio impostazione dei fornitori di metadata fallito\",\n  \"components.Settings.general\": \"Generale\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} non è una parola chiava TMDB.\",\n  \"components.Settings.menuMetadataProviders\": \"Fornitori Metadata\",\n  \"components.Settings.metadataProviderSelection\": \"Selezione fornitori metadata\",\n  \"components.Settings.metadataProviderSettings\": \"Fornitori Metadata\",\n  \"components.Settings.metadataSettings\": \"Impostazioni per i fornitori di metadata\",\n  \"components.Settings.metadataSettingsSaved\": \"Impostazioni del fornitore di metadata salvati\",\n  \"components.Settings.no\": \"No\",\n  \"components.Settings.noSpecialCharacters\": \"La configurazione dev'essere una lista separata da virgole di id di parole chiave di TMDB, e non deve né iniziare né terminare con una virgola.\",\n  \"components.Settings.nooptions\": \"Nessun risultato.\",\n  \"components.Settings.notTested\": \"Non testato\",\n  \"components.Settings.operational\": \"Operativo\",\n  \"components.Settings.providerStatus\": \"Status del fornitore di metadata\",\n  \"components.Settings.searchKeywords\": \"Cerca parole chiave…\",\n  \"components.Settings.seriesMetadataProvider\": \"Fornitore metadata per Serie TV\",\n  \"components.Settings.settings\": \"Impostazioni\",\n  \"components.Settings.starttyping\": \"Inizia a scrivere per cercare.\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"Il fornitore TMDB non funziona, scegli un altro fornitore dei metadata\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"il fornitore TVDB non funziona, scegli un altro fornitore dei metadata\",\n  \"components.Settings.valueRequired\": \"Devi fornire un valore.\",\n  \"components.Settings.yes\": \"Sì\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Browser\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Creata\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Cancella sottoscrizione\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Dispositivo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Disabilita web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Qualcosa si è rotto cercando di disabilitare il web push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Abilita il web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Qualcosa si è rotto cercando di abilitare il web push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Motore\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Gestisci dispositivi\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Non hai alcuna sottoscrizione web push da mostrare.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Sistema Operativo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Sottoscrizione cancellata.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Qualcosa si è rotto durante la cancellazione delle sottoscrizioni dell'utente.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"tipo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Sconosciuto\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Web push è stato disabilitato.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Web push è stato abilitato.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Qualcosa si è rotto durante il salvataggio delle impostazioni delle notifiche web push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Impostazioni notifiche web push salvate con successo!\",\n  \"i18n.completed\": \"Completato\",\n  \"i18n.deleted\": \"Eliminato\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Informazioni su Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Contribuisci\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Supporta Seerr\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Devi fornire un TTL massimo valido\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Devi fornire un valore TTL minimo valido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Sottoscrizione attiva\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Gestisci i media bloccati.\",\n  \"components.Blocklist.blocklistdate\": \"data\",\n  \"components.Blocklist.blocklistsettings\": \"Impostazioni Blocklist\",\n  \"components.Blocklist.filterManual\": \"Manuale\",\n  \"components.Blocklist.mediaName\": \"Nome\",\n  \"components.Blocklist.mediaType\": \"Tipo\",\n  \"components.Blocklist.showAllBlocklisted\": \"Mostra tutti i media bloccati\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Impossibile connettersi a {services}. Alcune informazioni potrebbero non essere disponibili.\",\n  \"components.PermissionEdit.blocklistedItems\": \"Media bloccati.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Concedi l'autorizzazione a bloccare i contenuti multimediali.\",\n  \"components.PermissionEdit.manageblocklist\": \"Gestisci blocklist\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Concedi l'autorizzazione per gestire i contenuti multimediali bloccati.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Visualizza i contenuti multimediali bloccati.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Concedi l'autorizzazione per visualizzare i contenuti multimediali bloccati.\",\n  \"components.RequestList.unableToConnect\": \"Impossibile connettersi a {services}. Alcune informazioni potrebbero non essere disponibili.\",\n  \"component.BlocklistBlock.blocklistdate\": \"Data blocco\",\n  \"component.BlocklistBlock.blocklistedby\": \"Bloccato da\",\n  \"component.BlocklistModal.blocklisting\": \"Bloccaggio\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> non è bloccato.\",\n  \"components.Blocklist.blocklistedby\": \"{date} da {user}\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Tag bloccati\",\n  \"components.Blocklist.mediaTmdbId\": \"Id tmdb\",\n  \"components.Discover.timeWindowDay\": \"Quotidiano\",\n  \"components.Discover.timeWindowWeek\": \"Settimanale\",\n  \"components.Layout.Sidebar.blocklist\": \"Lista blocchi\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Priorità\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"Devi fornire una priorità da 1 a 5\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Headers personalizzati\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Aggiungi Header\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Non è possibile usare contemporaneamente l'Header di Autorizzazione e l'Header di Autorizzazione personalizzato. Rimuovi uno dei due.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Tutti gli header devono avere nome e valore\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Nome Header\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Rimuovi\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Aggiungi un HTTP Header personalizzato da aggiungere alle richieste webhooks\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Valore Header\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Nessuna richiesta DNS è stata ancora memorizzata.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Processa i Tag bloccati\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Contenuto bloccato tramite Tag\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Limita il contenuto bloccato per Tag\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"Il lavoro \\\"Processa i Tag Bloccati\\\" bloccherà questo numero di pagine in ogni ordinamento. Numeri più elevati creeranno una lista di blocco più accurata, ma aumentano lo spazio richiesto.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Aggiungi automaticamente contenuti con tag alla lista blocchi tramite il processo \\\"Processa i Tag Bloccati\\\"\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Nascondi i bloccati\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Aggiungi i bloccati dalla pagina di esplorazione per tutti gli utenti col permesso \\\"Gestisci lista blocchi\\\"\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"Richiesta API scaduta\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Tempo massimo (in secondi) di attesa per la risposta dai servizi esterni come Radarr e Sonarr. Impostato a 0 significa che la richiesta non scade mai.\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Manda TUTTE le richieste HTTP/HTTPS attraverso un server proxy (host/porta). Questo NON abilita HTTPS, SSL o la configurazione dei certificati.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Devi fornire un valore di attesa massima valido\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Tieni d'occhio le nuove stagioni\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Incolla la configurazione per la lista di blocco tag qua sotto.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Importa la configurazione della lista di blocco Tag\",\n  \"components.Settings.blocklistedTagsText\": \"Tag bloccati\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Sei certo di voler ripulire la lista di tag bloccati?\",\n  \"components.Settings.copyBlocklistedTags\": \"Lista di tag bloccati copiata negli appunti.\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Nulla da copiare\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Copia la configurazione della lista di tag bloccati\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Importa la configurazione della lista dei tag bloccati\",\n  \"i18n.addToBlocklist\": \"Aggiungi alla lista blocchi\",\n  \"i18n.blocklist\": \"Lista blocchi\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> è già stato bloccato.\",\n  \"i18n.blocklistError\": \"Qualcosa non è andato a buon fine. Prova di nuovo.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> è stato bloccato con successo.\",\n  \"i18n.blocklisted\": \"Bloccato\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> è stato rimosso con successo dalla lista dei blocchi.\",\n  \"i18n.removefromBlocklist\": \"Rimuovi dalla lista dei blocchi\"\n}\n"
  },
  {
    "path": "src/i18n/locale/ja.json",
    "content": "{\n  \"components.Discover.popularmovies\": \"人気の映画\",\n  \"components.Discover.populartv\": \"人気のテレビ番組\",\n  \"components.Discover.recentlyAdded\": \"最近追加された動画\",\n  \"components.Discover.recentrequests\": \"最近のリクエスト\",\n  \"components.Discover.trending\": \"トレンド\",\n  \"components.Discover.upcoming\": \"今後リリースされる映画\",\n  \"components.Discover.upcomingmovies\": \"今後リリースされる映画\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"作品名で検索\",\n  \"components.Layout.Sidebar.dashboard\": \"ホーム\",\n  \"components.Layout.Sidebar.requests\": \"リクエスト\",\n  \"components.Layout.Sidebar.settings\": \"設定\",\n  \"components.Layout.Sidebar.users\": \"ユーザー\",\n  \"components.Layout.UserDropdown.signout\": \"ログアウト\",\n  \"components.MovieDetails.budget\": \"予算\",\n  \"components.MovieDetails.cast\": \"出演者\",\n  \"components.MovieDetails.originallanguage\": \"オリジナルの言語\",\n  \"components.MovieDetails.overview\": \"ストーリー\",\n  \"components.MovieDetails.overviewunavailable\": \"ストーリー情報がありません。\",\n  \"components.MovieDetails.recommendations\": \"オススメの作品\",\n  \"components.MovieDetails.releasedate\": \"公開日\",\n  \"components.MovieDetails.revenue\": \"収益\",\n  \"components.MovieDetails.runtime\": \"{minutes} 分\",\n  \"components.MovieDetails.similar\": \"関連作品\",\n  \"components.PersonDetails.appearsin\": \"出演作品\",\n  \"components.PersonDetails.ascharacter\": \"{character} 役\",\n  \"components.RequestBlock.seasons\": \"シーズン\",\n  \"components.RequestCard.seasons\": \"シーズン\",\n  \"components.RequestList.RequestItem.seasons\": \"シーズン\",\n  \"components.RequestList.requests\": \"リクエスト\",\n  \"components.RequestModal.cancel\": \"キャンセルリクエスト\",\n  \"components.RequestModal.numberofepisodes\": \"エピソード数\",\n  \"components.RequestModal.pendingrequest\": \"保留中のリクエスト\",\n  \"components.RequestModal.requestCancel\": \"<strong>{title}</strong> のリクエストは取り消されました。\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> のリクエストが完了しました！\",\n  \"components.RequestModal.requestadmin\": \"このリクエストは今すぐ承認されます。\",\n  \"components.RequestModal.requestfrom\": \"{username} はすでにリクエストを上げています。\",\n  \"components.RequestModal.requestseasons\": \"{seasonCount} シーズンをリクエスト\",\n  \"components.RequestModal.season\": \"シーズン\",\n  \"components.RequestModal.seasonnumber\": \"シーズン {number}\",\n  \"components.RequestModal.selectseason\": \"シーズンを選ぶ\",\n  \"components.Search.searchresults\": \"検索結果\",\n  \"components.Settings.Notifications.agentenabled\": \"エージェントを有効にする\",\n  \"components.Settings.Notifications.authPass\": \"SMTP 認証パスワード\",\n  \"components.Settings.Notifications.authUser\": \"SMTP 認証ユーザー\",\n  \"components.Settings.Notifications.emailsender\": \"配信元メールアドレス\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP ホスト\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP ポート\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"有効なホスト名・IP アドレスを入力してください\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"有効なポートを入力してください\",\n  \"components.Settings.Notifications.webhookUrl\": \"ウェブフック URL\",\n  \"components.Settings.RadarrModal.add\": \"サーバーを追加\",\n  \"components.Settings.RadarrModal.apiKey\": \"API キー\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL のベース\",\n  \"components.Settings.RadarrModal.createradarr\": \"Radarr サーバーを追加\",\n  \"components.Settings.RadarrModal.defaultserver\": \"デフォルトサーバー\",\n  \"components.Settings.RadarrModal.editradarr\": \"Radarr サーバーを編集\",\n  \"components.Settings.RadarrModal.hostname\": \"ホスト名・IP アドレス\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"最低リリース状況\",\n  \"components.Settings.RadarrModal.port\": \"ポート\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"画質プロファイル\",\n  \"components.Settings.RadarrModal.rootfolder\": \"ルートフォルダー\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"最低リリース状況を選ぶ\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"画質プロファイルを選ぶ\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"ルートフォルダーを選ぶ\",\n  \"components.Settings.RadarrModal.server4k\": \"4K サーバー\",\n  \"components.Settings.RadarrModal.servername\": \"サーバー名\",\n  \"components.Settings.RadarrModal.ssl\": \"SSL を有効にする\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Radarr サーバーの接続は失敗しました。\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr サーバーの接続は成功しました!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"API キーを入力してください\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"有効なホスト名・IP アドレスを入力してください\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"有効なポートを入力してください\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"プロファイルを選択してください\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"ルートフォルダーを選択してください\",\n  \"components.Settings.SonarrModal.add\": \"サーバーを追加\",\n  \"components.Settings.SonarrModal.apiKey\": \"API キー\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL のベース\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Sonarr サーバーを追加\",\n  \"components.Settings.SonarrModal.defaultserver\": \"デフォルトサーバー\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Sonarr サーバーを編集\",\n  \"components.Settings.SonarrModal.hostname\": \"ホスト名・IP アドレス\",\n  \"components.Settings.SonarrModal.port\": \"ポート\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"画質プロファイル\",\n  \"components.Settings.SonarrModal.rootfolder\": \"ルートフォルダー\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"シーズンフォルダー\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"画質プロファイルを選ぶ\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"ルートフォルダーを選ぶ\",\n  \"components.Settings.SonarrModal.server4k\": \"4K サーバー\",\n  \"components.Settings.SonarrModal.servername\": \"サーバー名\",\n  \"components.Settings.SonarrModal.ssl\": \"SSL を有効にする\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"API キーの入力が必要です\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"有効なホスト名・IP アドレスを入力してください\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"有効なポートを入力してください\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"プロファイルを選択してください\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"ルートフォルダーを選択してください\",\n  \"components.Settings.activeProfile\": \"アクティブプロファイル\",\n  \"components.Settings.addradarr\": \"Radarr サーバーを追加\",\n  \"components.Settings.address\": \"アドレス\",\n  \"components.Settings.addsonarr\": \"Sonarr サーバーを追加\",\n  \"components.Settings.cancelscan\": \"スキャンをキャンセル\",\n  \"components.Settings.currentlibrary\": \"現在のライブラリー：{name}\",\n  \"components.Settings.default\": \"デフォルト\",\n  \"components.Settings.default4k\": \"デフォルト 4K\",\n  \"components.Settings.deleteserverconfirm\": \"このサーバーを削除しますか?\",\n  \"components.Settings.hostname\": \"ホスト名・IP アドレス\",\n  \"components.Settings.librariesRemaining\": \"残りのライブラリー：{count}\",\n  \"components.Settings.manualscan\": \"手動ライブラリースキャン\",\n  \"components.Settings.manualscanDescription\": \"通常は 24 時間に一度しか実行されません。Seerr は、Plex サーバーの最近追加されたフォルダをより頻繁にチェックします。初めて Plex を設定する場合は、一度手動でライブラリーをスキャンすることをお勧めします！\",\n  \"components.Settings.menuAbout\": \"アプリ情報\",\n  \"components.Settings.menuGeneralSettings\": \"一般\",\n  \"components.Settings.menuJobs\": \"ジョブ\",\n  \"components.Settings.menuLogs\": \"ログ\",\n  \"components.Settings.menuNotifications\": \"通知\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"連携サービス\",\n  \"components.Settings.notificationsettings\": \"通知設定\",\n  \"components.Settings.notrunning\": \"実行されていない\",\n  \"components.Settings.plexlibraries\": \"Plex ライブラリー\",\n  \"components.Settings.plexlibrariesDescription\": \"Seerrがタイトルをスキャンするライブラリ。リストにない場合Plex の接続設定を保存し、下のボタンをクリックしてください。\",\n  \"components.Settings.plexsettings\": \"Plex の設定\",\n  \"components.Settings.plexsettingsDescription\": \"Plex サーバーの設定。SeerrはPlexサーバーを使用して間隔をおいてライブラリをスキャンし、利用可能なコンテンツを確認します。\",\n  \"components.Settings.port\": \"ポート\",\n  \"components.Settings.radarrsettings\": \"Radarr 設定\",\n  \"components.Settings.sonarrsettings\": \"Sonarr 設定\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"スキャンを開始\",\n  \"components.Setup.configureservices\": \"連携サービスの設定\",\n  \"components.Setup.continue\": \"続行\",\n  \"components.Setup.finish\": \"セットアップを完了\",\n  \"components.Setup.finishing\": \"保存中…\",\n  \"components.Setup.signinMessage\": \"Plex アカウントでログインして始める\",\n  \"components.Setup.welcome\": \"Seerrへようこそ\",\n  \"components.TvDetails.cast\": \"出演者\",\n  \"components.TvDetails.originallanguage\": \"オリジナルの言語\",\n  \"components.TvDetails.overview\": \"ストーリー\",\n  \"components.TvDetails.overviewunavailable\": \"ストーリー情報がありません。\",\n  \"components.TvDetails.recommendations\": \"オススメの作品\",\n  \"components.TvDetails.similar\": \"類似シリーズ\",\n  \"components.UserList.admin\": \"管理者\",\n  \"components.UserList.created\": \"作成日\",\n  \"components.UserList.plexuser\": \"Plexユーザー\",\n  \"components.UserList.role\": \"役割\",\n  \"components.UserList.totalrequests\": \"リクエスト数\",\n  \"components.UserList.user\": \"ユーザー\",\n  \"components.UserList.userlist\": \"ユーザーリスト\",\n  \"i18n.approve\": \"承認\",\n  \"i18n.approved\": \"承認済み\",\n  \"i18n.available\": \"視聴可能\",\n  \"i18n.cancel\": \"キャンセル\",\n  \"i18n.decline\": \"拒否する\",\n  \"i18n.declined\": \"拒否済み\",\n  \"i18n.delete\": \"削除\",\n  \"i18n.movies\": \"映画\",\n  \"i18n.partiallyavailable\": \"一部視聴可能\",\n  \"i18n.pending\": \"リクエスト中\",\n  \"i18n.processing\": \"処理中\",\n  \"i18n.tvshows\": \"シリーズ\",\n  \"i18n.unavailable\": \"視聴不可\",\n  \"pages.oops\": \"ああ\",\n  \"pages.returnHome\": \"ホームへ戻る\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"すべての出演者\",\n  \"components.Settings.validationPortRequired\": \"有効なポートを入力してください\",\n  \"components.Settings.validationHostnameRequired\": \"有効なホスト名・IP アドレスを入力してください\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"サーバー名を入力してください\",\n  \"components.Settings.SettingsAbout.version\": \"バージョン\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"総リクエスト数\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"総メディア数\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub ディスカッション\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"サポート\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"サーバー名を入力してください\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"メール通知設定が保存されました！\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"メール通知設定の保存に失敗しました。\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discord の通知設定の保存に失敗しました。\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord の通知設定が保存されました！\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"すべての出演者\",\n  \"i18n.deleting\": \"削除中…\",\n  \"components.UserList.userdeleteerror\": \"ユーザーの削除する時に問題が発生しました。\",\n  \"components.UserList.userdeleted\": \"ユーザーが削除されました！\",\n  \"components.UserList.deleteuser\": \"ユーザーの削除\",\n  \"components.UserList.deleteconfirm\": \"このユーザーを削除しますか？このユーザーの既存のリクエストデータはすべて削除されます。\",\n  \"components.TvDetails.showtype\": \"番組タイプ\",\n  \"components.TvDetails.network\": \"テレビ局\",\n  \"components.TvDetails.anime\": \"アニメ\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"ルートフォルダーをロードするには先に接続をテストしてください\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"画質プロファイルをロードするには先に接続をテストしてください\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"ルートフォルダー読込中…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"画質プロファイル読込中…\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"アニメルートフォルダー\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"アニメ画質プロファイル\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"最低リリース状況を選択してください\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"ルートフォルダーをロードするには先に接続をテストしてください\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"画質プロファイルをロードするには先に接続をテストしてください\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"画質プロファイル読込中…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"ルートフォルダー読込中…\",\n  \"components.MovieDetails.studio\": \"制作会社\",\n  \"i18n.close\": \"閉じる\",\n  \"components.Settings.SettingsAbout.timezone\": \"タイムゾーン\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"GitHub で見る\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"変更履歴参照\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} の変更履歴\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"リリース\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"リリースデータがありません。\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"最新のバージョン\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"現在のバージョン\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"フルクルー\",\n  \"components.MovieDetails.viewfullcrew\": \"フルクルーを表示\",\n  \"components.CollectionDetails.requestcollection\": \"リクエストコレクション\",\n  \"components.CollectionDetails.overview\": \"ストーリー\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} 本の映画\",\n  \"i18n.requested\": \"リクエスト済み\",\n  \"components.TvDetails.watchtrailer\": \"予告編を見る\",\n  \"components.MovieDetails.watchtrailer\": \"予告編を見る\",\n  \"components.UserList.importfromplexerror\": \"Plex からユーザーをインポート中に問題が発生しました。\",\n  \"components.UserList.importfromplex\": \"Plex からユーザーをインポート\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {ユーザー} other {ユーザー}}のインポートが完了しました！\",\n  \"components.TvDetails.viewfullcrew\": \"フルクルーを表示\",\n  \"components.TvDetails.firstAirDate\": \"初放送日\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"フルシリーズクルー\",\n  \"components.Settings.Notifications.allowselfsigned\": \"自己署名証明書を許可する\",\n  \"components.PersonDetails.crewmember\": \"クルー\",\n  \"i18n.retry\": \"リトライ\",\n  \"i18n.failed\": \"失敗\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"ウェブフック URL\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack の通知設定が保存されました！\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Slack の通知設定の保存に失敗しました。\",\n  \"components.Login.signin\": \"ログイン\",\n  \"components.Login.password\": \"パスワード\",\n  \"components.Login.loginerror\": \"ログイン中に問題が発生しました。\",\n  \"components.Login.forgotpassword\": \"パスワードを忘れた場合\",\n  \"components.Login.email\": \"メールアドレス\",\n  \"components.Layout.UserDropdown.settings\": \"設定\",\n  \"components.Layout.UserDropdown.myprofile\": \"プロフィール\",\n  \"components.Discover.discover\": \"ホーム\",\n  \"components.CollectionDetails.requestcollection4k\": \"4K のコレクションをリクエスト\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code> ボリュームマウントが正しく構成されていませんでした。コンテナーが停止または再起動されると、すべてのデータが消去されます。\",\n  \"components.Login.signingin\": \"ログイン中…\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"設定保存中に問題が発生しました。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"設定保存中に問題が発生しました。\",\n  \"components.Login.validationemailrequired\": \"有効なメールアドレスを入力してください\",\n  \"components.Login.signinwithplex\": \"Plex アカウントを使用する\",\n  \"components.Login.signinwithoverseerr\": \"{applicationTitle} アカウントを使用する\",\n  \"components.Login.signinheader\": \"続けるにはログインしてください\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"もっと見る\",\n  \"components.Login.validationpasswordrequired\": \"パスワードを入力してください\",\n  \"components.ResetPassword.validationemailrequired\": \"有効なメールアドレスを入力してください\",\n  \"components.Settings.Notifications.validationEmail\": \"有効なメールアドレスを入力してください\",\n  \"components.UserList.validationEmail\": \"メールアドレスが必要です\",\n  \"components.ResetPassword.email\": \"メールアドレス\",\n  \"components.UserList.email\": \"メールアドレス\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"エージェントを有効にする\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"エージェントを有効にする\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"エージェントを有効にする\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"エージェントを有効にする\",\n  \"components.PermissionEdit.request4k\": \"4K をリクエスト\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"通知\",\n  \"components.ResetPassword.password\": \"パスワード\",\n  \"components.UserList.password\": \"パスワード\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"パスワード\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"パスワード\",\n  \"i18n.edit\": \"編集\",\n  \"components.Settings.menuUsers\": \"ユーザー\",\n  \"components.UserList.users\": \"ユーザー\",\n  \"components.Settings.SettingsUsers.users\": \"ユーザー\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"設定保存中に問題が発生しました。\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"一般\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"一般設定\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"一般\",\n  \"pages.internalservererror\": \"内部サーバーエラー\",\n  \"pages.somethingwentwrong\": \"チケットが発生しました\",\n  \"pages.serviceunavailable\": \"サービスが利用できません\",\n  \"pages.pagenotfound\": \"ページが見つかりません\",\n  \"pages.errormessagewithcode\": \"{statusCode}－{error}\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Discover.StudioSlider.studios\": \"制作会社\",\n  \"components.Discover.NetworkSlider.networks\": \"テレビ局\",\n  \"components.Settings.enablessl\": \"SSL を有効にする\",\n  \"components.PersonDetails.lifespan\": \"{birthdate}－{deathdate}\",\n  \"components.PersonDetails.birthdate\": \"{birthdate}－\",\n  \"components.PersonDetails.alsoknownas\": \"別の呼び方：{names}\",\n  \"i18n.delimitedlist\": \"{a}、{b}\",\n  \"i18n.movie\": \"映画\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"映画\",\n  \"i18n.request\": \"リクエスト\",\n  \"components.PermissionEdit.request\": \"リクエスト\",\n  \"i18n.request4k\": \"4K をリクエスト\",\n  \"i18n.saving\": \"保存中…\",\n  \"i18n.save\": \"変更を保存\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"ウェブフック URL\",\n  \"i18n.next\": \"次\",\n  \"i18n.all\": \"すべて\",\n  \"i18n.loading\": \"ロード中…\",\n  \"i18n.testing\": \"テスト中…\",\n  \"i18n.test\": \"テストする\",\n  \"i18n.status\": \"状態\",\n  \"components.TvDetails.originaltitle\": \"原題\",\n  \"components.MovieDetails.originaltitle\": \"原題\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram のテスト通知が送信されました！\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"メールテスト通知が送信されました！\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord のテスト通知が送信されました！\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet のテスト通知が送信されました！\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover のテスト通知が送信されました！\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack のテスト通知が送信されました！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Telegram の通知設定の保存に失敗しました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"メール通知設定の保存に失敗しました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Discord の通知設定の保存に失敗しました。\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegram の通知設定の保存に失敗しました。\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbullet の通知設定の保存に失敗しました。\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushover の通知設定の保存に失敗しました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram の通知設定が保存されました！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"メール通知設定が保存されました！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord の通知設定が保存されました！\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram の通知設定が保存されました！\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet の通知設定が保存されました！\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover の通知設定が保存されました！\",\n  \"components.ResetPassword.validationpasswordrequired\": \"パスワードを入力してください\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {コミット} other {コミット}} behind\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"表示言語\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"すべての言語\",\n  \"components.LanguageSelector.languageServerDefault\": \"デフォルト言語（{language}）\",\n  \"components.DownloadBlock.estimatedtime\": \"所要時間：{time}\",\n  \"components.Discover.upcomingtv\": \"今後リリースされるシリーズ\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"シリーズのジャンル\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre}シリーズ\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language}のシリーズ\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"シリーズのジャンル\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"映画のジャンル\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"映画のジャンル\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio}の映画\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network}シーリーズ\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language}の映画\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre}映画\",\n  \"components.RequestModal.pending4krequest\": \"保留中の4Kリクエスト\",\n  \"components.RequestModal.errorediting\": \"リクエストを編集するときに問題が発生しました。\",\n  \"components.RequestModal.edit\": \"リクエストを編集\",\n  \"components.RequestModal.autoapproval\": \"自動承認\",\n  \"components.RequestModal.alreadyrequested\": \"すでにリクエスト済み\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"リクエストは自動的にマッチできませんでした。以下のリストから正しいマッチングを選択してください。\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"シーズン\",\n  \"components.RequestModal.QuotaDisplay.season\": \"シーズン\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"このユーザーはこのシーズンをリクエストするには、最低でも <strong>{seasons}</strong> シーズンリクエストが残っている必要があります。\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"このシーズンをリクエストするには、最低でも <strong>{seasons}</strong> シーズンリクエストが残っている必要があります。\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"残り <strong>{remaining}</strong> {type}リクエスト\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"このユーザーのリクエスト制限は<ProfileLink>プロフィールページ</ProfileLink>で確認できます。\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"リクエスト制限は<ProfileLink>プロフィールページ</ProfileLink>で確認できます。\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"シーズンリクエストが不足しています\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"映画\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"このユーザーは <strong>{days}</strong> 日ごとに <strong>{limit}</strong> {type}をリクエストできます。\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"<strong>{days}</strong> 日ごとに <strong>{limit}</strong> {type}をリクエストできます。\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"タグ\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"タグの選択\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"ルートフォルダ\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"別ユーザーとしてリクエスト\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"画質プロファイル\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"タグなし。\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"言語プロフィール\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path}（{space}）\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"送信先サーバー\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name}（デフォルト）\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* このシリーズはアニメです。\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"詳細オプション\",\n  \"components.RequestButton.viewrequest4k\": \"4Kリクエストを表示\",\n  \"components.RequestButton.viewrequest\": \"リクエストを表示\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"他のユーザーのリクエストを表示する権限を付与する。\",\n  \"components.RequestList.sortModified\": \"最終更新日\",\n  \"components.RequestList.sortAdded\": \"最新リクエスト\",\n  \"components.RequestList.showallrequests\": \"すべてのリクエストを表示\",\n  \"components.RequestList.RequestItem.requesteddate\": \"リクエストユーザー\",\n  \"components.RequestList.RequestItem.requested\": \"リクエスト\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{user}（{date}）\",\n  \"components.RequestList.RequestItem.modified\": \"最終更新者\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} が見つかりません\",\n  \"components.RequestList.RequestItem.failedretry\": \"リクエストを再試行するときに問題が発生しました。\",\n  \"components.RequestList.RequestItem.editrequest\": \"リクエストを編集\",\n  \"components.RequestList.RequestItem.deleterequest\": \"リクエストを削除\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"リクエストをキャンセル\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} が見つかりません\",\n  \"components.RequestCard.failedretry\": \"リクエストを再試行するときに問題が発生しました。\",\n  \"components.RequestCard.deleterequest\": \"リクエストを削除\",\n  \"components.RequestButton.requestmore4k\": \"もっと4Kリクエストする\",\n  \"components.RequestButton.requestmore\": \"もっとリクエストする\",\n  \"components.RequestButton.declinerequests\": \"{requestCount} つのリクエストを拒否\",\n  \"components.RequestButton.declinerequest4k\": \"4Kリクエストを拒否\",\n  \"components.RequestButton.declinerequest\": \"リクエストを拒否\",\n  \"components.RequestButton.decline4krequests\": \"{requestCount} つの 4K リクエストを拒否\",\n  \"components.RequestButton.approverequests\": \"{requestCount} つのリクエストを承認\",\n  \"components.RequestButton.approverequest4k\": \"4Kリクエストを承認\",\n  \"components.RequestButton.approverequest\": \"リクエストを承認\",\n  \"components.RequestButton.approve4krequests\": \"{requestCount, plural, one {4Kリクエスト} other {{requestCount} 4Kリクエスト}} を承認します\",\n  \"components.RequestBlock.server\": \"送信先サーバー\",\n  \"components.RequestBlock.rootfolder\": \"ルートフォルダ\",\n  \"components.RequestBlock.requestoverrides\": \"リクエストのオーバーライド\",\n  \"components.RequestBlock.profilechanged\": \"画質プロファイル\",\n  \"components.RegionSelector.regionServerDefault\": \"デフォルト（{region}）\",\n  \"components.RegionSelector.regionDefault\": \"全地域\",\n  \"components.QuotaSelector.unlimited\": \"無制限\",\n  \"components.QuotaSelector.tvRequests\": \"<quotaUnits>{quotaDays} {days}に </quotaUnits>{quotaLimit} {seasons}\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {シーズン} other {シーズン}}\",\n  \"components.QuotaSelector.movies\": \"映画\",\n  \"components.QuotaSelector.movieRequests\": \"<quotaUnits>{quotaDays} {days}に </quotaUnits>{quotaLimit} {movies}\",\n  \"components.QuotaSelector.days\": \"日\",\n  \"components.PermissionEdit.viewrequests\": \"リクエストを見る\",\n  \"components.PermissionEdit.usersDescription\": \"ユーザーを管理する権限を付与する。この権限を持つユーザーは、Admin 権限を持つユーザーの変更や、Admin 権限を付与することはできません。\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"ユーザーが承認を必要とする新メディアリクエストをすると通知する。\",\n  \"components.PermissionEdit.users\": \"ユーザー管理\",\n  \"components.PermissionEdit.requestTvDescription\": \"4K 以外のシリーズをリクエストする権限を与える。\",\n  \"components.PermissionEdit.requestTv\": \"シリーズをリクエスト\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"4K 以外の映画をリクエストする権限を与える。\",\n  \"components.PermissionEdit.requestMovies\": \"映画をリクエスト\",\n  \"components.PermissionEdit.requestDescription\": \"4K 以外のメディアをリクエストする権限を与える。\",\n  \"components.PermissionEdit.request4kTvDescription\": \"4K シリーズをリクエストする権限を与える。\",\n  \"components.PermissionEdit.request4kTv\": \"4K シリーズをリクエスト\",\n  \"components.PermissionEdit.request4kDescription\": \"4K メディアをリクエストする権限を与える。\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"4K 映画をリクエストする権限を与える。\",\n  \"components.PermissionEdit.request4kMovies\": \"4K映画をリクエスト\",\n  \"components.PermissionEdit.managerequestsDescription\": \"リクエストを管理する権限を付与する。この権限を持つユーザーのリクエストは、すべて自動的に承認されます。\",\n  \"components.PermissionEdit.managerequests\": \"リクエストを管理\",\n  \"components.MovieDetails.markavailable\": \"視聴可能をマーク\",\n  \"components.MovieDetails.mark4kavailable\": \"4K視聴可能をマーク\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr 安定版\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr開発版\",\n  \"components.Layout.VersionStatus.outofdate\": \"期限切れ\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"4K シリーズのリクエストを自動的に承認する。\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"4K映画のリクエストを自動的に承認する。\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"4K 以外のシリーズのリクエストを自動的に承認する。\",\n  \"components.PermissionEdit.autoapproveSeries\": \"シリーズを自動的に承認する\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"4K以外の映画のリクエストを自動的に承認する。\",\n  \"components.PermissionEdit.autoapproveMovies\": \"映画を自動的に承認する\",\n  \"components.PermissionEdit.autoapproveDescription\": \"4K以外のリクエストをすべて自動的に承認する。\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"4K シリーズを自動的に承認する\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"4K映画の自動的に承認する\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"すべての4Kリクエストを自動的に承認する。\",\n  \"components.PermissionEdit.autoapprove4k\": \"4Kの自動承認\",\n  \"components.PermissionEdit.autoapprove\": \"自動承認\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"高度なメディアリクエスト設定を変更する権限を付与する。\",\n  \"components.PermissionEdit.advancedrequest\": \"アドバンスド・リクエスト\",\n  \"components.PermissionEdit.adminDescription\": \"管理者のフルアクセス。すべての権限チェックをバイパスします。\",\n  \"components.PermissionEdit.admin\": \"管理者\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"他のユーザーが承認を必要とする新メディアリクエストをすると通知する。\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"RadarrまたはSonarrへのメディアリクエストの追加に失敗したときに通知をする。\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"メディアリクエストが拒否されたら通知する。\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"メディアリクエストが視聴可能になると通知する。\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"メディアリクエストが承認されると通知する。\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"他のユーザーの新メディアリクエストが自動的に承認されると通知する。\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"通知タイプ\",\n  \"components.NotificationTypeSelector.mediarequested\": \"リクエストは未承認\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"RadarrまたはSonarrへのメディアリクエストの追加に失敗したときに通知をする。\",\n  \"components.NotificationTypeSelector.mediafailed\": \"リクエストの処理が失敗した\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"メディアリクエストが拒否されると通知する。\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"リクエストは拒否された\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"メディアリクエストが視聴可能になりますと通知する。\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"リクエスト視聴可能\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"ユーザーのメディアリクエストが手動に承認されると通知する。\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"リクエストが承認された\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"ユーザーの新メディアリクエストが自動的に承認されると通知する。\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"リクエストを自動的に承認\",\n  \"components.MovieDetails.showmore\": \"もっと表示\",\n  \"components.MovieDetails.showless\": \"少なく表示\",\n  \"components.RequestModal.pendingapproval\": \"リクエストは承認待ちです。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"デフォルト言語（{language}）\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} 分\",\n  \"components.Settings.RadarrModal.loadingTags\": \"タグ読込中…\",\n  \"components.Settings.RadarrModal.notagoptions\": \"タグなし。\",\n  \"components.Settings.SonarrModal.animeTags\": \"アニメタグ\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"アニメ言語プロフィール\",\n  \"components.Settings.SonarrModal.notagoptions\": \"タグなし。\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"言語プロフィールを選ぶ\",\n  \"components.Settings.RadarrModal.selecttags\": \"タグを選ぶ\",\n  \"components.Settings.SonarrModal.loadingTags\": \"タグ読込中…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"言語プロフィール\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"言語プロフィール読込中…\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"言語プロフィールを選択してください\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"表示言語\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.ManageSlideOver.downloadstatus\": \"ダウンロード\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"データを消去\",\n  \"components.ManageSlideOver.manageModalRequests\": \"リクエスト\",\n  \"components.ManageSlideOver.openarr\": \"{arr} を開く\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"※リクエストを含め、すべての詳細情報が消去されます。この操作は元に戻すことができません。この作品が {mediaServerName} ライブラリに存在する場合、詳細情報は次のスキャンで再作成されます。\",\n  \"components.ManageSlideOver.openarr4k\": \"4K {arr} を開く\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"リクエストが有りません。\",\n  \"components.ManageSlideOver.manageModalTitle\": \"{mediaType}を管理\",\n  \"components.ManageSlideOver.movie\": \"映画\",\n  \"components.ManageSlideOver.tvshow\": \"シリーズ\",\n  \"components.IssueDetails.IssueDescription.edit\": \"チケット内容を編集\",\n  \"components.IssueDetails.allepisodes\": \"全エピソード\",\n  \"components.IssueDetails.allseasons\": \"全シーリーズ\",\n  \"components.IssueDetails.closeissue\": \"チケットをクローズ\",\n  \"components.IssueDetails.deleteissue\": \"チケットの削除\",\n  \"components.IssueDetails.commentplaceholder\": \"コメントを追加…\",\n  \"components.IssueDetails.deleteissueconfirm\": \"こちらのチケットを削除しますか？\",\n  \"components.IssueDetails.openinarr\": \"{arr} を開く\",\n  \"components.IssueDetails.season\": \"シーズン {seasonNumber}\",\n  \"components.IssueDetails.toaststatusupdated\": \"課題のステータスが正常に更新されました！\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"チケットステータスを更新する際に、問題が発生しました。\",\n  \"components.IssueDetails.unknownissuetype\": \"不明\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"メッセージの入力が必要です\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"こちらのコメントを削除しますか？\",\n  \"components.IssueDetails.IssueComment.delete\": \"コメントを削除\",\n  \"components.IssueDetails.IssueComment.edit\": \"コメントを編集\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"{username}による{relativeTime}に投稿（編集済み）\",\n  \"components.IssueDetails.IssueComment.postedby\": \"{username}による{relativeTime}に投稿\",\n  \"components.IssueDetails.nocomments\": \"コメントはありません。\",\n  \"components.IssueDetails.reopenissue\": \"チケットを再度開く\",\n  \"components.IssueDetails.problemseason\": \"該当シーリーズ\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"チケットを削除\",\n  \"components.IssueDetails.IssueDescription.description\": \"チケット内容\",\n  \"components.IssueDetails.comments\": \"コメント一覧\",\n  \"components.IssueDetails.issuetype\": \"チケット種類\",\n  \"components.IssueDetails.lastupdated\": \"最終更新日\",\n  \"components.IssueDetails.leavecomment\": \"コメント\",\n  \"components.IssueDetails.openin4karr\": \"4K {arr} を開く\",\n  \"components.IssueDetails.play4konplex\": \"Plexで4K再生\",\n  \"components.IssueDetails.reopenissueandcomment\": \"コメント追加して再度開く\",\n  \"components.IssueDetails.playonplex\": \"Plexで再生する\",\n  \"components.IssueDetails.problemepisode\": \"該当エピソード\",\n  \"components.IssueDetails.closeissueandcomment\": \"コメント追加してクローズ\",\n  \"components.IssueDetails.episode\": \"エピソード {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"チケット\",\n  \"components.IssueDetails.openedby\": \"{username}は#{issueId}を{relativeTime}に開きました\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"チケット内容編集中に問題が発生しました。\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"チケット内容の編集に成功しました！\",\n  \"components.IssueDetails.toastissuedeleted\": \"チケットの削除に成功しました！\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"チケットの削除する時に問題が発生しました。\",\n  \"components.ManageSlideOver.mark4kavailable\": \"4Kで視聴可能にする\",\n  \"components.MovieDetails.streamingproviders\": \"現在ストリーミング配信可能なプラットフォーム\",\n  \"components.NotificationTypeSelector.issuecreated\": \"チケット報告した\",\n  \"components.RequestModal.requestseasons4k\": \"4Kで{seasonCount}{seasonCount, plural, one {シーズン} other {シーズン}}をリクエスト\",\n  \"components.RequestModal.selectmovies\": \"映画を選択する\",\n  \"components.ResetPassword.confirmpassword\": \"パスワードを確認\",\n  \"components.ResetPassword.passwordreset\": \"パスワードをリセット\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"パスワードリセットリンクは、有効なユーザーの場合のみ、提供されたメールアドレスに送信されます。\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify の通知設定の保存に失敗しました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"メールを <OpenPgpLink>OpenPGP</OpenPgpLink> で暗号化する\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {エピソード} other {エピソード}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"不明\",\n  \"components.IssueList.sortAdded\": \"最新\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"すべてのシーズン\",\n  \"components.IssueList.showallissues\": \"すべてのチケットを表示\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"エピソード {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"特典\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"該当シーズン\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"チケットの詳細をご記入ください。\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"報告を送信\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"報告送信時に問題が発生した。\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"<strong>{title}</strong> の報告が送信されました！\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"チケットを表示\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"どうしましたか？\",\n  \"components.IssueModal.issueOther\": \"その他\",\n  \"components.IssueModal.issueSubtitles\": \"字幕\",\n  \"components.IssueModal.issueVideo\": \"映像\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"チケットの詳細を記入する必要があります\",\n  \"components.Layout.Sidebar.issues\": \"チケット\",\n  \"components.ManageSlideOver.manageModalIssues\": \"未解決チケット\",\n  \"components.NotificationTypeSelector.issuecomment\": \"チケットのコメント\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"自分が報告したチケットが解決された際に通知を受ける。\",\n  \"components.PermissionEdit.viewissuesDescription\": \"他のユーザーによって報告されたメディアの問題を表示する権限を付与すす。\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {#シーズン} other {#シーズン}}\",\n  \"components.Search.search\": \"検索\",\n  \"components.ManageSlideOver.opentautulli\": \"Tautulliで開く\",\n  \"components.ManageSlideOver.alltime\": \"現在まで\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"高度設定\",\n  \"components.ManageSlideOver.manageModalMedia\": \"メディア\",\n  \"components.ManageSlideOver.pastdays\": \"過去{days, number}日\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong>{playCount, plural, one {回} other {回}}\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"すべてのシーズンを4Kで視聴可能にする\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"チケットにコメントが追加される際に通知を受ける。\",\n  \"components.NotificationTypeSelector.issuereopened\": \"チケットを再度開いた\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"他ユーザーがチケットを報告する際に通知を受ける。\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"自ら報告したチケットが再度開いた際に通知を受ける。\",\n  \"components.PermissionEdit.manageissuesDescription\": \"メディアのチケットを管理する権限を付与する。\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL の末尾にスラッシュ（ / ）を入力してないでください\",\n  \"components.IssueList.sortModified\": \"最終更新\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"すべてのエピソード\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"該当エピソード\",\n  \"components.NotificationTypeSelector.issueresolved\": \"チケット解決済み\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"チケットが解決される際に通知を受ける。\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"自分が報告したチケットにコメントが追加した際に通知を受ける。\",\n  \"components.PermissionEdit.createissues\": \"チケットを報告\",\n  \"components.PermissionEdit.manageissues\": \"チケットを管理\",\n  \"components.PermissionEdit.viewissues\": \"チケットを表示\",\n  \"components.RequestModal.approve\": \"リクエストを承認\",\n  \"i18n.open\": \"未解決\",\n  \"components.RequestBlock.languageprofile\": \"言語プロフィール\",\n  \"components.RequestModal.requestApproved\": \"<strong>{title}</strong> のリクエストは承認されました!\",\n  \"components.RequestModal.requestcancelled\": \"<strong>{title}</strong> のリクエストはキャンセルされました。\",\n  \"components.RequestModal.requestmovies\": \"{count}{count, plural, one {映画} other {映画}}をリクエスト\",\n  \"components.RequestModal.requestmovies4k\": \"{count}{count, plural, one {映画} other {映画}}を4Kでリクエスト\",\n  \"components.ResetPassword.emailresetlink\": \"パスワードリセットリンクを送信\",\n  \"components.ResetPassword.gobacklogin\": \"ログインページへ戻る\",\n  \"components.ResetPassword.resetpassword\": \"パスワードをリセットする\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"パスワードリセットが成功しました！\",\n  \"components.ResetPassword.validationpasswordmatch\": \"パスワードは一致する必要があります\",\n  \"components.ResetPassword.validationpasswordminchars\": \"8文字以上のパスワードを入力してください\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify の通知設定が保存されました！\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Gotify のテスト通知を送信中…\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"通知の種類は一つ以上を選択してください\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"有効な URL を入力してください\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"<OpenPgpLink>OpenPGP</OpenPgpLink> を利用してメールを送信\",\n  \"components.IssueList.IssueItem.issuestatus\": \"ステータス\",\n  \"components.IssueList.IssueItem.opened\": \"報告者/報告日時：\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{user}・{date}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"該当エピソード\",\n  \"components.IssueList.IssueItem.issuetype\": \"種類\",\n  \"components.IssueModal.issueAudio\": \"オーディオ\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"チケットを報告\",\n  \"components.IssueModal.CreateIssueModal.season\": \"シーズン {seasonNumber}\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"すべてのシーズンを視聴可能にする\",\n  \"components.IssueList.issues\": \"チケット\",\n  \"components.IssueList.IssueItem.viewissue\": \"チケットを閲覧\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {シーズン} other {シーズン}}\",\n  \"components.ManageSlideOver.playedby\": \"再生者\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"<OpenPgpLink>OpenPGP</OpenPgpLink> を利用して暗号化されたメールを署名\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4Kメディア\",\n  \"components.MovieDetails.productioncountries\": \"制作{countryCount, plural, one {国} other {国}}\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"チケットが報告される際に通知を送信。\",\n  \"components.PermissionEdit.createissuesDescription\": \"チケットを報告できる権限を付与する。\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"他のユーザーがチケットにコメントすると通知を受け取る。\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"他ユーザーがチケットを報告する際に通知を受ける。\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"他ユーザーがチケットを解決した際に通知を受ける。\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"チケットが再度開く際に通知を受ける。\",\n  \"components.ManageSlideOver.markavailable\": \"視聴可能にする\",\n  \"components.RequestModal.requestedited\": \"<strong>{title}</strong>のリクエストは編集に成功しました!\",\n  \"components.RequestModal.requesterror\": \"リクエストの送信中に問題が発生しました。\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"アプリケーショントークンを入力してください\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify のテスト通知の送信に失敗しました。\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"エージェントを有効にする\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify のテスト通知を送信しました！\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"アプリケーショントークン\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"サーバーの URL\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"有効な URL を入力してください\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"有効な URL を入力してください\",\n  \"components.Settings.Notifications.validationUrl\": \"有効な URL を入力してください\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"有効な URL を入力してください\",\n  \"components.Settings.urlBase\": \"URL のベース\",\n  \"components.Settings.validationUrl\": \"有効な URL を入力してください\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"有効な URL を入力してください\",\n  \"components.Discover.CreateSlider.addSlider\": \"スライダーを追加\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"カスタムスライダーを作成\",\n  \"components.Discover.CreateSlider.addfail\": \"スライダーの作成に失敗しました。\",\n  \"components.Discover.CreateSlider.addsuccess\": \"新しいスライダーを作成し、ディスカバーのカスタマイズ設定を保存しました。\",\n  \"components.Discover.CreateSlider.editSlider\": \"スライダーの編集\",\n  \"components.Discover.CreateSlider.editfail\": \"スライダーの編集に失敗しました。\",\n  \"components.Discover.CreateSlider.editsuccess\": \"スライダーを編集し、検出カスタマイズ設定を保存しました。\",\n  \"components.Discover.CreateSlider.needresults\": \"1つ以上の結果が必要です。\",\n  \"components.Discover.CreateSlider.nooptions\": \"結果がありません。\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"TMDBジャンルIDを入力してください\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"TMDBキーワードIDを入力してください\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"TMDBネットワークIDを入力してください\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"検索クエリを入力してください\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"TMDBスタジオIDを入力してください\",\n  \"components.Discover.CreateSlider.searchGenres\": \"ジャンルを検索…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"検索キーワード…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"スタジオを検索…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"スライダー名\",\n  \"components.Discover.CreateSlider.starttyping\": \"検索するには入力を開始してください。\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"データ値を入力してください。\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"タイトルを入力してください。\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} 映画\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# アクティブフィルタ} other {# アクティブフィルタ}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"映画\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"人気（昇順）\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"人気（降順）\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"リリース日（昇順）\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"リリース日（降順）\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"タイトル (A-Z) （昇順）\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"タイトル (Z-A) （降順）\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB評価（昇順）\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB 評価 （降順）\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"スライダーの削除に失敗しました。\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"スライダーが削除されました。\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"表示の切り替え\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"取り除く\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# アクティブフィルタ} other {# アクティブフィルタ}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"シリーズ\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"初放送日（昇順）\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"初放送日（降順）\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"人気順（昇順）\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"人気順（降順）\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"タイトル (A-Z) （昇順）\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"タイトル (Z-A) （降順）\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB評価（昇順）\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB評価（昇順）\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} シリーズ\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"自分のウォッチリスト\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plexのウォッチリスト\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# アクティブフィルタ} other {# アクティブフィルタ}}\",\n  \"components.Discover.FilterSlideover.certification\": \"コンテンツ評価\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"アクティブフィルターをクリア\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"キーワードを除外\",\n  \"components.Discover.FilterSlideover.filters\": \"フィルター\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"初放送日\",\n  \"components.Discover.FilterSlideover.from\": \"から\",\n  \"components.Discover.FilterSlideover.genres\": \"ジャンル\",\n  \"components.Discover.FilterSlideover.keywords\": \"キーワード\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"オリジナル言語\",\n  \"components.Discover.FilterSlideover.ratingText\": \"{minValue} から {maxValue} までの評価\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"リリース日\",\n  \"components.Discover.FilterSlideover.runtime\": \"収録時間\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} 分の収録時間\",\n  \"components.Discover.FilterSlideover.status\": \"状態\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"ストリーミングサービス\",\n  \"components.Discover.FilterSlideover.studio\": \"スタジオ\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDBユーザースコア\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDBユーザー投票数\",\n  \"components.Discover.FilterSlideover.to\": \"に\",\n  \"components.Discover.FilterSlideover.voteCount\": \"{minValue} から {maxValue} までの投票数\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex ウォッチリスト</PlexWatchlistSupportLink>に追加されたメディアがここに表示されます。\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"ウォッチリスト\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"最近の追加\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"今後のシリーズ\",\n  \"components.Discover.createnewslider\": \"新しいスライダーの作成\",\n  \"components.Discover.customizediscover\": \"発見のカスタマイズ\",\n  \"components.Discover.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex ウォッチリスト</PlexWatchlistSupportLink>に追加されたメディアがここに表示されます。\",\n  \"components.Discover.moviegenres\": \"映画のジャンル\",\n  \"components.Discover.networks\": \"ネットワーク\",\n  \"components.Discover.plexwatchlist\": \"ウォッチリスト\",\n  \"components.Discover.resetfailed\": \"発見のカスタマイズ設定のリセット中に問題が発生しました。\",\n  \"components.Discover.resetsuccess\": \"発見のカスタマイズ設定がリセットされました。\",\n  \"components.Discover.resettodefault\": \"既定値にリセット\",\n  \"components.Discover.resetwarning\": \"すべてのスライダーを既定値にリセットします。これによりカスタムスライダーも削除されます！\",\n  \"components.Discover.stopediting\": \"編集を停止する\",\n  \"components.Discover.studios\": \"スタジオ\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB 映画ジャンル\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB 映画キーワード\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB 映画ストリーミングサービス\",\n  \"components.Discover.tmdbnetwork\": \"TMDBネットワーク\",\n  \"components.Discover.tmdbsearch\": \"TMDB検索\",\n  \"components.Discover.tmdbstudio\": \"TMDBスタジオ\",\n  \"components.Discover.tmdbtvgenre\": \"TMDBシリーズジャンル\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDBシリーズのキーワード\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TVストリーミングサービス\",\n  \"components.Discover.tvgenres\": \"シリーズのジャンル\",\n  \"components.Discover.updatefailed\": \"発見のカスタマイズ設定の更新中に問題が発生しました。\",\n  \"components.Discover.updatesuccess\": \"発見のカスタマイズ設定が更新されました。\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: シーズン {seasonNumber} エピソード {episodeNumber}\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"問題の説明\",\n  \"components.Layout.Sidebar.browsemovies\": \"映画\",\n  \"components.Layout.Sidebar.browsetv\": \"シリーズ\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"映画リクエスト\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"シリーズリクエスト\",\n  \"components.Layout.UserDropdown.requests\": \"リクエスト\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"メールアドレスが無効です。\",\n  \"components.Layout.UserWarnings.emailRequired\": \"メールアドレスが必要です。\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"パスワードが必要です。\",\n  \"components.Login.adminerror\": \"サインインするには管理者アカウントを使用してください。\",\n  \"components.Login.back\": \"戻る\",\n  \"components.Login.credentialerror\": \"ユーザー名またはパスワードが間違っています。\",\n  \"components.Login.description\": \"{applicationName} に初めてログインするために有効なメールアドレスを追加してください。\",\n  \"components.Login.emailtooltip\": \"アドレスは {mediaServerName} インスタンスに関連付ける必要はありません。\",\n  \"components.Login.enablessl\": \"SSLを使用する\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.initialsignin\": \"接続\",\n  \"components.Login.initialsigningin\": \"接続中…\",\n  \"components.Login.invalidurlerror\": \"{mediaServerName} サーバに接続できません。\",\n  \"components.Login.loginwithapp\": \"{appName} でログイン\",\n  \"components.Login.noadminerror\": \"サーバ上に管理者ユーザーが見つかりません。\",\n  \"components.Login.orsigninwith\": \"または次の方法でサインインします\",\n  \"components.Login.port\": \"ポート\",\n  \"components.Login.save\": \"追加\",\n  \"components.Login.saving\": \"追加中…\",\n  \"components.Login.servertype\": \"サーバの種類\",\n  \"components.Login.signinwithjellyfin\": \"{mediaServerName} アカウントを使用してください\",\n  \"components.Login.validationEmailRequired\": \"メールを設定してください\",\n  \"components.Login.validationPortRequired\": \"有効なポート番号を指定してください\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"URLベースの先頭にはスラッシュが必要です\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"URLベースの末尾はスラッシュで終わらないでください\",\n  \"components.Login.validationUrlTrailingSlash\": \"URLの末尾をスラッシュにしないでください\",\n  \"components.Login.validationemailformat\": \"有効なメールを入力してください\",\n  \"components.Login.validationhostformat\": \"有効なURLを入力してください\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URLを入力してください\",\n  \"components.Login.validationservertyperequired\": \"サーバの種類を選択してください\",\n  \"components.Login.validationusernamerequired\": \"ユーザー名を入力してください\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* これによりすべてのファイルを含むこの {mediaType} が {arr} から不可逆的に削除されます。\",\n  \"components.ManageSlideOver.removearr\": \"{arr} から削除\",\n  \"components.ManageSlideOver.removearr4k\": \"4K{arr} から削除\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"メタデータプロバイダーを選択してください\",\n  \"components.MetadataSelector.tmdbLabel\": \"映画データベース (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TVDB\",\n  \"components.MovieDetails.addtowatchlist\": \"ウォッチリストに追加\",\n  \"components.MovieDetails.digitalrelease\": \"デジタルリリース\",\n  \"components.MovieDetails.downloadstatus\": \"ダウンロード状態\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDBユーザースコア - 投票数: {formattedCount}\",\n  \"components.MovieDetails.managemovie\": \"映画の管理\",\n  \"components.MovieDetails.openradarr\": \"Radarrで映画を開く\",\n  \"components.MovieDetails.openradarr4k\": \"4KRadarrで映画を開く\",\n  \"components.MovieDetails.physicalrelease\": \"パッケージリリース\",\n  \"components.MovieDetails.play\": \"{mediaServerName} で再生\",\n  \"components.MovieDetails.play4k\": \"{mediaServerName} で4Kで再生\",\n  \"components.MovieDetails.removefromwatchlist\": \"ウォッチリストから削除\",\n  \"components.MovieDetails.reportissue\": \"問題を報告する\",\n  \"components.MovieDetails.rtaudiencescore\": \"ロッテントマトの視聴者スコア\",\n  \"components.MovieDetails.rtcriticsscore\": \"ロッテントマトのトマトメーター\",\n  \"components.MovieDetails.theatricalrelease\": \"劇場公開\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB ユーザースコア\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> がウォッチリストから削除されました！\",\n  \"components.MovieDetails.watchlistError\": \"何か問題が発生しました。もう一度試してください。\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> がウォッチリストに追加されました！\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"リクエストが自動的に送信されました\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"ウォッチリストのアイテムに対して新しいメディアリクエストが自動的に送信されると通知を受け取ります。\",\n  \"components.PermissionEdit.autorequest\": \"自動リクエスト\",\n  \"components.PermissionEdit.autorequestDescription\": \"Plexウォッチリスト経由で非4Kメディアのリクエストを自動的に送信する権限を付与します。\",\n  \"components.PermissionEdit.autorequestMovies\": \"映画の自動リクエスト\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Plexウォッチリスト経由で非4K映画のリクエストを自動的に送信する権限を付与します。\",\n  \"components.PermissionEdit.autorequestSeries\": \"シリーズの自動リクエスト\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Plexウォッチリスト経由で非4Kシリーズのリクエストを自動的に送信する権限を付与します。\",\n  \"components.PermissionEdit.viewrecent\": \"最近の追加を表示\",\n  \"components.PermissionEdit.viewrecentDescription\": \"最近追加されたメディアのリストを表示する権限を付与します。\",\n  \"components.PermissionEdit.viewwatchlists\": \"{mediaServerName} のウォッチリストを表示する\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"他のユーザーの {mediaServerName} ウォッチリストを表示する権限を付与します。\",\n  \"components.RequestBlock.approve\": \"リクエストの承認\",\n  \"components.RequestBlock.decline\": \"リクエストの拒否\",\n  \"components.RequestBlock.delete\": \"リクエストの削除\",\n  \"components.RequestBlock.edit\": \"リクエストの編集\",\n  \"components.RequestBlock.lastmodifiedby\": \"最終更新者\",\n  \"components.RequestBlock.requestdate\": \"リクエスト日\",\n  \"components.RequestBlock.requestedby\": \"リクエスト者\",\n  \"components.RequestCard.approverequest\": \"リクエストの承認\",\n  \"components.RequestCard.cancelrequest\": \"リクエストのキャンセル\",\n  \"components.RequestCard.declinerequest\": \"リクエストの拒否\",\n  \"components.RequestCard.editrequest\": \"リクエストの編集\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TVDB ID\",\n  \"components.RequestCard.unknowntitle\": \"タイトル不明\",\n  \"components.RequestList.RequestItem.profileName\": \"プロフィール\",\n  \"components.RequestList.RequestItem.removearr\": \"{arr} から削除\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TVDB ID\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"タイトル不明\",\n  \"components.RequestList.sortDirection\": \"ソート方向の切り替え\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"このシリーズに一致するものが見つかりませんでした。\",\n  \"components.RequestModal.requestcollection4ktitle\": \"4Kコレクションのリクエスト\",\n  \"components.RequestModal.requestcollectiontitle\": \"コレクションのリクエスト\",\n  \"components.RequestModal.requestmovie4ktitle\": \"4K映画のリクエスト\",\n  \"components.RequestModal.requestmovietitle\": \"映画のリクエスト\",\n  \"components.RequestModal.requestseries4ktitle\": \"4Kシリーズのリクエスト\",\n  \"components.RequestModal.requestseriestitle\": \"シリーズのリクエスト\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"証明書の読込みに失敗しました\",\n  \"components.Selector.CertificationSelector.maxRating\": \"最大評価\",\n  \"components.Selector.CertificationSelector.minRating\": \"最小評価\",\n  \"components.Selector.CertificationSelector.noOptions\": \"利用可能なオプションはありません\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"証明書を選択してください\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"国を選択してください\",\n  \"components.Selector.CertificationSelector.starttyping\": \"検索するには入力を開始してください。\",\n  \"components.Selector.canceled\": \"キャンセルされました\",\n  \"components.Selector.ended\": \"完了\",\n  \"components.Selector.inProduction\": \"製品版\",\n  \"components.Selector.nooptions\": \"結果はありません。\",\n  \"components.Selector.pilot\": \"パイロット版\",\n  \"components.Selector.planned\": \"計画済み\",\n  \"components.Selector.returningSeries\": \"再放送\",\n  \"components.Selector.searchGenres\": \"ジャンルを選択…\",\n  \"components.Selector.searchKeywords\": \"キーワード検索…\",\n  \"components.Selector.searchStatus\": \"ステータスを選択...\",\n  \"components.Selector.searchStudios\": \"スタジオを検索…\",\n  \"components.Selector.searchUsers\": \"ユーザーの選択…\",\n  \"components.Selector.showless\": \"表示を減らす\",\n  \"components.Selector.showmore\": \"もっと見る\",\n  \"components.Selector.starttyping\": \"検索するには入力を開始してください。\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"優先度\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"優先番号を設定してください\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"エージェントを有効にする\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"ポスターを埋め込む\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Ntfy 通知設定を保存できませんでした。\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Ntfy通知設定が保存されました！\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"パスワード\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Ntfy テスト通知の送信に失敗しました。\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"ntfy テスト通知を送信中…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Ntfy テスト通知が送信されました！\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"トークン\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"トークン認証\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"トピック\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"サーバのルートURL\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"ユーザー名\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"ユーザー名 + パスワード認証\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"トピックを指定してください\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"有効なURLを指定してください\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"通知タイプを1つ以上選択してください\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"チャンネルタグ\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet 通知設定を保存できませんでした。\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Pushbullet テスト通知を送信中…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"アクセストークンを指定してください\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"通知タイプを1つ以上選択してください\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"アプリケーションAPIトークン\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"Seerrで使用する<ApplicationRegistrationLink>アプリを登録</ApplicationRegistrationLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"デバイスのデフォルト\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"ポスターを埋め込む\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"通知音\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover テスト通知の送信に失敗しました。\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Pushover テスト通知を送信中…\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"ユーザーまたはグループキー\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"30文字の<UsersGroupsLink>ユーザーまたはグループの識別子</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"有効なアプリケーショントークンを提供してください\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"通知タイプを1つ以上選択してください\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"有効なユーザーまたはグループキーを指定してください\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"ポスターを埋め込む\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack テスト通知の送信に失敗しました。\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Slack テスト通知を送信しています…\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"通知タイプを1つ以上選択してください\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"<WebhookLink>受信 Webhook</WebhookLink> 統合を作成する\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"認証ヘッダー\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSONペイロード\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"既定値にリセット\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSONペイロードがリセットされました！\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"URLパラメータのサポート\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"用可能な変数はWebhookテンプレート変数セクションに記載されています\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"テンプレート変数のヘルプ\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Webhook テスト通知の送信に失敗しました。\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Webhook テスト通知を送信中…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook テスト通知が送信されました！\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"有効な JSONペイロードを指定してください\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"通知タイプを1つ以上選択してください\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"テスト通知URLは、実際のWebhook URLではなく{testUrl}に設定されます。\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Webhook 通知設定を保存できませんでした。\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Webhook 通知設定が保存されました！\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"エージェントを有効にする\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"ポスターを埋め込む\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Webプッシュ通知を受信するには、SeerrをHTTPS経由で提供してください。\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Webプッシュ テスト通知の送信に失敗しました。\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Webプッシュテスト通知を送信中…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Webプッシュテスト通知を送信しました！\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Webプッシュ通知設定の保存に失敗しました。\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Webプッシュ通知設定が保存されました！\",\n  \"components.Settings.Notifications.botAPI\": \"ボット認証トークン\",\n  \"components.Settings.Notifications.botApiTip\": \"Seerrで使用する<CreateBotLink>ボットを作成する</CreateBotLink>\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"ボットアバターのURL\",\n  \"components.Settings.Notifications.botUsername\": \"ボットのユーザー名\",\n  \"components.Settings.Notifications.botUsernameTip\": \"ユーザーがボットとチャットを開始し独自の通知を構成できるようにする\",\n  \"components.Settings.Notifications.chatId\": \"チャットID\",\n  \"components.Settings.Notifications.chatIdTip\": \"ボットとチャットを開始し、<GetIdBotLink>@get_id_bot</GetIdBotLink> を追加して <code>/my_id</code> コマンドを実行してください\",\n  \"components.Settings.Notifications.embedPoster\": \"ポスターを埋め込む\",\n  \"components.Settings.Notifications.enableMentions\": \"メンションを有効にする\",\n  \"components.Settings.Notifications.encryption\": \"暗号化方式\",\n  \"components.Settings.Notifications.encryptionDefault\": \"利用可能な場合は STARTTLS を使用する\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"暗黙的TLSを使用する\",\n  \"components.Settings.Notifications.encryptionNone\": \"なし\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"常にSTARTTLSを使用する\",\n  \"components.Settings.Notifications.encryptionTip\": \"ほとんどの場合暗黙的TLSはポート 465 を使用しSTARTTLSはポート 587 を使用します\",\n  \"components.Settings.Notifications.messageThreadId\": \"スレッド/トピック ID\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"グループチャットでトピックが有効になっている場合、ここでスレッド/トピックのIDを指定できます\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGPパスワード\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP秘密鍵\",\n  \"components.Settings.Notifications.sendSilently\": \"サイレント送信\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"音を出さずに通知を送信する\",\n  \"components.Settings.Notifications.senderName\": \"送信者名\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord テスト通知の送信に失敗しました。\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Discord テスト通知を送信中…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"メールテスト通知の送信に失敗しました。\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"メールテスト通知を送信中…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram テスト通知の送信に失敗しました。\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Telegram テスト通知を送信中…\",\n  \"components.Settings.Notifications.userEmailRequired\": \"ユーザーのメールを必須にする\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"ボット認証トークンを指定してください\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"有効なチャットIDを指定してください\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"スレッド/トピックIDは正の整数にしてください\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"PGPパスワードを入力してください\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"有効なPGP秘密キーを指定してください\",\n  \"components.Settings.Notifications.validationTypes\": \"通知タイプを1つ以上選択してください\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"有効なDiscord ロールIDを指定してください\",\n  \"components.Settings.Notifications.webhookRoleId\": \"ロールIDの通知\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"Webhookメッセージで言及するロールID。メンションを無効にするには空のままにしてください\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"サーバに<DiscordWebhookLink>webhook連携</DiscordWebhookLink>を作成してください\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"条件\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"パラメータ変更を適用する前に条件を指定します。ルールを適用するには各フィールドの検証が必要です（AND演算）。いずれかのプロパティが一致した場合そのフィールドは検証済みと見なされます（OR演算）。\",\n  \"components.Settings.OverrideRuleModal.create\": \"ルールの作成\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"新しい上書きルール\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"上書きルールの編集\",\n  \"components.Settings.OverrideRuleModal.genres\": \"ジャンル\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"キーワード\",\n  \"components.Settings.OverrideRuleModal.languages\": \"言語\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"タグはありません。\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"品質プロファイル\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"ルートフォルダー\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"上書きルールが作成されました！\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"上書きルールが更新されました！\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"品質プロファイルの選択\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"ルートフォルダーを選択\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"サービスの選択\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"タグの選択\",\n  \"components.Settings.OverrideRuleModal.service\": \"サービス\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"このルールを選択したサービスに適用します。\",\n  \"components.Settings.OverrideRuleModal.settings\": \"設定\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"上記の条件が満たされた場合にどの設定を変更するかを指定します。\",\n  \"components.Settings.OverrideRuleModal.tags\": \"タグ\",\n  \"components.Settings.OverrideRuleModal.users\": \"ユーザー\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"条件\",\n  \"components.Settings.OverrideRuleTile.genre\": \"ジャンル\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"キーワード\",\n  \"components.Settings.OverrideRuleTile.language\": \"言語\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"品質プロファイル\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"ルートフォルダー\",\n  \"components.Settings.OverrideRuleTile.settings\": \"設定\",\n  \"components.Settings.OverrideRuleTile.tags\": \"タグ\",\n  \"components.Settings.OverrideRuleTile.users\": \"ユーザー\",\n  \"components.Settings.RadarrModal.announced\": \"発表された\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"新しい4K Radarrサーバを追加\",\n  \"components.Settings.RadarrModal.default4kserver\": \"デフォルトの4Kサーバ\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"4K Radarrサーバの編集\",\n  \"components.Settings.RadarrModal.enableSearch\": \"自動検索を有効にする\",\n  \"components.Settings.RadarrModal.externalUrl\": \"外部URL\",\n  \"components.Settings.RadarrModal.inCinemas\": \"劇場公開中\",\n  \"components.Settings.RadarrModal.released\": \"リリースされた\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"スキャンを有効にする\",\n  \"components.Settings.RadarrModal.tagRequests\": \"タグリクエスト\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"リクエスト者のユーザーIDと表示名を含む追加のタグを自動的に追加します\",\n  \"components.Settings.RadarrModal.tags\": \"タグ\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"タグを読込むための接続テスト\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URLの末尾をスラッシュにしないでください\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URLベースには先頭にスラッシュが必要です\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URLベースの末尾をスラッシュにしないでください\",\n  \"components.Settings.SettingsAbout.about\": \"アプリ情報\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"データディレクトリ\",\n  \"components.Settings.SettingsAbout.documentation\": \"ドキュメント\",\n  \"components.Settings.SettingsAbout.outofdate\": \"期限切れ\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"あなたはSeerrの<code>開発版</code>のブランチを実行しています。このブランチは開発に貢献する方や最先端のテストを支援する方にのみ推奨されます。\",\n  \"components.Settings.SettingsAbout.uptodate\": \"最新\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"メディア可用性の同期\",\n  \"components.Settings.SettingsJobsCache.cache\": \"キャッシュ\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerrは外部APIエンドポイントへのリクエストをキャッシュしてパフォーマンスを最適化し、不要なAPI呼び出しを回避します。\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} キャッシュがクリアされました。\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"ヒット数\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"キーの総数\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"キーサイズ\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"ミス\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"キャッシュ名\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"値のサイズ\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"ジョブのキャンセル\",\n  \"components.Settings.SettingsJobsCache.command\": \"コマンド\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNSキャッシュ\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"SeerrはDNSルックアップをキャッシュしてパフォーマンスを最適化し、不要なAPI呼び出しを回避します。\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"グローバルDNSキャッシュ統計\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"これらの統計はすべてのDNSキャッシュエントリにわたって集計されます。\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"アクティブアドレス\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"年\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"{hostname} のDNSキャッシュがクリアされました。\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"ヒット数\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"ミス\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"ホスト名\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"ダウンロード同期\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"ダウンロード同期のリセット\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"ジョブの変更\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"現在の周波数\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"新しい周波数\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"{jobScheduleDays, plural, one {1日} other {{jobScheduleDays} 日}} おき\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"{jobScheduleHours, plural, one {1時間} other {{jobScheduleHours} 時間}} おき\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"{jobScheduleMinutes, plural, one {1分} other {{jobScheduleMinutes} 分}} おき\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"{jobScheduleSeconds, plural, one {1秒} other {{jobScheduleSeconds} 秒}} おき\",\n  \"components.Settings.SettingsJobsCache.failures\": \"失敗\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"キャッシュクリア\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"DNSキャッシュクリア\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"ヒット率\",\n  \"components.Settings.SettingsJobsCache.hits\": \"ヒット数\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"画像キャッシュのクリーンアップ\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"画像キャッシュ\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"設定で有効化するとSeerrは事前設定された外部ソースからの画像をプロキシ経由で取得しキャッシュします。キャッシュされた画像は設定フォルダに保存されます。ファイルは<code>{appDataPath}/cache/images</code>で確認できます。\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"キャッシュされた画像\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"合計キャッシュサイズ\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4フォールバック\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Jellyfin フルライブラリスキャン\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Jellyfinの最近の追加をスキャン\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"ジョブの保存中に問題が発生しました。\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"ジョブは正常に編集されました！\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} がキャンセルされました。\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"ジョブ名\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"ジョブ\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerrは定期的にスケジュールされたジョブとして特定のメンテナンスタスクを実行しますが、以下で手動でトリガーすることもできます。ジョブを手動で実行してもスケジュールは変更されません。\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"ジョブとキャッシュ\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} が開始されました。\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"タイプ\",\n  \"components.Settings.SettingsJobsCache.misses\": \"ミス\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"次回の実行\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plex フルライブラリスキャン\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plexの最近の追加をスキャン\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex リフレッシュトークン\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex ウォッチリストの同期\",\n  \"components.Settings.SettingsJobsCache.process\": \"プロセス\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarrをスキャン\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"今すぐ実行\",\n  \"components.Settings.SettingsJobsCache.size\": \"サイズ\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarrをスキャン\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"不明なジョブ\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"ユーザーのアバター\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"クリップボードにコピー\",\n  \"components.Settings.SettingsLogs.extraData\": \"追加データ\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"デバッグ\",\n  \"components.Settings.SettingsLogs.filterError\": \"エラー\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"情報\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"警告\",\n  \"components.Settings.SettingsLogs.label\": \"ラベル\",\n  \"components.Settings.SettingsLogs.level\": \"重大度\",\n  \"components.Settings.SettingsLogs.logDetails\": \"ログの詳細\",\n  \"components.Settings.SettingsLogs.logs\": \"ログ\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"これらのログは <code>stdout</code>経由で直接表示することも、<code>{appDataPath}/logs/seerr.log</code>で確認することもできます。\",\n  \"components.Settings.SettingsLogs.message\": \"メッセージ\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"一時停止\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"再開\",\n  \"components.Settings.SettingsLogs.showall\": \"すべてのログを表示\",\n  \"components.Settings.SettingsLogs.time\": \"タイムスタンプ\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"詳細を見る\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"APIキーをクリップボードにコピーしました。\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"アプリ名\",\n  \"components.Settings.SettingsMain.applicationurl\": \"アプリのURL\",\n  \"components.Settings.SettingsMain.cacheImages\": \"画像キャッシュを有効にする\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"外部ソースのイメージをキャッシュします（大量のディスク容量が必要）\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"地域を見つける\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"利用可能な地域に応じてコンテンツをフィルタリングする\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"スペシャルエピソードのリクエストを許可する\",\n  \"components.Settings.SettingsMain.general\": \"一般\",\n  \"components.Settings.SettingsMain.generalsettings\": \"一般設定\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Seerrのグローバル設定とデフォルト設定を構成します。\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"利用可能なメディアを非表示にする\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"発見ページからは利用可能なメディアを非表示にするが、検索結果からは非表示にしない\",\n  \"components.Settings.SettingsMain.locale\": \"表示言語\",\n  \"components.Settings.SettingsMain.originallanguage\": \"言語を見つける\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"元の言語でコンテンツをフィルタリングする\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"部分的なシリーズリクエストを許可する\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"ストリーミング地域\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"利用可能な地域別にストリーミングサイトを表示する\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"新しいAPIキーの生成中に問題が発生しました。\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"新しいAPIキーが生成されました！\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"設定の保存中に問題が発生しました。\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"設定が保存されました！\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"アプリ名を入力してください\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"有効なURLを指定してください\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URLの末尾をスラッシュにしないでください\",\n  \"components.Settings.SettingsMain.validationUrl\": \"有効なURLを指定してください\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URLの末尾をスラッシュにしないでください\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTubeのURL\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"自己ホスト型のYouTubeインスタンスが使用されている場合のYouTube動画のベース URL。\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"CSRF保護を有効にする\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"何をしようとしているのか理解していない限り、この設定を有効にしないでください！\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"外部APIアクセスを読み取り専用に設定します（HTTPSが必要）\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNSキャッシュ\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"DNSキャッシュの最大TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"DNSキャッシュの最小TTL\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"DNSルックアップで問題が発生している場合はこれを有効にしないでください\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"DNSルックアップのキャッシュを有効にしてパフォーマンスを最適化し、不要な API 呼び出しを回避します\",\n  \"components.Settings.SettingsNetwork.docs\": \"ドキュメント\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"IPv4解決を最初に強制する\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"SeerrがIPv6ではなくIPv4アドレスを最初に解決するように強制する\",\n  \"components.Settings.SettingsNetwork.network\": \"ネットワーク\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"これらの設定ではなく、コンテナ/システム側のネットワークパラメータを使用してください。詳細は{docs}を参照してください。\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"ネットワーク設定\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Seerrインスタンスのネットワーク設定を構成します。\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"プロキシで無視されるアドレス\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"区切り文字として「,」と「*.」を使用します。サブドメインのワイルドカードとして\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"ローカルアドレスのバイパスプロキシ\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) プロキシ\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"プロキシのホスト名\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"プロキシパスワード\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"プロキシポート\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"プロキシにSSLを使用する\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"プロキシのユーザー名\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"設定の保存中に問題が発生しました。\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"設定が保存されました！\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"プロキシサポートを有効にする\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Seerrがプロキシの背後でクライアントIPアドレスを正しく登録できるようにする\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"有効なポートを指定してください\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"1つ以上のの認証方法を選択してください。\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"デフォルトの権限\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"新しいユーザーに割り当てられる初期権限\",\n  \"components.Settings.SettingsUsers.localLogin\": \"ローカルサインインを有効にする\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"ユーザーが自分のメールアドレスとパスワードを使用してサインインできるようにします\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"ログイン方法\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"ユーザーのログイン方法を設定します。\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"{mediaServerName} のサインインを有効にする\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"ユーザーが自分の {mediaServerName} アカウントを使用してサインインできるようにします\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"グローバル映画リクエスト制限\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"新しい {mediaServerName} サインインを有効にする\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"最初にインポートせずに {mediaServerName} ユーザーにサインインを許可する\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"ユーザー設定が保存されました！\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"グローバルシリーズリクエスト制限\",\n  \"components.Settings.SettingsUsers.userSettings\": \"ユーザー設定\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"グローバル設定とデフォルトのユーザー設定を構成します。\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"アニメシリーズの種類\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"新しい4K Sonarrサーバを追加する\",\n  \"components.Settings.SonarrModal.default4kserver\": \"デフォルトの4Kサーバ\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"4K Sonarrサーバの編集\",\n  \"components.Settings.SonarrModal.enableSearch\": \"自動検索を有効にする\",\n  \"components.Settings.SonarrModal.externalUrl\": \"外部URL\",\n  \"components.Settings.SonarrModal.selecttags\": \"タグの選択\",\n  \"components.Settings.SonarrModal.seriesType\": \"シリーズタイプ\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"スキャンを有効にする\",\n  \"components.Settings.SonarrModal.tagRequests\": \"タグリクエスト\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"リクエスト者のユーザーIDと表示名を含む追加のタグを自動的に追加します\",\n  \"components.Settings.SonarrModal.tags\": \"タグ\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"言語プロファイルを読込むための接続をテストします\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"タグを読込むための接続をテストする\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Sonarrへの接続に失敗しました。\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr接続が確立されました！\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URLの末尾をスラッシュにしないでください\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"ベースURLには先頭にスラッシュが必要です\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"ベースURLの末尾をスラッシュにしないでください\",\n  \"components.Settings.addrule\": \"新しい上書きルール\",\n  \"components.Settings.advancedTooltip\": \"この設定を誤って構成すると機能が正常に動作しなくなる可能性があります\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"選択されたすべてのメタデータプロバイダーが動作中です\",\n  \"components.Settings.animeMetadataProvider\": \"アニメのメタデータプロバイダー\",\n  \"components.Settings.chooseProvider\": \"さまざまなコンテンツタイプのメタデータプロバイダーを選択する\",\n  \"components.Settings.clickTest\": \"[テスト]ボタンをクリックしてメタデータプロバイダーとの接続を確認する\",\n  \"components.Settings.connectionTestFailed\": \"接続テストに失敗しました\",\n  \"components.Settings.deleteServer\": \"{serverType}サーバを削除\",\n  \"components.Settings.email\": \"メール\",\n  \"components.Settings.experimentalTooltip\": \"この設定を有効にするとアプリケーションが予期しない動作をする可能性があります\",\n  \"components.Settings.externalUrl\": \"外部URL\",\n  \"components.Settings.failed\": \"動作しません\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"メタデータプロバイダーの設定を保存できませんでした\",\n  \"components.Settings.general\": \"一般\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} はTMDBキーワードではありません。\",\n  \"components.Settings.invalidurlerror\": \"{mediaServerName} サーバに接続できません。\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"パスワードを忘れた場合のURL\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName} の設定\",\n  \"components.Settings.jellyfinSettingsDescription\": \"必要に応じて{mediaServerName}サーバの内部エンドポイントと外部エンドポイントを構成します。ほとんどの場合、外部URLは内部URLとは異なります。別のパスワードリセットページにリダイレクトしたい場合に備えて、{mediaServerName}ログイン用にカスタムパスワードリセットURLを設定することもできます。以前に自動的に生成されたJellyfin APIキーを変更することもできます。\",\n  \"components.Settings.jellyfinSettingsFailure\": \"{mediaServerName} 設定の保存中に問題が発生しました。\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName} の設定が保存されました！\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"自動ライブラリグループ化によるカスタム認証はサポートされていません\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"ライブラリの同期中に問題が発生しました\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"ライブラリが見つかりませんでした\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName} ライブラリ\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"ライブラリ {mediaServerName} がタイトルをスキャンします。ライブラリがリストされていない場合は下のボタンをクリックしてください。\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName} の設定\",\n  \"components.Settings.jellyfinsettingsDescription\": \"{mediaServerName}サーバの設定を構成します。 {mediaServerName} は、{mediaServerName} ライブラリをスキャンして利用可能なコンテンツを確認します。\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"通常は 24 時間に一度しか実行されません。Seerrは{mediaServerName}サーバーの最近追加されたフォルダをより頻繁にチェックします。初めてSeerrを設定する場合は、一度手動でライブラリーをスキャンすることをお勧めします！\",\n  \"components.Settings.manualscanJellyfin\": \"手動ライブラリスキャン\",\n  \"components.Settings.mediaTypeMovie\": \"映画\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.menuMetadataProviders\": \"メタデータプロバイダー\",\n  \"components.Settings.menuNetwork\": \"ネットワーク\",\n  \"components.Settings.metadataProviderSelection\": \"メタデータプロバイダーの選択\",\n  \"components.Settings.metadataProviderSettings\": \"メタデータプロバイダー\",\n  \"components.Settings.metadataSettings\": \"メタデータプロバイダーの設定\",\n  \"components.Settings.metadataSettingsSaved\": \"メタデータプロバイダーの設定が保存されました\",\n  \"components.Settings.no\": \"いいえ\",\n  \"components.Settings.noDefault4kServer\": \"ユーザーが4K{mediaType}リクエストを送信できるようにするには、4K{serverType}サーバをデフォルトとしてマークしてください。\",\n  \"components.Settings.noDefaultNon4kServer\": \"非4Kコンテンツと4Kコンテンツの両方に対応する{serverType}サーバが1台しかない場合（または4Kコンテンツのみをダウンロードする場合）、その{serverType}サーバを4Kサーバとして指定しては<strong>いけません</strong>。\",\n  \"components.Settings.noDefaultServer\": \"{mediaType}リクエストを処理するには、1つ以上の {serverType}サーバをデフォルトとしてマークしてください。\",\n  \"components.Settings.noSpecialCharacters\": \"設定はTMDBキーワードIDのカンマ区切りのリストである必要があり、カンマで開始または終了することはできません。\",\n  \"components.Settings.nooptions\": \"結果はありません。\",\n  \"components.Settings.notTested\": \"未テスト\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"通知エージェントを構成して有効にします。\",\n  \"components.Settings.notifications\": \"通知\",\n  \"components.Settings.operational\": \"稼働中\",\n  \"components.Settings.overrideRules\": \"上書きルール\",\n  \"components.Settings.overrideRulesDescription\": \"上書きルールを使用すると、リクエストがルールに一致する場合に置き換えられるプロパティを指定できます。\",\n  \"components.Settings.providerStatus\": \"メタデータプロバイダーのステータス\",\n  \"components.Settings.restartrequiredTooltip\": \"この設定への変更を有効にするにはSeerrを再起動してください\",\n  \"components.Settings.save\": \"変更を保存\",\n  \"components.Settings.saving\": \"保存中…\",\n  \"components.Settings.scan\": \"ライブラリを同期する\",\n  \"components.Settings.scanbackground\": \"スキャンはバックグラウンドで実行されます。その間セットアッププロセスを続行できます。\",\n  \"components.Settings.scanning\": \"同期中…\",\n  \"components.Settings.searchKeywords\": \"検索キーワード…\",\n  \"components.Settings.seriesMetadataProvider\": \"シリーズのメタデータプロバイダー\",\n  \"components.Settings.serverLocal\": \"地域\",\n  \"components.Settings.serverRemote\": \"リモート\",\n  \"components.Settings.serverSecure\": \"セキュア\",\n  \"components.Settings.serverpreset\": \"サーバ\",\n  \"components.Settings.serverpresetLoad\": \"ボタンを押して利用可能なサーバをロードします\",\n  \"components.Settings.serverpresetManualMessage\": \"手動構成\",\n  \"components.Settings.serverpresetRefreshing\": \"サーバを取得中…\",\n  \"components.Settings.serviceSettingsDescription\": \"以下で {serverType}サーバを構成します。複数の {serverType}サーバに接続できますが、デフォルトとしてマークできるサーバは2つだけです（1つは非4K、もう1つは4K）。管理者は承認前に新しいリクエストの処理に使用されるサーバを上書きできます。\",\n  \"components.Settings.services\": \"サービス\",\n  \"components.Settings.settingUpPlexDescription\": \"Plexを設定するには詳細を手動で入力するか、<RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>から取得したサーバーを選択できます。ドロップダウンの右側にあるボタンを押すと利用可能なサーバーの一覧を取得できます。\",\n  \"components.Settings.settings\": \"設定\",\n  \"components.Settings.starttyping\": \"検索するには入力を開始してください。\",\n  \"components.Settings.syncJellyfin\": \"ライブラリの同期\",\n  \"components.Settings.syncing\": \"同期中\",\n  \"components.Settings.tautulliApiKey\": \"APIキー\",\n  \"components.Settings.tautulliSettings\": \"Tautulli設定\",\n  \"components.Settings.tautulliSettingsDescription\": \"必要に応じてTautulliサーバの設定を構成します。SeerrはPlexメディアの視聴履歴データをTautulliから取得します。\",\n  \"components.Settings.timeout\": \"タイムアウト\",\n  \"components.Settings.tip\": \"ヒント\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"TMDBプロバイダーが機能しません。別のメタデータプロバイダーを選択してください\",\n  \"components.Settings.toastPlexConnecting\": \"Plexに接続しようとしています…\",\n  \"components.Settings.toastPlexRefresh\": \"Plexからサーバリストを取得しています…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Plexサーバリストの取得に失敗しました。\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Plexサーバのリストを取得しました！\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Tautulli設定の保存中に問題が発生しました。\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli設定が保存されました！\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"TVDBプロバイダーが機能しません。別のメタデータプロバイダーを選択してください\",\n  \"components.Settings.validationApiKey\": \"APIキーを指定してください\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URLベースには先頭にスラッシュが必要です\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"URLベースの末尾をスラッシュにしないでください\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URLの末尾をスラッシュにしないでください\",\n  \"components.Settings.valueRequired\": \"値を指定してください。\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Webアプリ</WebAppLink>URL\",\n  \"components.Settings.webAppUrlTip\": \"オプションで「ホストされた」Web アプリではなく、サーバ上のWebアプリにユーザーを誘導します\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.webpush\": \"Webプッシュ\",\n  \"components.Settings.yes\": \"はい\",\n  \"components.Setup.back\": \"戻る\",\n  \"components.Setup.configemby\": \"Embyの構成\",\n  \"components.Setup.configjellyfin\": \"Jellyfinの構成\",\n  \"components.Setup.configplex\": \"Plexの構成\",\n  \"components.Setup.configuremediaserver\": \"メディアサーバの構成\",\n  \"components.Setup.librarieserror\": \"検証が失敗しました。続行するにはライブラリを再度切り替えてください。\",\n  \"components.Setup.servertype\": \"サーバの種類を選択してください\",\n  \"components.Setup.setup\": \"設定\",\n  \"components.Setup.signin\": \"サインイン\",\n  \"components.Setup.signinWithEmby\": \"Embyの詳細を入力してください\",\n  \"components.Setup.signinWithJellyfin\": \"Jellyfinの詳細を入力してください\",\n  \"components.Setup.signinWithPlex\": \"Plexの詳細を入力してください\",\n  \"components.Setup.subtitle\": \"メディアサーバを選択して開始します\",\n  \"components.StatusBadge.managemedia\": \"{mediaType}を管理する\",\n  \"components.StatusBadge.openinarr\": \"{arr}で開く\",\n  \"components.StatusBadge.playonplex\": \"{mediaServerName}で再生する\",\n  \"components.StatusBadge.seasonepisodenumber\": \"{seasonNumber}期{episodeNumber}話\",\n  \"components.StatusBadge.seasonnumber\": \"{seasonNumber}期\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle}が更新されました\",\n  \"components.StatusChecker.appUpdatedDescription\": \"下のボタンをクリックしてアプリをリロードしてください。\",\n  \"components.StatusChecker.reloadApp\": \"{applicationTitle}をリロード\",\n  \"components.StatusChecker.restartRequired\": \"サーバの再起動が必要です\",\n  \"components.StatusChecker.restartRequiredDescription\": \"更新された設定を適用するにはサーバを再起動してください。\",\n  \"components.TitleCard.addToWatchList\": \"ウォッチリストに追加\",\n  \"components.TitleCard.cleardata\": \"データのクリア\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} が見つかりません\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tvdbid\": \"TVDB ID\",\n  \"components.TitleCard.watchlistCancel\": \"<strong>{title}</strong>のウォッチリストがキャンセルされました。\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong>がウォッチリストから削除されました！\",\n  \"components.TitleCard.watchlistError\": \"何か問題が発生しました。もう一度試してください。\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> がウォッチリストに追加されました！\",\n  \"components.TvDetails.Season.noepisodes\": \"エピソードリストは利用できません。\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"シーズンデータの取得中に問題が発生しました。\",\n  \"components.TvDetails.addtowatchlist\": \"ウォッチリストに追加\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# エピソード} other {# エピソード}}\",\n  \"components.TvDetails.episodeRuntime\": \"エピソードの収録時間\",\n  \"components.TvDetails.manageseries\": \"シリーズの管理\",\n  \"components.TvDetails.nextAirDate\": \"次回放送日\",\n  \"components.TvDetails.play\": \"{mediaServerName}で再生\",\n  \"components.TvDetails.play4k\": \"{mediaServerName}で4Kを再生\",\n  \"components.TvDetails.productioncountries\": \"製作 {countryCount, plural, one {国} other {国}}\",\n  \"components.TvDetails.removefromwatchlist\": \"ウォッチリストから削除\",\n  \"components.TvDetails.reportissue\": \"問題を報告する\",\n  \"components.TvDetails.rtaudiencescore\": \"ロッテントマトの視聴者スコア\",\n  \"components.TvDetails.rtcriticsscore\": \"ロッテントマトのトマトメーター\",\n  \"components.TvDetails.seasonnumber\": \"シーズン {seasonNumber}\",\n  \"components.TvDetails.seasonstitle\": \"{seasonCount, plural, one {# シーズン} other {# シーズン}}\",\n  \"components.TvDetails.status4k\": \"4K{status}\",\n  \"components.TvDetails.streamingproviders\": \"現在ストリーミング中\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDBユーザースコア\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong>がウォッチリストから削除されました！\",\n  \"components.TvDetails.watchlistError\": \"何か問題が発生しました。もう一度試してください。\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong>がウォッチリストに追加されました！\",\n  \"components.UserList.accounttype\": \"タイプ\",\n  \"components.UserList.autogeneratepassword\": \"パスワードを自動生成する\",\n  \"components.UserList.autogeneratepasswordTip\": \"サーバが生成したパスワードをユーザーにメールで送信します\",\n  \"components.UserList.bulkedit\": \"一括編集\",\n  \"components.UserList.create\": \"作成\",\n  \"components.UserList.createlocaluser\": \"ローカルユーザーの作成\",\n  \"components.UserList.creating\": \"作成中…\",\n  \"components.UserList.edituser\": \"ユーザー権限の編集\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {ユーザー} other {ユーザー}}のインポートが完了しました！\",\n  \"components.UserList.importfromJellyfin\": \"{mediaServerName} ユーザーのインポート\",\n  \"components.UserList.importfromJellyfinerror\": \"{mediaServerName} ユーザーのインポート中に問題が発生しました。\",\n  \"components.UserList.importfrommediaserver\": \"{mediaServerName} ユーザーのインポート\",\n  \"components.UserList.localLoginDisabled\": \"<strong>ローカルサインインを有効にする</strong>設定は現在無効になっています。\",\n  \"components.UserList.localuser\": \"ローカルユーザー\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName}ユーザー\",\n  \"components.UserList.newJellyfinsigninenabled\": \"<strong>新しい{mediaServerName}へのサインインを有効にする</strong>設定は現在有効です。ライブラリへのアクセス権を持つ{mediaServerName}ユーザーはサインインのためにインポートする必要はありません。\",\n  \"components.UserList.newplexsigninenabled\": \"<strong>新しいPlexサインインを有効にする</strong>設定は現在有効です。ライブラリへのアクセス権を持つPlexユーザーはサインインのためにインポートする必要はありません。\",\n  \"components.UserList.noJellyfinuserstoimport\": \"インポートする{mediaServerName}ユーザーがいません。\",\n  \"components.UserList.nouserstoimport\": \"インポートするPlexユーザーがいません。\",\n  \"components.UserList.owner\": \"所有者\",\n  \"components.UserList.passwordinfodescription\": \"アプリケーションURLを構成しメール通知を有効にしてパスワードの自動生成を許可します。\",\n  \"components.UserList.sortCreated\": \"登録日\",\n  \"components.UserList.sortDisplayName\": \"表示名\",\n  \"components.UserList.sortRequests\": \"リクエスト数\",\n  \"components.UserList.usercreatedfailed\": \"ユーザーの作成中に問題が発生しました。\",\n  \"components.UserList.usercreatedfailedexisting\": \"指定されたメールアドレスはすでに別のユーザーによって使用されています。\",\n  \"components.UserList.usercreatedsuccess\": \"ユーザーが作成されました！\",\n  \"components.UserList.userfail\": \"ユーザー権限の保存中に問題が発生しました。\",\n  \"components.UserList.username\": \"ユーザー名\",\n  \"components.UserList.userssaved\": \"ユーザー権限が保存されました！\",\n  \"components.UserList.validationUsername\": \"ユーザー名を指定してください\",\n  \"components.UserList.validationpasswordminchars\": \"パスワードが短すぎます; 8文字以上にしてください\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"{joindate}に参加しました\",\n  \"components.UserProfile.ProfileHeader.profile\": \"プロフィールを見る\",\n  \"components.UserProfile.ProfileHeader.settings\": \"設定の編集\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ユーザーID: {userid}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"{mediaServerName}の認証情報を入力してアカウントを{applicationName}にリンクします。\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"このアカウントはすでに{applicationName}ユーザーにリンクされています\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"{mediaServerName} に指定の認証情報を使用して接続できませんでした\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"不明なエラーが発生しました\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"パスワード\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"パスワードを入力してください\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"リンク\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"追加中…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"{mediaServerName}アカウントをリンク\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"ユーザー名\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"ユーザー名を指定してください\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"アカウントの種類\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"管理\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"DiscordのユーザーID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"自身のDiscordユーザーアカウントに関連付けられた<FindDiscordIdLink>複数桁のID番号</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"地域を見つける\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"利用可能な地域に応じてコンテンツをフィルタリングする\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"表示名\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"メール\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"グローバル制限を上書きする\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"ローカルユーザー\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName}ユーザー\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"動画リクエストの制限\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"言語を見つける\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"元の言語でコンテンツをフィルタリングする\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"所有者\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plexユーザー\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"映画の自動リクエスト\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"<PlexWatchlistSupportLink>Plexウォッチリスト</PlexWatchlistSupportLink>の映画を自動でリクエスト\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"シリーズの自動リクエスト\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"<PlexWatchlistSupportLink>Plexウォッチリスト</PlexWatchlistSupportLink>のシリーズを自動でリクエスト\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"地域を見つける\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"利用可能な地域に応じてコンテンツをフィルタリングする\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"ロール\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"変更を保存\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"保存中…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"シリーズリクエスト制限\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"ストリーミング地域\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"利用可能な地域別にストリーミングサイトを表示する\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"このメールアドレスは既に使われています！\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"別のユーザーがすでにこのユーザー名を持っています。メールアドレスを設定してください\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"設定が保存されました！\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"ユーザー\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"有効なDiscordユーザーIDを指定してください\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"有効なメールが必要です\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"メールアドレスが必要です\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"リンクされたアカウントを削除できません。\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"不明なエラーが発生しました\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"リンクされたアカウント\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"これらの外部アカウントは{applicationName}アカウントにリンクされています。\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"あなたのアカウントにリンクされている外部アカウントはありません。\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"このユーザーのリンクされたアカウントを変更する権限がありません。\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"このアカウントはすでにPlexユーザーにリンクされています\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Plexに指定の認証情報で接続できませんでした\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"ブラウザ\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"作成された\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"サブスクリプションの削除\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"デバイス\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Webプッシュを無効にする\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Webプッシュを無効にしているときに問題が発生しました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Webプッシュを有効にする\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Webプッシュを有効にしているときに問題が発生しました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"エンジン\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"デバイスの管理\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"表示するWebプッシュサブスクリプションがありません。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"オペレーティングシステム\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"サブスクリプションが削除されました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"ユーザーサブスクリプションの削除中に問題が発生しました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"タイプ\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"不明\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Webプッシュが無効になっています。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Webプッシュが有効になりました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Webプッシュ通知設定の保存に失敗しました。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Webプッシュ通知設定が保存されました！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"デバイスのデフォルト\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ユーザーID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"自分のユーザーアカウントに関連付けられた<FindDiscordIdLink>複数桁のID番号</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"メール\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"通知\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"通知設定\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"PGP公開鍵\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"アクセストークン\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"<PushbulletSettingsLink>アカウント設定</PushbulletSettingsLink>からトークンを作成してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Pushbullet通知設定を保存できませんでした。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet通知設定が保存されました！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"アプリケーションAPIトークン\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>アプリケーションを登録</ApplicationRegistrationLink>して{applicationTitle}で使用してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"ユーザーまたはグループキー\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"30文字の<UsersGroupsLink>ユーザーまたはグループの識別子</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Pushover通知設定を保存できませんでした。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover通知設定が保存されました！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"サイレント送信\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"音を出さずに通知を送信します\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"通知音\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"チャットID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>チャットを開始</TelegramBotLink>し、<GetIdBotLink>@get_id_bot</GetIdBotLink>を追加して<code>/my_id</code>コマンドを実行してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"スレッド/トピック ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"グループチャットでトピックが有効になっている場合ここでスレッド/トピックのIDを指定できます\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"有効なユーザーIDを指定してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"有効なPGP公開キーを指定してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"アクセストークンを指定してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"有効なアプリケーショントークンを指定してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"有効なユーザーまたはグループキーを指定してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"有効なチャットIDを指定してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"スレッド/トピック IDは正の整数にしてください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Webプッシュ\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"パスワードの認証\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"現在のパスワード\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"新しいパスワード\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"このユーザーアカウントには現在パスワードが設定されていません。このアカウントが「ローカルユーザー」としてサインインできるようにするには以下にパスワードを構成します。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"現在あなたのアカウントにはパスワードが設定されていません。メールアドレスを使用して「ローカル ーザー」としてサインインできるようにするには以下にパスワードを構成します。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"このユーザーのパスワードを変更する権限がありません。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"パスワードの保存中に問題が発生しました。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"パスワードの保存中に問題が発生しました。現在のパスワードは正しく入力されましたか？\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"パスワードが保存されました！\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"新しいパスワードを確認してください\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"パスワードは一致する必要があります\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"現在のパスワードを入力してください\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"新しいパスワードを入力してください\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"パスワードが短すぎます。8文字以上にしてください\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"権限\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"権限が保存されました！\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"自分自身の権限を変更することはできません。\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"リンクされたアカウント\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"権限\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"このユーザーの設定を変更する権限がありません。\",\n  \"components.UserProfile.emptywatchlist\": \"<PlexWatchlistSupportLink>Plexウォッチリスト</PlexWatchlistSupportLink>に追加されたメディアはここに表示されます。\",\n  \"components.UserProfile.limit\": \"{remaining} / {limit}\",\n  \"components.UserProfile.localWatchlist\": \"{username}のウォッチリスト\",\n  \"components.UserProfile.movierequests\": \"映画のリクエスト\",\n  \"components.UserProfile.pastdays\": \"{type}（過去 {days} 日間）\",\n  \"components.UserProfile.plexwatchlist\": \"Plexのウォッチリスト\",\n  \"components.UserProfile.recentlywatched\": \"最近見たもの\",\n  \"components.UserProfile.recentrequests\": \"最近のリクエスト\",\n  \"components.UserProfile.requestsperdays\": \"残り {limit}\",\n  \"components.UserProfile.seriesrequest\": \"シリーズリクエスト\",\n  \"components.UserProfile.totalrequests\": \"総リクエスト数\",\n  \"components.UserProfile.unlimited\": \"無制限\",\n  \"i18n.advanced\": \"高度な\",\n  \"i18n.areyousure\": \"本気ですか？\",\n  \"i18n.back\": \"戻る\",\n  \"i18n.completed\": \"完了しました\",\n  \"i18n.deleted\": \"削除されました\",\n  \"i18n.importing\": \"インポート中…\",\n  \"i18n.previous\": \"前\",\n  \"i18n.requesting\": \"リクエスト中…\",\n  \"i18n.resolved\": \"解決済み\",\n  \"i18n.restartRequired\": \"再起動が必要です\",\n  \"i18n.resultsperpage\": \"ページ毎に{pageSize}の結果を表示します\",\n  \"i18n.retrying\": \"再試行中…\",\n  \"i18n.settings\": \"設定\",\n  \"i18n.showingresults\": \"<strong>{from}</strong> から <strong>{to}</strong> までの <strong>{total}</strong>件の結果を表示中\",\n  \"i18n.specials\": \"スペシャル\",\n  \"i18n.tvshow\": \"シリーズ\",\n  \"i18n.usersettings\": \"ユーザー設定\",\n  \"i18n.view\": \"表示\",\n  \"components.Login.title\": \"メールを追加\",\n  \"components.Login.urlBase\": \"URLベース\",\n  \"components.Login.username\": \"ユーザー名\",\n  \"components.Settings.mediaTypeSeries\": \"シリーズ\",\n  \"i18n.canceling\": \"キャンセル中…\",\n  \"i18n.collection\": \"コレクション\",\n  \"i18n.experimental\": \"実験的\",\n  \"i18n.import\": \"インポート\",\n  \"i18n.noresults\": \"結果はありません。\",\n  \"i18n.notrequested\": \"リクエストはありません\",\n  \"components.Settings.SettingsMain.apikey\": \"APIキー\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Plexへの接続に失敗しました。\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex接続が確立されました！\",\n  \"components.AirDateBadge.airedrelative\": \"{relativeTime}に放送\",\n  \"components.AirDateBadge.airsrelative\": \"{relativeTime}に放送予定\",\n  \"components.Login.validationEmailFormat\": \"無効なメール\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"アクセストークン\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"<PushbulletSettingsLink>アカウント設定</PushbulletSettingsLink>からトークンを作成します\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"ログメッセージをクリップボードにコピーしました。\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.apiKey\": \"APIキー\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Seerrについて\",\n  \"components.Settings.SettingsAbout.contribute\": \"貢献する\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Seerr サポート\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"有効な最大TTLを指定してください\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"有効な最小TTLを指定してください\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"アクティブなサブスクリプション\",\n  \"component.BlocklistBlock.blocklistdate\": \"ブロックリストに登録された日付\",\n  \"component.BlocklistBlock.blocklistedby\": \"ブロックリストに登録された\",\n  \"component.BlocklistModal.blocklisting\": \"ブロックリストへの登録\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> はブロックリストに登録されていません。\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"ブロックリストに登録されたメディアを管理します。\",\n  \"components.Blocklist.blocklistdate\": \"日付\",\n  \"components.Blocklist.blocklistedby\": \"{date} 作成者: {user}\",\n  \"components.Blocklist.blocklistsettings\": \"ブロックリストの設定\",\n  \"components.Blocklist.filterBlocklistedTags\": \"ブロックリストに登録されたタグ\",\n  \"components.Blocklist.filterManual\": \"手動\",\n  \"components.Blocklist.mediaName\": \"名前\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb ID\",\n  \"components.Blocklist.mediaType\": \"タイプ\",\n  \"components.Blocklist.showAllBlocklisted\": \"ブロックリストに登録されたメディアをすべて表示\",\n  \"components.PermissionEdit.blocklistedItems\": \"メディアをブロックリストに登録します。\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"メディアをブロックリストに登録する権限を付与します。\",\n  \"components.PermissionEdit.manageblocklist\": \"ブロックリストの管理\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"ブロックリストに登録されたメディアを管理する権限を付与します。\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"ブロックリストに登録されたメディアを表示します。\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"ブロックリストに登録されたメディアを表示する権限を付与します。\",\n  \"components.RequestList.unableToConnect\": \"{services} に接続できません。一部の情報が入手できない場合があります。\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"{services}に接続できません。一部の情報が入手できない場合があります。\",\n  \"components.Layout.Sidebar.blocklist\": \"ブロックリスト\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"DNSルックアップはまだキャッシュされていません。\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"ブロックリストに登録されたタグを処理する\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"タグ付きのコンテンツをブロックリストに登録する\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"タグごとにブロックリストに登録されるコンテンツを制限する\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"「ブロックリストタグの処理」ジョブは各ソートごとにこの数のページをブロックリストに登録します。数値が大きいほど正確なブロックリストが作成されますがより多くのスペースを消費します。\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"「ブロックリストタグの処理」ジョブを使用して、タグ付きのコンテンツをブロックリストに自動的に追加します\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"ブロックリストに登録されたアイテムを非表示にする\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"「ブロックリスト管理」権限を持つすべてのユーザーの検出ページからブロックリストに登録されたアイテムを非表示にする\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"APIリクエストタイムアウト\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"外部サービス（Radarr/Sonarrなど）からの応答を待機する最大時間（秒単位）。タイムアウトなしの場合は0に設定してください。\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"すべての送信HTTP/HTTPSリクエストをプロキシサーバー（ホスト/ポート）経由で送信します。HTTPS、SSL、または証明書の設定は有効になりません。\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"有効なタイムアウト値を指定してください\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"以下にブロックリストタグの設定を貼り付けます。\",\n  \"components.Settings.blocklistedTagImportTitle\": \"ブロックリストに登録されたタグ構成をインポートする\",\n  \"components.Settings.blocklistedTagsText\": \"ブロックリストに登録されたタグ\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"ブロックリストに登録されたタグをクリアしてもよろしいですか？\",\n  \"components.Settings.copyBlocklistedTags\": \"ブロックリストに登録されたタグをクリップボードにコピーしました。\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"コピーするものはありません\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"ブロックリストに登録されたタグ設定をコピーする\",\n  \"components.Settings.importBlocklistedTagsTip\": \"ブロックリストに登録されたタグ構成をインポートする\",\n  \"i18n.addToBlocklist\": \"ブロックリストに追加\",\n  \"i18n.blocklist\": \"ブロックリスト\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong>は既にブロックリストに登録されています。\",\n  \"i18n.blocklistError\": \"何か問題が発生しました。もう一度試してください。\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong>がブロックリストに登録されました。\",\n  \"i18n.blocklisted\": \"ブロックリストに登録されました\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong>がブロックリストから削除されました。\",\n  \"i18n.removefromBlocklist\": \"ブロックリストから削除\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"新シーズンを監視する\",\n  \"components.Discover.timeWindowDay\": \"毎日\",\n  \"components.Discover.timeWindowWeek\": \"毎週\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"優先度\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"優先度を1から5の間で指定してください\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"カスタムヘッダー\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"ヘッダーを追加\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"AuthorizationヘッダーとカスタムAuthorizationヘッダーの両方を使用することはできません。いずれか一方を削除してください。\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"すべてのヘッダーには名前と値の両方が必要です\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"ヘッダー名\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"削除\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Webhookリクエストに含めるカスタムHTTPヘッダーを追加する\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"ヘッダーの値\"\n}\n"
  },
  {
    "path": "src/i18n/locale/ko.json",
    "content": "{\n  \"components.AirDateBadge.airedrelative\": \"{relativeTime} 방영됨\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code> 볼륨이 정상적으로 마운트되지 않았습니다. 컨테이너가 중지되거나 다시 시작되면 모든 데이터가 삭제됩니다.\",\n  \"components.CollectionDetails.overview\": \"정보\",\n  \"components.CollectionDetails.requestcollection\": \"컬렉션 요청\",\n  \"components.AirDateBadge.airsrelative\": \"{relativeTime} 방영 예정\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} 영화\",\n  \"components.CollectionDetails.requestcollection4k\": \"4K로 컬렉션 요청\",\n  \"components.Discover.CreateSlider.addSlider\": \"슬라이더 추가\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"사용자 지정 슬라이더 생성\",\n  \"components.Discover.CreateSlider.addfail\": \"새 슬라이더를 생성하는 데 실패했습니다.\",\n  \"components.Discover.CreateSlider.editSlider\": \"슬라이더 수정\",\n  \"components.Discover.CreateSlider.editfail\": \"슬라이더 수정에 실패했습니다.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"새 슬라이더를 만들고 검색 사용자 지정 설정을 저장했습니다.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"슬라이더를 수정하고 검색 사용자 지정 설정을 저장했습니다.\",\n  \"components.Discover.CreateSlider.needresults\": \"1개 이상의 검색 결과가 필요합니다.\",\n  \"components.Discover.CreateSlider.nooptions\": \"결과가 없습니다.\",\n  \"components.Discover.CreateSlider.searchGenres\": \"장르 검색…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"검색어…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"스튜디오 검색…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"슬라이더 이름\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} 영화\",\n  \"components.Discover.upcomingmovies\": \"개봉 예정작\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"영화 및 시리즈 검색\",\n  \"components.PermissionEdit.request4kMovies\": \"4K 영화 요청\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"4K 영화를 요청할 수 있는 권한을 부여합니다.\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"TMDB 키워드 ID 입력\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"TMDB 장르 ID 입력\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"검색어 입력\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"TMDB 스튜디오 ID 입력\",\n  \"components.Discover.CreateSlider.starttyping\": \"검색어를 입력하세요.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"값을 입력해야 합니다.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"이름을 입력해야 합니다.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} 영화\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} 영화\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"영화\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"인기 오름차순\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"인기 내림차순\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"개봉일 오래된순\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"개봉일 최신순\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"제목 (A-Z) 오름차순\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} 시리즈\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"제목 (Z-A) 내림차순\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"슬라이더를 삭제하지 못했습니다.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"슬라이더를 삭제했습니다.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"표시 여부\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"삭제\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB 점수 오름차순\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB 점수 내림차순\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} 영화\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"첫 방영일 오래된순\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"첫 방영일 최신순\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"인기 오름차순\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"인기 내림차순\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"제목 (A-Z) 오름차순\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"제목 (Z-A) 내림차순\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"당신의 Plex 관심 목록\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex 시청 목록\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"선택한 필터 해제\",\n  \"components.Discover.FilterSlideover.filters\": \"필터\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"첫 방영일\",\n  \"components.Discover.FilterSlideover.from\": \"부터\",\n  \"components.Discover.FilterSlideover.genres\": \"장르\",\n  \"components.Discover.FilterSlideover.keywords\": \"키워드\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"원작 언어\",\n  \"components.Discover.FilterSlideover.ratingText\": \"{minValue}~{maxValue} 사이의 점수\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"공개일\",\n  \"components.Discover.FilterSlideover.runtime\": \"상영 시간\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} 분 상영 시간\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"스트리밍 서비스\",\n  \"components.Discover.FilterSlideover.studio\": \"스튜디오\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB 회원 점수\",\n  \"components.Discover.FilterSlideover.to\": \"까지\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"영화 장르\",\n  \"components.Discover.NetworkSlider.networks\": \"방송사\",\n  \"components.Discover.networks\": \"방송사\",\n  \"components.Discover.popularmovies\": \"인기 영화\",\n  \"components.Discover.tmdbnetwork\": \"TMDB 방송사\",\n  \"components.Discover.upcoming\": \"개봉 예정작\",\n  \"components.Layout.Sidebar.browsemovies\": \"영화\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"4K 영화 요청의 자동 승인 권한을 부여합니다.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"영화 자동 수락\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"비-4K 영화 요청의 자동 승인 권한을 부여합니다.\",\n  \"components.PermissionEdit.autorequestMovies\": \"영화 자동 요청\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Plex Watchlist를 통해 비-4K 영화를 자동으로 요청할 수 있는 권한을 부여합니다.\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"비-4K 영화를 요청할 수 있는 권한을 부여합니다.\",\n  \"components.PermissionEdit.requestMovies\": \"영화 요청\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{영화} 당 {quotaDays} {일}</quotaUnits>\",\n  \"components.RequestModal.selectmovies\": \"영화 선택\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"영화 자동 요청\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"<PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>의 영화를 자동으로 요청합니다\",\n  \"i18n.movies\": \"영화\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"TMDB 방송사 ID 입력\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"4K 영화 자동 수락\",\n  \"components.Discover.DiscoverTv.discovertv\": \"시리즈\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB 점수 오름차순\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB 점수 내림차순\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} 시리즈\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} 시리즈\",\n  \"components.IssueDetails.allepisodes\": \"모든 에피소드\",\n  \"components.IssueDetails.play4konplex\": \"Plex에서 4K로 재생\",\n  \"components.IssueDetails.playonplex\": \"Plex에서 재생\",\n  \"components.IssueModal.CreateIssueModal.season\": \"시즌 {seasonNumber}\",\n  \"components.Layout.Sidebar.browsetv\": \"시리즈\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"시리즈 요청\",\n  \"components.Login.password\": \"비밀번호\",\n  \"components.Layout.UserDropdown.settings\": \"설정\",\n  \"components.Discover.createnewslider\": \"새 슬라이더 생성\",\n  \"components.Layout.UserDropdown.requests\": \"요청\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} 시리즈\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"영화 장르\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"plex 관심 목록\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"최근에 추가됨\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"시리즈 장르\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"시리즈 장르\",\n  \"components.Discover.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex 관심 목록</PlexWatchlistSupportLink>에 추가된 미디어가 여기에 표시됩니다.\",\n  \"components.Discover.moviegenres\": \"영화 장르\",\n  \"components.Discover.plexwatchlist\": \"Plex 관심 목록\",\n  \"components.Discover.populartv\": \"인기 시리즈\",\n  \"components.Discover.recentlyAdded\": \"최근에 추가됨\",\n  \"components.Discover.recentrequests\": \"최근 요청\",\n  \"components.Discover.tmdbtvgenre\": \"TDMB 시리즈 장르\",\n  \"components.Discover.tmdbtvkeyword\": \"TDMB 시리즈 키워드\",\n  \"components.Discover.tvgenres\": \"시리즈 장르\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: 시즌 {seasonNumber} 에피소드 {episodeNumber}\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"메시지를 입력해야 합니다\",\n  \"components.IssueDetails.episode\": \"에피소드 {episodeNumber}\",\n  \"components.IssueDetails.season\": \"시즌 {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"에피소드 {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"무슨 문제인가요?\",\n  \"components.IssueModal.issueSubtitles\": \"자막\",\n  \"components.Layout.Sidebar.requests\": \"요청\",\n  \"components.Layout.Sidebar.settings\": \"설정\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"영화 요청\",\n  \"components.Login.email\": \"이메일 주소\",\n  \"components.Login.forgotpassword\": \"비밀번호를 잊으셨나요?\",\n  \"components.Login.signinwithoverseerr\": \"{applicationTitle} 계정을 사용하세요\",\n  \"components.Login.signinwithplex\": \"Plex 계정을 사용하세요\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"고급\",\n  \"components.Login.validationemailrequired\": \"유효한 이메일 주소를 입력해야 합니다\",\n  \"components.Login.validationpasswordrequired\": \"비밀번호를 입력해야 합니다\",\n  \"components.ManageSlideOver.downloadstatus\": \"다운로드\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB 사용자 투표 수\",\n  \"components.Discover.FilterSlideover.voteCount\": \"{minValue}와 {maxValue} 사이의 투표 수\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB 영화 장르\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB 영화 키워드\",\n  \"components.Discover.upcomingtv\": \"다음 시리즈\",\n  \"components.Discover.updatefailed\": \"디스커버 사용자 지정 설정을 업데이트하는 데 문제가 발생했습니다.\",\n  \"components.DownloadBlock.estimatedtime\": \"예상 {time}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"이 댓글을 삭제하시겠습니까?\",\n  \"components.IssueDetails.IssueDescription.description\": \"설명\",\n  \"components.IssueDetails.IssueDescription.edit\": \"설명 수정\",\n  \"components.IssueDetails.deleteissueconfirm\": \"이 이슈를 삭제하시겠습니까?\",\n  \"components.IssueDetails.issuepagetitle\": \"이슈\",\n  \"components.IssueDetails.unknownissuetype\": \"알 수 없음\",\n  \"components.IssueList.IssueItem.issuestatus\": \"상태\",\n  \"components.IssueList.IssueItem.issuetype\": \"유형\",\n  \"components.IssueList.IssueItem.opened\": \"열림\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{user}의 {date}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"알 수 없음\",\n  \"components.IssueList.IssueItem.viewissue\": \"이슈 보기\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {에피소드} other {에피소드}}\",\n  \"components.IssueList.sortModified\": \"마지막 수정\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"모든 에피소드\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"영향을 받는 에피소드\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"영향을 받는 시즌\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"발생한 이슈에 대한 자세한 설명을 작성해주세요.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"이슈 보고\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"이슈 보기\",\n  \"components.Layout.Sidebar.dashboard\": \"디스커버\",\n  \"components.Layout.UserDropdown.signout\": \"로그아웃\",\n  \"components.Login.signin\": \"로그인\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"데이터 지우기\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"모든 시즌을 사용 가능하게 표시\",\n  \"components.Layout.VersionStatus.outofdate\": \"오래됨\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {커밋} other {커밋}} 이후\",\n  \"components.ManageSlideOver.markavailable\": \"사용 가능하게 표시\",\n  \"components.ManageSlideOver.playedby\": \"플레이한 사용자\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"자세히 보기\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"전체 출연진\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"전체 제작진\",\n  \"components.MovieDetails.markavailable\": \"사용 가능한 것으로 표시\",\n  \"components.MovieDetails.physicalrelease\": \"실물 개봉일\",\n  \"components.MovieDetails.showless\": \"간단히 보기\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB 사용자 점수\",\n  \"components.MovieDetails.viewfullcrew\": \"전체 제작진 보기\",\n  \"components.MovieDetails.watchtrailer\": \"예고편 보기\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"다른 사용자가 이슈에 댓글을 남길 때 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"다른 사용자가 이슈를 다시 열 때 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"다른 사용자가 이슈를 해결했을 때 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"이슈 댓글\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"이슈가 다시 열리면 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Plex 시청 목록에 있는 항목에 대해 새 미디어 요청이 자동으로 제출될 때 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"미디어 요청을 사용할 수 있게 되면 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"요청 처리 실패\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"사용자가 승인이 필요한 새 미디어 요청을 제출할 때 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"알림 유형\",\n  \"components.PermissionEdit.admin\": \"관리자\",\n  \"components.PermissionEdit.autoapprove4k\": \"4K 자동 승인\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"모든 4K 미디어 요청에 대해 자동 승인을 부여합니다.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"4K 시리즈 요청에 대한 자동 승인을 부여합니다.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"4K가 아닌 모든 미디어 요청에 대해 자동 승인을 부여합니다.\",\n  \"components.PermissionEdit.autorequestSeries\": \"자동 요청 시리즈\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Plex 시청 목록를 통해 비 4K 시리즈에 대한 요청을 자동으로 제출할 수 있는 권한을 부여합니다.\",\n  \"components.PermissionEdit.createissuesDescription\": \"미디어 이슈를 보고할 권한을 부여합니다.\",\n  \"components.PermissionEdit.manageissues\": \"이슈 관리\",\n  \"components.PermissionEdit.request4kTv\": \"4K 시리즈 요청\",\n  \"components.PermissionEdit.requestTv\": \"시리즈 요청\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.RequestBlock.delete\": \"삭제 요청\",\n  \"components.RequestBlock.requestedby\": \"요청자\",\n  \"components.RequestButton.viewrequest4k\": \"4K 요청 보기\",\n  \"components.RequestCard.approverequest\": \"요청 승인\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {영화} other {영화}}\",\n  \"components.RequestCard.cancelrequest\": \"요청 취소\",\n  \"components.RequestCard.declinerequest\": \"요청 거부\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} 찾을 수 없음\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {시즌} other {시즌}}\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} 찾을 수 없음\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"알 수 없는 제목\",\n  \"components.RequestList.requests\": \"요청\",\n  \"components.RequestList.showallrequests\": \"모든 요청 표시\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"루트 폴더\",\n  \"components.RequestModal.QuotaDisplay.season\": \"시즌\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {시즌} other {시즌}}\",\n  \"components.RequestModal.alreadyrequested\": \"이미 요청됨\",\n  \"components.RequestModal.approve\": \"요청 승인\",\n  \"components.RequestModal.pendingapproval\": \"당신의 요청이 승인 대기 중입니다.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"4K로 컬렉션 요청\",\n  \"components.RequestModal.requestcollectiontitle\": \"컬렉션 요청\",\n  \"components.RequestModal.requestfrom\": \"{username}님의 요청이 승인 대기 중입니다.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"4K 영화 요청\",\n  \"components.RequestModal.requestmovies4k\": \"4K에서 {count} {count, plural, one {영화} other {영화}} 요청\",\n  \"components.RequestModal.requestmovietitle\": \"영화 요청\",\n  \"components.RequestModal.requestseasons\": \"요청 {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}\",\n  \"components.ResetPassword.passwordreset\": \"비밀번호 재설정\",\n  \"components.ResetPassword.validationpasswordmatch\": \"비밀번호가 일치해야 합니다\",\n  \"components.Selector.searchGenres\": \"장르 선택…\",\n  \"components.Selector.searchKeywords\": \"키워드 검색…\",\n  \"components.ResetPassword.validationemailrequired\": \"유효한 이메일 주소를 입력해야 합니다\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"적어도 하나 이상의 알림 유형을 선택해야 합니다\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify 테스트 알림을 보내지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"유효한 URL을 입력해야 합니다\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"에이전트 활성화\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Slack 알림 설정을 저장하지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"유효한 애플리케이션 토큰을 입력해야 합니다\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack 테스트 알림을 보내지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Slack 테스트 알림을 보내는 중…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"슬랙 테스트 알림이 전송되었습니다!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"웹훅 테스트 알림을 보내지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"웹훅 알림 설정을 저장하지 못했습니다.\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"봇 아바타 URL\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"이메일 테스트 알림을 보내지 못했습니다.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"이메일 테스트 알림을 보내는 중…\",\n  \"components.Settings.Notifications.validationTypes\": \"적어도 하나 이상의 알림 유형을 선택해야 합니다\",\n  \"components.Settings.Notifications.webhookUrl\": \"웹훅 URL\",\n  \"components.Settings.RadarrModal.add\": \"서버 추가\",\n  \"components.Settings.RadarrModal.announced\": \"공개됨\",\n  \"components.Settings.RadarrModal.apiKey\": \"API 키\",\n  \"components.Settings.RadarrModal.baseUrl\": \"기본 URL\",\n  \"components.Settings.Notifications.validationUrl\": \"유효한 URL을 입력해야 합니다\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"새 4K Radarr 서버 추가\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"4K Radarr 서버 수정\",\n  \"components.Settings.RadarrModal.enableSearch\": \"자동 검색 활성화\",\n  \"components.Settings.RadarrModal.externalUrl\": \"외부접속 URL\",\n  \"components.Settings.RadarrModal.hostname\": \"호스트 네임 또는 IP 주소\",\n  \"components.Settings.RadarrModal.inCinemas\": \"영화관에서\",\n  \"components.Settings.RadarrModal.loadingTags\": \"태그 불러오는 중…\",\n  \"components.Settings.RadarrModal.notagoptions\": \"태그가 없습니다.\",\n  \"components.Settings.RadarrModal.port\": \"포트\",\n  \"components.Settings.RadarrModal.released\": \"출시됨\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"루트 폴더 선택\",\n  \"components.Settings.RadarrModal.ssl\": \"SSL 사용\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"스캔 활성화\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"품질 프로필 불러오는 중…\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"태그를 불러오기 위한 연결 테스트\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL 기반에는 선행 슬래시가 있어야 합니다\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL 기반은 슬래시로 끝나지 않아야 합니다\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"변경 로그 보기\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"GitHub에서 보기\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"조회 수\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"작업 및 캐시\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname}이(가) 시작되었습니다.\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"알 수 없는 작업\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"재개\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"새 API 키를 생성하는 동안 문제가 발생했습니다.\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"기본 권한\",\n  \"components.Settings.SonarrModal.port\": \"포트\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"애니메이션 품질 프로필\",\n  \"components.Settings.menuServices\": \"서비스\",\n  \"components.Settings.toastPlexConnecting\": \"Plex에 연결 시도 중…\",\n  \"components.TvDetails.overview\": \"정보\",\n  \"components.TvDetails.overviewunavailable\": \"정보를 볼 수 없습니다.\",\n  \"components.TvDetails.rtaudiencescore\": \"Rotten Tomatoes 시청자 점수\",\n  \"components.UserProfile.ProfileHeader.profile\": \"프로필 보기\",\n  \"components.UserProfile.ProfileHeader.userid\": \"사용자 ID: {userid}\",\n  \"components.UserProfile.ProfileHeader.settings\": \"설정 수정\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"관리자\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"표시 언어\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"디스코드 사용자 ID\",\n  \"i18n.partiallyavailable\": \"일부 사용 가능\",\n  \"pages.pagenotfound\": \"페이지를 찾을 수 없음\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"요청자의 사용자 ID 및 표시 이름으로 추가 태그를 자동으로 추가합니다\",\n  \"components.Settings.RadarrModal.tagRequests\": \"태그 요청\",\n  \"components.Settings.RadarrModal.tags\": \"태그\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"루트 폴더를 불러오기 위한 연결 테스트\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"품질 프로필을 불러오기 위한 연결 테스트\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Radarr에 연결하지 못했습니다.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr 연결이 성공적으로 설정되었습니다!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"API 키를 입력해야 합니다\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"유효한 URL을 입력해야 합니다\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"품질 프로필을 선택해야 합니다\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"현재\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"최신\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"현재 출시 데이터를 사용할 수 없습니다.\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"데이터 디렉토리\",\n  \"components.Settings.SettingsAbout.documentation\": \"문서\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"지원 받기\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"당신은 <code>개발</code>에 기여하거나 최신 테스트를 지원하는 사람들에게만 권장되는 Overserr 분기를 실행하고 있습니다.\",\n  \"components.Settings.SettingsAbout.timezone\": \"시간대\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"사용가능한 미디어 동기화\",\n  \"components.Settings.SettingsJobsCache.cache\": \"캐시\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr는 외부 API 엔드포인트에 대한 요청을 캐시하여 성능을 최적화하고 불필요한 API 호출을 방지합니다.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} 캐시가 플러시되었습니다.\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"전체 키\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"키 크기\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"작업 취소\",\n  \"components.Settings.SettingsJobsCache.command\": \"명령\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"다운로드 동기화\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"작업 수정\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"현재 주파수\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"새 주파수\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"매 {jobScheduleSeconds, plural, one {초} other {{jobScheduleSeconds} 초}}\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"이미지 캐시\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"설정에서 활성화하면 Seerr는 미리 구성된 외부 소스에서 이미지를 프록시하고 캐시합니다. 캐시된 이미지는 구성 폴더에 저장됩니다. <code>{appDataPath}/cache/images</code> 에서 파일을 찾을 수 있습니다.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"작업을 저장하는 동안 문제가 발생했습니다.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"작업이 성공적으로 수정되었습니다!\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"작업\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr는 특정 유지 관리 작업을 정기적으로 예약된 작업으로 수행하지만 아래에서 수동으로 트리거할 수도 있습니다. 작업을 수동으로 실행해도 일정이 변경되지는 않습니다.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"유형\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plex 전체 라이브러리 스캔\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plex 최근 추가 스캔\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex 시청 목록 동기화\",\n  \"components.Settings.SettingsJobsCache.process\": \"프로세스\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr 스캔\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"지금 실행\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr 스캔\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"로그 메시지를 클립보드에 복사했습니다.\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"클립보드에 복사\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"디버그\",\n  \"components.Settings.SettingsLogs.filterError\": \"오류\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"경고\",\n  \"components.Settings.SettingsLogs.label\": \"레이블\",\n  \"components.Settings.SettingsLogs.level\": \"심각도\",\n  \"components.Settings.SettingsLogs.logDetails\": \"로그 정보\",\n  \"components.Settings.SettingsLogs.logs\": \"로그\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"로그는 <code>stdout</code> 또는 <code>{appDataPath}/logs/seerr.log</code> 통해 직접 볼 수도 있습니다.\",\n  \"components.Settings.SettingsLogs.showall\": \"전체 로그 보기\",\n  \"components.Settings.SettingsMain.general\": \"일반\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"유효한 URL을 입력해야 합니다\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL은 슬래시로 끝나서는 안 됩니다\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"새 사용자에게 할당된 초기 권한\",\n  \"components.Settings.SettingsUsers.localLogin\": \"로컬 로그인 활성화\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"새 Plex 로그인 활성화\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Plex 사용자를 미리 불러오지 않았어도 로그인하도록 허용\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"설정을 저장하는 동안 문제가 발생했습니다.\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"전역 시리즈 요청 제한\",\n  \"components.Settings.SettingsUsers.userSettings\": \"사용자 설정\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"전역 및 기본 사용자 설정을 구성합니다.\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"애니메이션 루트 폴더\",\n  \"components.Settings.SonarrModal.createsonarr\": \"새 Sonarr 서버 추가\",\n  \"components.Settings.SonarrModal.default4kserver\": \"기본 4K 서버\",\n  \"components.Settings.SonarrModal.enableSearch\": \"자동 검색 활성화\",\n  \"components.Settings.SonarrModal.externalUrl\": \"외부접속 URL\",\n  \"components.Settings.SonarrModal.languageprofile\": \"언어 프로필\",\n  \"components.Settings.SonarrModal.loadingTags\": \"태그 불러오는 중…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"품질 프로필 불러오는 중…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"루트 폴더 불러오는 중…\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"품질 프로필\",\n  \"components.Settings.SonarrModal.rootfolder\": \"루트 폴더\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"시즌 폴더\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"언어 프로필 선택\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"루트 폴더 선택\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"품질 프로필 선택\",\n  \"components.Settings.SonarrModal.server4k\": \"4K 서버\",\n  \"components.Settings.SonarrModal.servername\": \"서버 이름\",\n  \"components.Settings.SonarrModal.tagRequests\": \"태그 요청\",\n  \"components.Settings.SonarrModal.ssl\": \"SSL 사용\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"요청자의 사용자 ID 및 표시 이름이 포함된 추가 태그를 자동으로 추가합니다\",\n  \"components.Settings.SonarrModal.tags\": \"태그\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"루트 폴더를 불러오기 위한 연결 테스트\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"언어 프로필을 불러오기 위한 연결 테스트\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"품질 프로필을 불러오기 위한 연결 테스트\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"API 키를 입력해야 합니다\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"유효한 URL을 입력해야 합니다\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"기본 URL은 슬래시로 끝나지 않아야 합니다\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL은 슬래시로 끝나서는 안 됩니다\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"유효한 호스트 네임 또는 IP 주소를 입력해야 합니다\",\n  \"components.Settings.addsonarr\": \"Sonarr 서버 추가\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"루트 폴더를 선택해야 합니다\",\n  \"components.Settings.advancedTooltip\": \"이 설정을 잘못 구성하면 기능이 제대로 작동하지 않을 수 있습니다\",\n  \"components.Settings.cancelscan\": \"스캔 취소\",\n  \"components.Settings.currentlibrary\": \"현재 라이브러리: {name}\",\n  \"components.Settings.default4k\": \"기본 4K\",\n  \"components.Settings.deleteServer\": \"{serverType} 서버 삭제\",\n  \"components.Settings.externalUrl\": \"외부접속 URL\",\n  \"components.Settings.hostname\": \"호스트 네임 또는 IP 주소\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.manualscan\": \"수동으로 라이브러리 스캔\",\n  \"components.Settings.mediaTypeMovie\": \"영화\",\n  \"components.Settings.manualscanDescription\": \"일반적으로 이는 24시간에 한 번 실행됩니다. Seerr는 Plex 서버의 최근 추가 항목을 더 적극적으로 확인합니다. 만약 Plex를 처음 구성하는 경우, 한번은 전체 수동 라이브러리 스캔을 권장합니다!\",\n  \"components.Settings.mediaTypeSeries\": \"시리즈\",\n  \"components.Settings.menuAbout\": \"정보\",\n  \"components.Settings.menuGeneralSettings\": \"일반\",\n  \"components.Settings.menuJobs\": \"작업 및 캐시\",\n  \"components.Settings.menuLogs\": \"로그\",\n  \"components.Settings.menuNotifications\": \"알림\",\n  \"components.Settings.menuUsers\": \"사용자\",\n  \"components.Settings.noDefaultNon4kServer\": \"비-4K 및 4K 콘텐츠를 전부 처리하는 유일한 {serverType} 서버가 있는 경우(또는 4K 콘텐츠만 다운로드하는 경우), {serverType} 서버는 4K 서버로 지정되어서는 <strong>안됩니다</strong>.\",\n  \"components.Settings.noDefaultServer\": \"{mediaType} 요청을 처리하기 위해서는 적어도 하나 이상의 {serverType} 서버를 기본 설정해야 합니다.\",\n  \"components.Settings.notifications\": \"알림\",\n  \"components.Settings.plexlibrariesDescription\": \"Seerr에서 타이틀을 스캔하는 라이브러리입니다. Plex 연결 설정을 설정하고 저장한 후, 라이브러리가 표시되지 않는 경우 아래 버튼을 클릭하세요.\",\n  \"components.Settings.port\": \"포트\",\n  \"components.Settings.radarrsettings\": \"Radarr 설정\",\n  \"components.Settings.restartrequiredTooltip\": \"이 변경된 설정이 적용되려면 Seerr를 재시작해야 합니다\",\n  \"components.Settings.serverRemote\": \"원격\",\n  \"components.Settings.serverSecure\": \"보안\",\n  \"components.Settings.serverpreset\": \"서버\",\n  \"components.Settings.serverpresetLoad\": \"사용 가능한 서버를 불러오려면 버튼을 눌러 주세요\",\n  \"components.Settings.serverpresetManualMessage\": \"수동 구성\",\n  \"components.Settings.serverpresetRefreshing\": \"서버 검색 중…\",\n  \"components.Settings.tautulliApiKey\": \"API 키\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Plex에 연결하지 못했습니다.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex 연결이 성공적으로 설정되었습니다!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Plex 서버 목록을 검색하지 못했습니다.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Plex 서버 목록을 성공적으로 검색했습니다!\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Tautulli 설정을 저장하는 동안 문제가 발생했습니다.\",\n  \"components.Settings.validationHostnameRequired\": \"유효한 호스트 네임 또는 IP 주소를 입력해야 합니다\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"기본 URL은 슬래시로 끝나서는 안 됩니다\",\n  \"components.Settings.validationUrlTrailingSlash\": \"기본 URL은 슬래시로 끝나서는 안 됩니다\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>웹 앱</WebAppLink> URL\",\n  \"components.Settings.webhook\": \"웹훅\",\n  \"components.Settings.webpush\": \"웹 푸시\",\n  \"components.Setup.configureservices\": \"서비스 구성\",\n  \"components.Setup.continue\": \"계속\",\n  \"components.Setup.finish\": \"설정 완료\",\n  \"components.Setup.finishing\": \"마무리하는 중…\",\n  \"components.Setup.signinMessage\": \"Plex 계정으로 로그인하세요\",\n  \"components.StatusBadge.playonplex\": \"Plex에서 재생\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} 수정됨\",\n  \"components.StatusChecker.appUpdatedDescription\": \"애플리케이션을 다시 로드하려면 아래 버튼을 클릭해주세요.\",\n  \"components.StatusChecker.reloadApp\": \"{applicationTitle} 새로고침\",\n  \"components.TitleCard.cleardata\": \"데이터 비우기\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} 찾을 수 없음\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TvDetails.Season.noepisodes\": \"에피소드 목록을 사용할 수 없습니다.\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"전체 시리즈 출연진\",\n  \"components.TvDetails.anime\": \"애니메이션\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"전체 시리즈 제작진\",\n  \"components.TvDetails.episodeRuntime\": \"에피소드 런타임\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# 에피소드} other {# 에피소드}}\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} 분\",\n  \"components.TvDetails.manageseries\": \"시리즈 관리\",\n  \"components.TvDetails.originallanguage\": \"원작 언어\",\n  \"components.TvDetails.originaltitle\": \"원작명\",\n  \"components.TvDetails.nextAirDate\": \"다음 방영일\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {방송사} other {방송사}}\",\n  \"components.TvDetails.recommendations\": \"추천\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes 토마토미터\",\n  \"components.TvDetails.seasonnumber\": \"시즌 {seasonNumber}\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# 시즌} other {# 시즌}}\",\n  \"components.TvDetails.showtype\": \"시리즈 유형\",\n  \"components.TvDetails.similar\": \"유사한 시리즈\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.streamingproviders\": \"현재 스트리밍 중\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB 사용자 점수\",\n  \"components.TvDetails.seasonstitle\": \"시즌\",\n  \"components.TvDetails.viewfullcrew\": \"전체 제작진 보기\",\n  \"components.TvDetails.watchtrailer\": \"예고편 보기\",\n  \"components.UserList.accounttype\": \"유형\",\n  \"components.UserList.autogeneratepassword\": \"비밀번호 자동 생성\",\n  \"components.UserList.bulkedit\": \"일괄 수정\",\n  \"components.UserList.create\": \"만들기\",\n  \"components.UserList.created\": \"가입됨\",\n  \"components.UserList.createlocaluser\": \"로컬 사용자 생성\",\n  \"components.UserList.edituser\": \"사용자 권한 수정\",\n  \"components.UserList.email\": \"이메일 주소\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {user} other {users}}를 성공적으로 불러왔습니다!\",\n  \"components.UserList.importfromplex\": \"Plex 사용자 불러오기\",\n  \"components.UserList.importfromplexerror\": \"Plex 사용자를 불러오는 동안 문제가 발생했습니다.\",\n  \"components.UserList.localLoginDisabled\": \"<strong>로컬 로그인 활성화</strong> 설정이 현재 비활성화되어 있습니다.\",\n  \"components.UserList.localuser\": \"로컬 사용자\",\n  \"components.UserList.nouserstoimport\": \"불러올 Plex 사용자가 없습니다.\",\n  \"components.UserList.sortDisplayName\": \"표시 이름\",\n  \"components.UserList.sortCreated\": \"가입 일자\",\n  \"components.UserList.sortRequests\": \"요청 수\",\n  \"components.UserList.totalrequests\": \"요청\",\n  \"components.UserList.usercreatedfailed\": \"사용자를 생성하는 동안 문제가 발생했습니다.\",\n  \"components.UserList.usercreatedfailedexisting\": \"입력된 이메일 주소는 이미 다른 사용자가 사용 중입니다.\",\n  \"components.UserList.usercreatedsuccess\": \"사용자가 성공적으로 생성되었습니다!\",\n  \"components.UserList.userdeleteerror\": \"사용자를 삭제하는 동안 문제가 발생했습니다.\",\n  \"components.UserList.userfail\": \"사용자 권한을 저장하는 동안 문제가 발생했습니다.\",\n  \"components.UserList.userlist\": \"사용자 목록\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"{joindate}에 가입함\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"계정 유형\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"자동으로 영화 요청 <PlexWatchlistSupportLink>Plex 시청 목록</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"원작 언어로 콘텐츠 필터링\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"디스커버 지역\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"자동으로 시리즈 요청 <PlexWatchlistSupportLink>Plex 시청 목록</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"역할\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"사용자\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"이메일 알림 설정을 저장하지 못했습니다.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"알림\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"알림 설정\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"PGP 공개 키\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"다음을 사용하여 이메일 메시지 암호화 <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"사용자의 토큰 생성 <PushbulletSettingsLink>계정 설정</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Pushbullet 알림 설정을 저장하지 못했습니다.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"사용자 또는 그룹 키\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"조용히 전송\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"소리 없이 알림 보내기\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"유효한 사용자 ID를 입력해야 합니다\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"암호 확인\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"현재 암호\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"암호를 저장하는 동안 문제가 발생했습니다.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"비밀번호를 저장하는 동안 문제가 발생했습니다. 현재 비밀번호를 올바르게 입력하셨습니까?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"암호가 일치해야 합니다\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"비밀번호가 너무 짧습니다. 최소 8자리 이상이어야 합니다\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"설정을 저장하는 동안 문제가 발생했습니다.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"권한이 성공적으로 저장되었습니다!\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"일반\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"알림\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"권한\",\n  \"components.UserProfile.pastdays\": \"{type} (지난 {days} 일)\",\n  \"components.UserProfile.recentlywatched\": \"최근에 본 영화\",\n  \"components.UserProfile.seriesrequest\": \"시리즈 요청\",\n  \"components.UserProfile.totalrequests\": \"총 요청 수\",\n  \"i18n.all\": \"전체\",\n  \"i18n.approve\": \"승인\",\n  \"i18n.approved\": \"승인됨\",\n  \"i18n.available\": \"사용 가능\",\n  \"i18n.back\": \"뒤로\",\n  \"i18n.cancel\": \"취소\",\n  \"i18n.canceling\": \"취소하는 중…\",\n  \"i18n.close\": \"닫기\",\n  \"i18n.deleting\": \"삭제 중…\",\n  \"i18n.import\": \"불러오기\",\n  \"i18n.importing\": \"불러오는 중…\",\n  \"i18n.loading\": \"불러오는 중…\",\n  \"i18n.movie\": \"영화\",\n  \"i18n.pending\": \"보류 중\",\n  \"i18n.previous\": \"이전\",\n  \"i18n.requested\": \"요청됨\",\n  \"i18n.requesting\": \"요청 중…\",\n  \"i18n.resolved\": \"해결됨\",\n  \"i18n.restartRequired\": \"다시 시작 필요\",\n  \"i18n.resultsperpage\": \"페이지당 {pageSize}개의 결과 표시\",\n  \"i18n.retry\": \"다시 시도\",\n  \"i18n.retrying\": \"다시 시도 중…\",\n  \"i18n.save\": \"변경 사항 저장\",\n  \"i18n.saving\": \"저장 중…\",\n  \"i18n.settings\": \"설정\",\n  \"i18n.showingresults\": \"<strong>{from}</strong>부터 <strong>{to}</strong>까지의 결과 중 <strong>{total}</strong>개를 표시합니다\",\n  \"i18n.status\": \"상태\",\n  \"i18n.test\": \"테스트\",\n  \"i18n.testing\": \"테스트 중…\",\n  \"i18n.tvshow\": \"시리즈\",\n  \"i18n.tvshows\": \"시리즈\",\n  \"i18n.usersettings\": \"사용자 설정\",\n  \"i18n.view\": \"보기\",\n  \"pages.internalservererror\": \"내부 서버 오류\",\n  \"pages.oops\": \"죄송합니다\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB 영화 스트리밍 서비스\",\n  \"components.IssueDetails.problemepisode\": \"영향을 받는 에피소드\",\n  \"components.IssueDetails.reopenissue\": \"이슈 다시 열기\",\n  \"components.IssueDetails.openinarr\": \"{arr}에서 열기\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {시즌} other {시즌}}\",\n  \"components.IssueList.sortAdded\": \"가장 최근\",\n  \"components.IssueList.issues\": \"이슈\",\n  \"components.IssueList.showallissues\": \"모든 이슈 표시\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"이슈를 제출하는 동안에 문제가 발생했습니다.\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"표시 언어\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr 개발\",\n  \"components.ManageSlideOver.tvshow\": \"시리즈\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {재생} other {재생}}\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes 시청자 점수\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes 토마토미터\",\n  \"components.MovieDetails.runtime\": \"{minutes} 분\",\n  \"components.PermissionEdit.manageissuesDescription\": \"미디어 이슈를 관리할 권한을 부여합니다.\",\n  \"components.PersonDetails.crewmember\": \"제작진\",\n  \"components.PermissionEdit.viewissues\": \"이슈 보기\",\n  \"components.RequestBlock.decline\": \"요청 거부\",\n  \"components.RequestModal.pendingrequest\": \"보류 중인 요청\",\n  \"components.ResetPassword.emailresetlink\": \"이메일 복구 링크\",\n  \"components.ResetPassword.confirmpassword\": \"비밀번호 확인\",\n  \"components.ResetPassword.gobacklogin\": \"로그인 페이지로 돌아가기\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Gotify 테스트 알림을 보내는 중…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Pushover 테스트 알림을 보내는 중…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover 테스트 알림이 전송되었습니다!\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"적어도 하나 이상의 알림 유형을 선택해야 합니다\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"웹훅 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"이메일 테스트 알림이 전송되었습니다!\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"유효한 PGP 개인 키를 입력해야 합니다\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"유효한 포트 번호를 입력해야 합니다\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"루트 폴더 불러오는 중…\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"최소 요구 사항 선택\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"루트 폴더를 선택해야 합니다\",\n  \"components.Settings.RadarrModal.selecttags\": \"태그 선택\",\n  \"components.Settings.RadarrModal.server4k\": \"4K 서버\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"전체 미디어\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"총 요청 수\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname}이(가) 취소되었습니다.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"작업 이름\",\n  \"components.Settings.SonarrModal.baseUrl\": \"기본 URL\",\n  \"components.Settings.SonarrModal.defaultserver\": \"기본 서버\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"4K Sonarr 서버 수정\",\n  \"components.Settings.activeProfile\": \"활성화된 프로필\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"유효한 포트 번호를 입력해야 합니다\",\n  \"components.TvDetails.productioncountries\": \"제작 {countryCount, plural, one {국가} other {국가}}\",\n  \"components.UserList.owner\": \"소유자\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"표시 이름\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"이메일 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"텔레그램 알림 설정을 저장하지 못했습니다.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"유효한 Chat ID를 입력해야 합니다\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"웹 푸시\",\n  \"components.UserProfile.unlimited\": \"무제한\",\n  \"pages.returnHome\": \"홈으로 돌아가기\",\n  \"components.Settings.tautulliSettings\": \"Tautulli 설정\",\n  \"components.TvDetails.cast\": \"출연진\",\n  \"components.UserList.user\": \"사용자\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"일반 설정\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chat ID\",\n  \"i18n.decline\": \"거절\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# 선택한 필터} other {# 선택한 필터}}\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# 선택한 필터} other {# 선택한 필터}}\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex 시청 목록</PlexWatchlistSupportLink>에 추가한 미디어는 여기에 표시됩니다.\",\n  \"components.Discover.StudioSlider.studios\": \"스튜디오\",\n  \"components.Discover.discover\": \"디스커버\",\n  \"components.Discover.resetsuccess\": \"디스커버 사용자 지정 설정을 재설정했습니다.\",\n  \"components.Discover.resettodefault\": \"기본값으로 재설정\",\n  \"components.Discover.studios\": \"스튜디오\",\n  \"components.Discover.resetfailed\": \"디스커버 사용자 지정 설정을 재설정하는 중에 문제가 발생했습니다.\",\n  \"components.Discover.trending\": \"인기 있는\",\n  \"components.Discover.updatesuccess\": \"디스커버 사용자 지정 설정이 업데이트되었습니다.\",\n  \"components.IssueDetails.IssueComment.delete\": \"댓글 삭제\",\n  \"components.IssueDetails.IssueComment.postedby\": \"{username}님이 {relativeTime}에 게시함\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"{username}님이 {relativeTime}에 게시함 (수정됨)\",\n  \"components.IssueDetails.allseasons\": \"모든 시즌\",\n  \"components.IssueDetails.closeissue\": \"이슈 종료\",\n  \"components.IssueDetails.closeissueandcomment\": \"댓글 첨부로 닫기\",\n  \"components.IssueDetails.comments\": \"댓글\",\n  \"components.IssueDetails.deleteissue\": \"이슈 삭제\",\n  \"components.IssueDetails.commentplaceholder\": \"댓글 추가…\",\n  \"components.IssueDetails.leavecomment\": \"댓글\",\n  \"components.IssueDetails.issuetype\": \"유형\",\n  \"components.IssueDetails.nocomments\": \"댓글이 없습니다.\",\n  \"components.IssueDetails.openedby\": \"#{issueId}가 {username}에 의해 {relativeTime}에 열림\",\n  \"components.IssueDetails.lastupdated\": \"마지막 업데이트\",\n  \"components.IssueDetails.openin4karr\": \"4K {arr}에서 열기\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"이슈 내용이 성공적으로 수정되었습니다!\",\n  \"components.IssueDetails.toastissuedeleted\": \"이슈가 성공적으로 삭제되었습니다!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"이슈를 삭제하는 동안 문제가 발생했습니다.\",\n  \"components.IssueDetails.toaststatusupdated\": \"이슈 상태가 성공적으로 수정되었습니다!\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"추가 콘텐츠\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"모든 시즌\",\n  \"components.IssueModal.issueAudio\": \"오디오\",\n  \"components.IssueModal.issueOther\": \"기타\",\n  \"components.IssueModal.issueVideo\": \"영상\",\n  \"components.LanguageSelector.languageServerDefault\": \"기본값 ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"모든 언어\",\n  \"components.Layout.Sidebar.issues\": \"이슈\",\n  \"components.Layout.UserDropdown.myprofile\": \"프로필\",\n  \"components.Login.loginerror\": \"로그인을 시도하는 중에 문제가 발생했습니다.\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr 안정\",\n  \"components.Login.signingin\": \"로그인 중…\",\n  \"components.ManageSlideOver.manageModalIssues\": \"진행 중인 이슈\",\n  \"components.ManageSlideOver.manageModalMedia\": \"미디어\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"요청 없음.\",\n  \"components.ManageSlideOver.mark4kavailable\": \"4K에서 사용 가능한 것으로 표시\",\n  \"components.MovieDetails.budget\": \"제작비\",\n  \"components.MovieDetails.reportissue\": \"이슈 보고\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {개봉일} other {개봉일}}\",\n  \"components.MovieDetails.theatricalrelease\": \"극장 개봉일\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {스튜디오} other {스튜디오}}\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"이슈가 보고되면 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"자동 승인 요청\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"요청 거부됨\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"미디어 요청이 거부되면 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"미디어 요청이 거부되면 알림을 받습니다.\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"고급 미디어 요청 옵션을 수정할 권한을 부여합니다.\",\n  \"components.PermissionEdit.autoapprove\": \"자동 승인\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"4K 영화 자동 승인\",\n  \"components.PermissionEdit.autoapproveSeries\": \"시리즈 자동 승인\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"비 4K 시리즈 요청에 대해 자동 승인을 부여합니다.\",\n  \"components.PermissionEdit.createissues\": \"이슈 보고\",\n  \"components.PermissionEdit.autorequest\": \"자동 요청\",\n  \"components.PermissionEdit.autorequestDescription\": \"Plex 시청 목록를 통해 4K가 아닌 미디어에 대한 요청을 자동으로 제출할 수 있는 권한을 부여합니다.\",\n  \"components.PermissionEdit.managerequests\": \"요청 관리\",\n  \"components.PermissionEdit.managerequestsDescription\": \"미디어 요청을 관리할 수 있는 권한을 부여합니다. 이 권한이 있는 사용자의 모든 요청은 자동으로 승인됩니다.\",\n  \"components.PermissionEdit.request\": \"요청\",\n  \"components.PermissionEdit.request4k\": \"4K 요청\",\n  \"components.PermissionEdit.request4kTvDescription\": \"4K 시리즈에 대한 요청을 제출할 수 있는 권한을 부여합니다.\",\n  \"components.PermissionEdit.requestDescription\": \"4K가 아닌 미디어에 대한 요청을 제출할 수 있는 권한을 부여합니다.\",\n  \"components.PermissionEdit.users\": \"사용자 관리\",\n  \"components.PermissionEdit.viewrequests\": \"요청 보기\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"다른 사용자가 제출한 미디어 요청을 볼 수 있는 권한을 부여합니다.\",\n  \"components.PersonDetails.ascharacter\": \"{character} 역\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {일} other {일}}\",\n  \"components.RegionSelector.regionServerDefault\": \"기본 ({region})\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{시즌} 당 {quotaDays} {일}</quotaUnits>\",\n  \"components.RequestBlock.lastmodifiedby\": \"최종 수정자\",\n  \"components.RequestBlock.requestoverrides\": \"요청 재정의\",\n  \"components.RequestButton.approve4krequests\": \"승인 {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.approverequest\": \"요청 승인\",\n  \"components.RequestButton.approverequest4k\": \"4K 요청 승인\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {시즌} other {시즌}}\",\n  \"components.RequestButton.declinerequests\": \"거부 {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.declinerequest\": \"요청 거부\",\n  \"components.RequestButton.requestmore\": \"추가 요청\",\n  \"components.RequestButton.requestmore4k\": \"4K에서 추가 요청\",\n  \"components.RequestButton.viewrequest\": \"요청 보기\",\n  \"components.RequestCard.deleterequest\": \"요청 삭제\",\n  \"components.RequestCard.editrequest\": \"요청 수정\",\n  \"components.RequestCard.failedretry\": \"요청을 다시 시도하는 동안 문제가 발생했습니다.\",\n  \"components.RequestList.RequestItem.deleterequest\": \"요청 삭제\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {시즌} other {시즌}}\",\n  \"components.RequestList.RequestItem.modified\": \"수정됨\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"대상 서버\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"남은 시즌 요청이 충분하지 않음\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"<ProfileLink>프로필 페이지</ProfileLink>에서 이 사용자의 요청 제한에 관한 요약을 확인할 수 있습니다.\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {영화} other {영화}}\",\n  \"components.RequestModal.errorediting\": \"요청을 수정하는 동안 문제가 발생했습니다.\",\n  \"components.RequestModal.cancel\": \"요청 취소\",\n  \"components.RequestModal.numberofepisodes\": \"에피소드 수\",\n  \"components.RequestModal.edit\": \"요청 수정\",\n  \"components.RequestModal.requestadmin\": \"이 요청은 자동으로 승인됩니다.\",\n  \"components.RequestModal.requestCancel\": \"<strong>{title}</strong> 에 대한 요청이 취소되었습니다.\",\n  \"components.RequestModal.requestseriestitle\": \"시리즈 요청\",\n  \"components.RequestModal.season\": \"시즌\",\n  \"components.RequestModal.seasonnumber\": \"시즌 {number}\",\n  \"components.RequestModal.selectseason\": \"시즌 선택\",\n  \"components.Search.search\": \"검색\",\n  \"components.Search.searchresults\": \"검색 결과\",\n  \"components.Selector.nooptions\": \"검색된 결과가 없습니다.\",\n  \"components.Selector.searchStudios\": \"스튜디오 검색…\",\n  \"components.Selector.starttyping\": \"검색하시려면 입력해주세요.\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"에이전트 활성화\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify 테스트 알림이 전송되었습니다!\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL은 슬래시로 끝나서는 안 됩니다\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"채널 태그\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet 테스트 알림이 전송되었습니다!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet 테스트 알림을 보내지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Pushbullet 테스트 알림 보내기…\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"Seerr와 함께 사용할 <ApplicationRegistrationLink>애플리케이션 등록</ApplicationRegistrationLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"에이전트 활성화\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"적어도 하나 이상의 알림 유형을 선택해야 합니다\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"애플리케이션 API 토큰\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushover 알림 설정을 저장하지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"에이전트 활성화\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"유효한 URL을 입력해야 합니다\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Web Push 알림을 받으려면 Overserr가 HTTPS를 통해 입력되어야 합니다.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON 페이로드\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"기본값으로 재설정\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"웹훅 테스트 알림을 보내는 중…\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"적어도 하나 이상의 알림 유형을 선택해야 합니다\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"웹훅 URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"유효한 JSON 페이로드를 입력해야 합니다\",\n  \"components.Settings.Notifications.allowselfsigned\": \"자체 서명된 인증서 허용\",\n  \"components.Settings.Notifications.authUser\": \"SMTP 사용자 이름\",\n  \"components.Settings.Notifications.botApiTip\": \"Seerr와 함께 사용할 <CreateBotLink>봇 생성</CreateBotLink>이 필요합니다\",\n  \"components.Settings.Notifications.botUsername\": \"봇 사용자 이름\",\n  \"components.Settings.Notifications.chatIdTip\": \"봇과 채팅을 시작하고 <GetIdBotLink>@get_id_bot</GetIdBotLink>, <code>/my_id</code> 명령을 실행하세요\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discord 알림 설정을 저장하지 못했습니다.\",\n  \"components.Settings.Notifications.chatId\": \"Chat ID\",\n  \"components.Settings.Notifications.botUsernameTip\": \"사용자가 봇과 채팅을 시작하고 자신의 알림을 구성하도록 허용\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"이메일 알림 설정을 저장하지 못했습니다.\",\n  \"components.Settings.Notifications.enableMentions\": \"멘션 활성화\",\n  \"components.Settings.Notifications.encryption\": \"암호화 방식\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"이메일 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.Notifications.encryptionDefault\": \"가능한 경우 STARTTLS 사용\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"암시적 TLS 사용\",\n  \"components.Settings.Notifications.encryptionNone\": \"없음\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"항상 STARTTLS 사용\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP 비밀번호\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP 개인 키\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"다음을 사용하여 암호화된 이메일 메시지 서명 <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.sendSilently\": \"조용히 전송\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"다음을 사용하여 암호화된 이메일 메시지 서명 <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"소리 없이 알림 보내기\",\n  \"components.Settings.Notifications.senderName\": \"발신자 이름\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP 호스트\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP 포트\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"텔레그램 알림 설정을 저장하지 못했습니다.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"텔레그램 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"PGP 비밀번호를 입력해야 합니다\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"봇 인증 토큰을 입력해야 합니다\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"유효한 Chat ID를 입력해야 합니다\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"텔레그램 테스트 알림이 전송되었습니다!\",\n  \"components.Settings.Notifications.validationEmail\": \"유효한 이메일 주소를 입력해야 합니다\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"당신의 서버에서 <DiscordWebhookLink>웹훅 통합</DiscordWebhookLink> 만들기\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"최소 요구 사항\",\n  \"components.Settings.RadarrModal.servername\": \"서버 이름\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"서버 이름을 입력해야 합니다\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"유효한 포트 번호를 입력해야 합니다\",\n  \"components.Settings.SettingsAbout.about\": \"정보\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"출시\",\n  \"components.Settings.SettingsAbout.outofdate\": \"오래됨\",\n  \"components.Settings.SettingsLogs.message\": \"메시지\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"일시중지\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"원작 언어로 콘텐츠 필터링\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"부분 시리즈 요청 허용\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"사용자가 Plex OAuth 대신 이메일 주소와 암호를 사용하여 로그인하도록 허용\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"전역 영화 요청 제한\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"사용자 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.SonarrModal.apiKey\": \"API 키\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Sonarr 서버 수정\",\n  \"components.Settings.SonarrModal.notagoptions\": \"태그가 없습니다.\",\n  \"components.Settings.SonarrModal.selecttags\": \"태그 선택\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Sonarr에 연결하지 못했습니다.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr 연결이 성공적으로 설정되었습니다!\",\n  \"components.Settings.address\": \"주소\",\n  \"components.Settings.enablessl\": \"SSL 사용\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.plexlibraries\": \"Plex 라이브러리\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.scanning\": \"동기화 중…\",\n  \"components.Settings.services\": \"서비스\",\n  \"components.Settings.validationUrl\": \"유효한 URL을 입력해야 합니다\",\n  \"components.StatusBadge.openinarr\": \"{arr}에서 열기\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"시즌 데이터를 검색하는 동안 문제가 발생했습니다.\",\n  \"components.UserList.creating\": \"생성 중…\",\n  \"components.UserList.deleteuser\": \"사용자 삭제\",\n  \"components.UserList.passwordinfodescription\": \"애플리케이션 URL을 구성하고 이메일 알림을 활성화하여 자동으로 비밀번호를 생성할 수 있도록 설정해주세요.\",\n  \"components.UserList.role\": \"역할\",\n  \"components.UserList.plexuser\": \"Plex 사용자\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"기본값 ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"소유자\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"시리즈 요청 제한\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"사용자 ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"이메일\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"30자의 <UsersGroupsLink>사용자 또는 그룹 식별자</UsersGroupsLink>를 입력해주세요\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Pushover 알림 설정을 저장하지 못했습니다.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"비밀번호가 성공적으로 저장되었습니다!\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"권한\",\n  \"components.UserProfile.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex 시청 목록</PlexWatchlistSupportLink>에 추가한 미디어는 여기에 표시됩니다.\",\n  \"components.UserProfile.movierequests\": \"영화 요청\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"이 사용자의 설정을 수정할 수 있는 권한이 없습니다.\",\n  \"i18n.advanced\": \"고급\",\n  \"i18n.edit\": \"수정\",\n  \"i18n.next\": \"다음\",\n  \"i18n.noresults\": \"결과가 없습니다.\",\n  \"i18n.request4k\": \"4K로 요청\",\n  \"i18n.processing\": \"처리 중\",\n  \"i18n.request\": \"요청\",\n  \"i18n.unavailable\": \"사용할 수 없음\",\n  \"pages.somethingwentwrong\": \"문제가 발생했습니다\",\n  \"components.Discover.customizediscover\": \"디스커버 사용자 지정\",\n  \"components.Discover.resetwarning\": \"모든 슬라이더를 기본값으로 재설정합니다. 이렇게 하면 모든 사용자 지정 슬라이더도 삭제됩니다!\",\n  \"components.Discover.stopediting\": \"수정 중단\",\n  \"components.Discover.tmdbsearch\": \"TMDB 검색\",\n  \"components.Discover.tmdbstudio\": \"TMDB 스튜디오\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TV 스트리밍 서비스\",\n  \"components.IssueList.IssueItem.problemepisode\": \"영향을 받는 에피소드\",\n  \"components.IssueDetails.IssueComment.edit\": \"댓글 수정\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"이슈 삭제\",\n  \"components.Layout.Sidebar.users\": \"사용자\",\n  \"components.ManageSlideOver.alltime\": \"전체 시간\",\n  \"components.IssueDetails.problemseason\": \"영향을 받는 시즌\",\n  \"components.IssueDetails.reopenissueandcomment\": \"댓글과 함께 다시 이슈 열기\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"이슈 내용을 수정하는 동안 문제가 발생했습니다.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"이슈 상태를 수정하는 동안 문제가 발생했습니다.\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"이슈 제출\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"<strong>{title}</strong> 에 대한 이슈 보고서가 성공적으로 제출되었습니다!\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"반드시 내용을 입력해야 합니다\",\n  \"components.Login.signinheader\": \"계속하려면 로그인하세요\",\n  \"components.ManageSlideOver.movie\": \"영화\",\n  \"components.MovieDetails.originaltitle\": \"원작명\",\n  \"components.ManageSlideOver.openarr4k\": \"4K {arr}에서 열기\",\n  \"components.MovieDetails.originallanguage\": \"원작 언어\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* 이렇게 하면 모든 요청을 포함하여 이 {mediaType}에 대한 모든 데이터가 되돌릴 수 없게 삭제됩니다. 이 항목이 Plex 라이브러리에 있으면 다음 스캔 중에 미디어 정보가 다시 생성됩니다.\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K 미디어\",\n  \"components.ManageSlideOver.openarr\": \"{arr}에서 열기\",\n  \"components.ManageSlideOver.manageModalRequests\": \"요청\",\n  \"components.ManageSlideOver.manageModalTitle\": \"{mediaType} 관리\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"모든 시즌을 4K에서 사용 가능하게 표시\",\n  \"components.ManageSlideOver.opentautulli\": \"Tautulli에서 열기\",\n  \"components.ManageSlideOver.pastdays\": \"지난 {days, number}일\",\n  \"components.MovieDetails.cast\": \"출연진\",\n  \"components.MovieDetails.digitalrelease\": \"디지털 출시\",\n  \"components.MovieDetails.managemovie\": \"영화 관리\",\n  \"components.MovieDetails.mark4kavailable\": \"4K에서 사용 가능하게 표시\",\n  \"components.MovieDetails.overview\": \"정보\",\n  \"components.MovieDetails.overviewunavailable\": \"정보를 볼 수 없습니다.\",\n  \"components.MovieDetails.revenue\": \"수익\",\n  \"components.MovieDetails.productioncountries\": \"제작 {countryCount, plural, one {국가} other {국가}}\",\n  \"components.MovieDetails.recommendations\": \"추천\",\n  \"components.MovieDetails.showmore\": \"자세히 보기\",\n  \"components.MovieDetails.streamingproviders\": \"현재 스트리밍 중\",\n  \"components.NotificationTypeSelector.issuecreated\": \"보고된 이슈\",\n  \"components.MovieDetails.similar\": \"비슷한 콘텐츠\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"이슈에 새 댓글이 수신되면 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"재개된 이슈\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"이슈가 해결되면 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"요청 승인됨\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"자동으로 제출된 요청\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"보고한 이슈가 해결되면 알림을 받습니다.\",\n  \"components.PermissionEdit.usersDescription\": \"사용자를 관리할 수 있는 권한을 부여합니다. 이 권한이 있는 사용자는 관리자 권한으로 사용자를 수정하거나 부여할 수 없습니다.\",\n  \"components.QuotaSelector.unlimited\": \"무제한\",\n  \"components.NotificationTypeSelector.issueresolved\": \"해결된 이슈\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"사용자가 자동으로 승인되는 새 미디어 요청을 제출할 때 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"미디어 요청이 수동으로 승인되면 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"요청 가능\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"미디어 요청이 Radarr 또는 Sonarr에 추가되지 않으면 알림을 보냅니다.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"미디어 요청을 사용할 수 있게 되면 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"다른 사용자가 승인이 필요한 새 미디어 요청을 제출할 때 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"다른 사용자가 이슈를 보고하면 알림을 받습니다.\",\n  \"components.PermissionEdit.request4kDescription\": \"4K 미디어에 대한 요청을 제출할 수 있는 권한을 부여합니다.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"보류 중인 승인 요청\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"신고한 이슈에 새로운 댓글이 도착하면 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"보고한 이슈가 다시 열릴 때 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"다른 사용자가 자동으로 승인되는 새 미디어 요청을 제출할 때 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"미디어 요청이 승인되면 알림을 받습니다.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"미디어 요청이 Radarr 또는 Sonarr에 추가되지 않을 때 알림을 받습니다.\",\n  \"components.PermissionEdit.adminDescription\": \"완전한 관리자 액세스. 다른 모든 권한 검사를 무시합니다.\",\n  \"components.PermissionEdit.advancedrequest\": \"고급 요청\",\n  \"components.PermissionEdit.viewrecent\": \"최근 추가된 항목 보기\",\n  \"components.PermissionEdit.requestTvDescription\": \"비 4K 시리즈에 대한 요청을 제출할 수 있는 권한을 부여합니다.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Plex 시청 목록 보기\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"다른 사용자의 Plex 시청 목록을 볼 수 있는 권한을 부여합니다.\",\n  \"components.PersonDetails.appearsin\": \"출연\",\n  \"components.PermissionEdit.viewissuesDescription\": \"다른 사용자가 보고한 미디어 이슈를 볼 수 있는 권한을 부여합니다.\",\n  \"components.PermissionEdit.viewrecentDescription\": \"최근 추가된 미디어 목록을 볼 수 있는 권한을 부여합니다.\",\n  \"components.PersonDetails.alsoknownas\": \"다른 이름: {names}\",\n  \"components.PersonDetails.birthdate\": \"{birthdate} 출생\",\n  \"components.RequestBlock.profilechanged\": \"품질 프로필\",\n  \"components.RequestBlock.rootfolder\": \"루트 폴더\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"요청 취소\",\n  \"components.RequestList.RequestItem.requested\": \"요청됨\",\n  \"components.RegionSelector.regionDefault\": \"모든 지역\",\n  \"components.RequestBlock.approve\": \"요청 승인\",\n  \"components.RequestBlock.languageprofile\": \"언어 프로필\",\n  \"components.RequestButton.decline4krequests\": \"거부 {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.declinerequest4k\": \"4K 요청 거부\",\n  \"components.RequestBlock.edit\": \"요청 수정\",\n  \"components.RequestBlock.server\": \"대상 서버\",\n  \"components.RequestButton.approverequests\": \"승인 {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestCard.unknowntitle\": \"알 수 없는 제목\",\n  \"components.RequestList.RequestItem.failedretry\": \"요청을 다시 시도하는 동안 문제가 발생했습니다.\",\n  \"components.RequestList.RequestItem.requesteddate\": \"요청됨\",\n  \"components.RequestList.sortAdded\": \"가장 최근\",\n  \"components.RequestList.sortModified\": \"마지막 수정\",\n  \"components.RequestList.RequestItem.editrequest\": \"요청 수정\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{user}의 {date}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"영화\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"비밀번호가 성공적으로 재설정되었습니다!\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"인증 헤더\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"고급\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* 이 시리즈는 애니메이션입니다.\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"태그가 없습니다.\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"태그 선택\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"태그\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"이 시리즈를 자동으로 매칭할 수 없습니다. 아래에서 올바른 일치 항목을 선택하십시오.\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (기본값)\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"품질 프로필\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"언어 프로필\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"다음으로 요청\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"<strong>{days}</strong> 일 마다 <strong>{limit}</strong> {type} 을(를) 요청할 수 있습니다 .\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"<ProfileLink>프로필 페이지</ProfileLink>에서 요청 제한에 관한 요약을 확인할 수 있습니다.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"이 사용자는 <strong>{days}</strong> 일 마다 <strong>{limit}</strong> {type} 을(를) 요청할 수 있습니다.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"이 시리즈에 대한 요청을 제출하려면 최소한 <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}}가 남아 있어야 합니다.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"이 사용자가 이 시리즈에 대한 요청을 제출하려면 최소한 <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}}가 남아 있어야 합니다.\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"이 시리즈와 일치하는 항목을 찾을 수 없습니다.\",\n  \"components.RequestModal.autoapproval\": \"자동 승인\",\n  \"components.RequestModal.pending4krequest\": \"보류 중인 4K 요청\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> 요청 성공했습니다!\",\n  \"components.RequestModal.requestApproved\": \"<strong>{title}</strong> 요청이 승인되었습니다!\",\n  \"components.RequestModal.requestseries4ktitle\": \"4K 시리즈 요청\",\n  \"components.RequestModal.requestcancelled\": \"<strong>{title}</strong> 에 대한 요청이 취소되었습니다.\",\n  \"components.ResetPassword.email\": \"이메일 주소\",\n  \"components.RequestModal.requestedited\": \"<strong>{title}</strong> 요청이 성공적으로 수정되었습니다!\",\n  \"components.RequestModal.requesterror\": \"요청을 제출하는 동안 문제가 발생했습니다.\",\n  \"components.RequestModal.requestseasons4k\": \"4K에서 {seasonCount} {seasonCount, plural, one {Season} other {Seasons}} 요청\",\n  \"components.RequestModal.requestmovies\": \"{count} {count, plural, one {영화} other {영화}} 요청\",\n  \"components.ResetPassword.password\": \"비밀번호\",\n  \"components.ResetPassword.resetpassword\": \"비밀번호 재설정\",\n  \"components.ResetPassword.validationpasswordminchars\": \"비밀번호가 너무 짧습니다; 최소 8자리 이상이어야 합니다\",\n  \"components.ResetPassword.validationpasswordrequired\": \"암호를 입력해야 합니다\",\n  \"components.Selector.showless\": \"간단히 보기\",\n  \"components.Selector.showmore\": \"더 보기\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify 알림 설정을 저장하지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"애플리케이션 토큰\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"서버 URL\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"에이전트 활성화\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"액세스 토큰\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"사용자의 토큰 생성 <PushbulletSettingsLink>Account Settings</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbullet 알림 설정을 저장하지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"액세스 토큰을 입력해야 합니다\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover 테스트 알림을 보내지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"사용자 또는 그룹 키\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"30자의 <UsersGroupsLink>사용자 또는 그룹 식별자</UsersGroupsLink>를 입력해주세요\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"적어도 하나 이상의 알림 유형을 선택해야 합니다\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"웹훅 URL\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Web Push 테스트 알림을 보내지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"<WebhookLink>Incoming 웹훅</WebhookLink> 통합을 생성하세요\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Web Push 테스트 알림을 보내는 중…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Web Push 테스트 알림이 전송되었습니다!\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"에이전트 활성화\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Web Push 알림 설정을 저장하지 못했습니다.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Web Push 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON 페이로드가 성공적으로 재설정되었습니다!\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"템플릿 변수 도움말\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"웹훅 테스트 알림이 전송되었습니다!\",\n  \"components.Settings.Notifications.authPass\": \"SMTP 비밀번호\",\n  \"components.Settings.Notifications.agentenabled\": \"에이전트 활성화\",\n  \"components.Settings.Notifications.emailsender\": \"발신자 주소\",\n  \"components.Settings.Notifications.botAPI\": \"봇 인증 토큰\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"새 API 키가 성공적으로 생성되었습니다!\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord 테스트 알림을 보내지 못했습니다.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Discord 테스트 알림을 보내는 중…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord 테스트 알림이 전송되었습니다!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"텔레그램 테스트 알림을 보내지 못했습니다.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"텔레그램 테스트 알림을 보내는 중…\",\n  \"components.Settings.RadarrModal.createradarr\": \"새 Radarr 서버 추가\",\n  \"components.Settings.RadarrModal.default4kserver\": \"기본 4K 서버\",\n  \"components.Settings.RadarrModal.editradarr\": \"Radarr 서버 수정\",\n  \"components.Settings.RadarrModal.defaultserver\": \"기본 서버\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"품질 프로필 선택\",\n  \"components.Settings.RadarrModal.rootfolder\": \"루트 폴더\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"품질 프로필\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL은 슬래시로 끝나서는 안 됩니다\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"최소 요구 사항을 선택해야 합니다\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"만약 입력된 이메일 주소가 유효한 사용자와 연결되어 있다면, 비밀번호 재설정 링크가 해당 이메일 주소로 전송될 것입니다.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"애플리케이션 토큰을 입력해야 합니다\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"유효한 사용자 또는 그룹 키를 입력해야 합니다\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"유효한 URL을 입력해야 합니다\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"유효한 호스트 네임 또는 IP 주소를 입력해야 합니다\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"유효한 호스트 네임 또는 IP 주소를 입력해야 합니다\",\n  \"components.Settings.Notifications.encryptionTip\": \"대부분의 경우 암시적 TLS는 465 포트를 사용하고 STARTTLS는 587 포트를 사용합니다\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} 변경 로그\",\n  \"components.Settings.SettingsAbout.uptodate\": \"최신\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub 토론\",\n  \"components.Settings.SettingsAbout.version\": \"버전\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"값 크기\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"누락\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"캐시 이름\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"다운로드 동기화 재설정\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"이미지 캐시 비우기\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"매 {jobScheduleMinutes, plural, one {분} other {{jobScheduleMinutes} 분}}\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"캐시 플러시\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"저장된 이미지\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"총 캐시 크기\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"정보\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"다음 실행\",\n  \"components.Settings.SettingsLogs.extraData\": \"추가 데이터\",\n  \"components.Settings.SettingsLogs.time\": \"타임스탬프\",\n  \"components.Settings.SettingsMain.cacheImages\": \"이미지 캐싱 활성화\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Seerr에 대한 전역 및 기본 설정을 구성합니다.\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"세부 정보 보기\",\n  \"components.Settings.SettingsMain.applicationurl\": \"애플리케이션 URL\",\n  \"components.Settings.SettingsMain.apikey\": \"API 키\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"외부 소스 이미지 캐시 (상당한 디스크 공간 필요)\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"애플리케이션 이름\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"사용 가능한 미디어 숨기기\",\n  \"components.Settings.SettingsMain.locale\": \"표시 언어\",\n  \"components.Settings.SettingsMain.generalsettings\": \"일반 설정\",\n  \"components.Settings.SettingsMain.originallanguage\": \"디스커버 언어\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"설정을 저장하는 동안 문제가 발생했습니다.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"사용자 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"애플리케이션 이름을 입력해야 합니다\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"스캔 활성화\",\n  \"components.Settings.SettingsUsers.users\": \"사용자\",\n  \"components.Settings.SonarrModal.add\": \"서버 추가\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"애니메이션 언어 프로필\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"새 4K Sonarr 서버 추가\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"언어 프로필 불러오는 중…\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"기본 URL 앞에는 슬래시가 있어야 합니다\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"서버 이름을 입력해야 합니다\",\n  \"components.Settings.serviceSettingsDescription\": \"아래에서 {serverType} 서버(들)를 구성하세요. 여러 개의 {serverType} 서버를 연결할 수 있지만, 기본 설정으로는 두 개만 지정할 수 있습니다 (비-4K 한 대와 4K 한 대). 관리자는 승인 이전에 새로운 요청을 처리하는 데 사용할 서버를 재지정할 수 있습니다.\",\n  \"components.StatusBadge.managemedia\": \"{mediaType} 관리\",\n  \"components.Settings.SonarrModal.animeTags\": \"애니메이션 태그\",\n  \"components.Settings.SonarrModal.hostname\": \"호스트 네임 또는 IP 주소\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"태그 불러오기를 위한 연결 테스트\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"언어 프로필을 선택해야 합니다\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"품질 프로필을 선택해야 합니다\",\n  \"components.Settings.addradarr\": \"Radarr 서버 추가\",\n  \"components.Settings.default\": \"기본값\",\n  \"components.Settings.email\": \"이메일\",\n  \"components.Settings.experimentalTooltip\": \"이 설정을 활성화하면 예기치 않은 애플리케이션 동작이 발생할 수 있습니다\",\n  \"components.Settings.notrunning\": \"실행 중이 아님\",\n  \"components.Settings.deleteserverconfirm\": \"정말 서버를 삭제하시겠습니까?\",\n  \"components.Settings.librariesRemaining\": \"남은 라이브러리: {count}\",\n  \"components.Settings.noDefault4kServer\": \"4K {serverType} 서버는 사용자가 4K {mediaType} 요청을 제출할 수 있도록 기본 설정되어야 합니다.\",\n  \"components.Settings.scan\": \"라이브러리 동기화\",\n  \"components.Settings.plexsettingsDescription\": \"Plex 서버의 설정을 구성하세요. Seerr는 Plex 라이브러리를 스캔하여 콘텐츠의 사용 가능성을 판단합니다.\",\n  \"components.Settings.notificationsettings\": \"알림 설정\",\n  \"components.Settings.plexsettings\": \"Plex 설정\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"알림 에이전트를 구성하고 활성화합니다.\",\n  \"components.Settings.serverLocal\": \"로컬\",\n  \"components.Settings.sonarrsettings\": \"Sonarr 설정\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"스캔 시작\",\n  \"components.Settings.urlBase\": \"기본 URL\",\n  \"components.Settings.toastPlexRefresh\": \"Plex에서 서버 목록 검색 중…\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli 설정이 성공적으로 저장되었습니다!\",\n  \"components.Settings.validationApiKey\": \"API 키를 입력해야 합니다\",\n  \"components.Settings.validationPortRequired\": \"유효한 포트 번호를 입력해야 합니다\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"기본 URL은 슬래시로 끝나서는 안 됩니다\",\n  \"components.Settings.webAppUrlTip\": \"사용자에게 \\\"호스팅된\\\" 웹 앱 대신 서버의 웹 앱으로 이동하도록 선택적으로 설정할 수 있습니다\",\n  \"components.Setup.setup\": \"설정\",\n  \"components.Setup.welcome\": \"Seerr에 오신 것을 환영합니다\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.TvDetails.firstAirDate\": \"첫 방영일\",\n  \"components.StatusChecker.restartRequired\": \"서버 재시작 필요\",\n  \"components.StatusChecker.restartRequiredDescription\": \"수정된 설정을 적용하려면 서버를 다시 시작하십시오.\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.TvDetails.reportissue\": \"이슈 보고\",\n  \"components.UserList.admin\": \"관리자\",\n  \"components.UserList.autogeneratepasswordTip\": \"서버에서 생성한 비밀번호를 사용자에게 이메일로 보내기\",\n  \"components.UserList.deleteconfirm\": \"이 사용자를 삭제하시겠습니까? 모든 요청 데이터가 영구적으로 삭제됩니다.\",\n  \"components.UserList.newplexsigninenabled\": \"<strong>새 Plex 로그인</strong> 설정이 현재 활성화되어 있습니다. 라이브러리 액세스 권한이 있는 Plex 사용자는 로그인하기 위해 미리 불러올 필요가 없습니다.\",\n  \"components.UserList.userssaved\": \"사용자 권한이 성공적으로 저장되었습니다!\",\n  \"components.UserList.validationEmail\": \"유효한 이메일 주소를 입력해야 합니다\",\n  \"components.UserList.userdeleted\": \"사용자가 성공적으로 삭제되었습니다!\",\n  \"components.UserList.users\": \"사용자\",\n  \"components.UserList.password\": \"비밀번호\",\n  \"components.UserList.validationpasswordminchars\": \"비밀번호가 너무 짧습니다. 최소 8자리 이상이어야 합니다\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Discord 사용자 계정과 연결된 <FindDiscordIdLink>다중 자릿수 ID 번호</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"유효한 애플리케이션 토큰을 입력해야 합니다\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex 사용자\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"액세스 토큰\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"일반\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"영화 요청 제한\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"전역 제한 재정의\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"디스커버 언어\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"로컬 사용자\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"설정을 저장하는 동안 문제가 발생했습니다.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"설정이 성공적으로 저장되었습니다!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"사용자 계정과 연결된 <FindDiscordIdLink>다중 자릿수 ID 번호</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"영화 자동 요청\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"유효한 Discord 사용자 ID를 입력해야 합니다\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Discord 알림 설정을 저장하지 못했습니다.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"애플리케이션 API 토큰\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>애플리케이션 등록</ApplicationRegistrationLink>을 통해 {applicationTitle}과(와) 함께 사용할 수 있도록 등록해주세요\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>채팅 시작</TelegramBotLink>, <GetIdBotLink>@get_id_bot</GetIdBotLink>, <code>/my_id</code> 명령을 실행하세요\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"유효한 사용자 또는 그룹 키를 입력해야 합니다\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"텔레그램 알림 설정이 성공적으로 저장되었습니다!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"유효한 PGP 공개 키를 입력해야 합니다\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"액세스 토큰을 입력해야 합니다\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"이 사용자 계정에는 현재 암호가 설정되어 있지 않습니다. 이 계정이 \\\"로컬 사용자\\\"로 로그인할 수 있도록 하려면 아래 암호를 구성하세요\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"새 암호\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"새 비밀번호를 확인해야 합니다\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"비밀번호\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"당신의 계정에는 현재 비밀번호가 설정되어 있지 않습니다. 이메일 주소를 사용하여 \\\"로컬 사용자\\\" 로 로그인하려면 아래 비밀번호를 구성하세요.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"이 사용자의 암호를 수정할 수 있는 권한이 없습니다.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"비밀번호\",\n  \"i18n.open\": \"열기\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"현재 암호를 입력해야 합니다\",\n  \"components.UserProfile.limit\": \"{limit} 중 {remaining}\",\n  \"components.UserProfile.requestsperdays\": \"{limit} 남음\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"새 비밀번호를 입력해야 합니다\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"자신의 권한을 수정할 수 없습니다.\",\n  \"components.UserProfile.plexwatchlist\": \"Plex 시청 목록\",\n  \"components.UserProfile.recentrequests\": \"최근 요청\",\n  \"i18n.areyousure\": \"확실합니까?\",\n  \"i18n.declined\": \"거부됨\",\n  \"i18n.collection\": \"컬렉션\",\n  \"i18n.delete\": \"삭제\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.experimental\": \"실험적\",\n  \"i18n.failed\": \"실패\",\n  \"i18n.notrequested\": \"요청되지 않음\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.serviceunavailable\": \"서비스를 사용할 수 없음\",\n  \"components.Settings.settingUpPlexDescription\": \"Plex를 설정하려면, 세부 정보를 수동으로 입력하거나 <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>에서 검색된 서버를 선택할 수 있습니다. 사용 가능한 서버 목록을 불러오려면 드롭다운 오른쪽에 있는 버튼을 누르세요.\",\n  \"components.Settings.tautulliSettingsDescription\": \"선택적으로 Tautulli 서버의 설정을 구성하세요. Seerr는 Tautulli로부터 Plex 미디어의 시청 기록 데이터를 불러옵니다.\",\n  \"components.RequestBlock.requestdate\": \"요청 일자\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# 선택한 필터} other {# 선택한 필터}}\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {시즌} other {시즌}}\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {없음} other {<strong>#</strong>개의}} {type} {remaining, plural, one {요청} other {요청}} 남음\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"매 {jobScheduleHours, plural, one {시간} other {{jobScheduleHours} 시간}}\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB 사용자 점수\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/lb.json",
    "content": "{}\n"
  },
  {
    "path": "src/i18n/locale/lt.json",
    "content": "{\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} filmai\",\n  \"components.CollectionDetails.overview\": \"Apžvalga\",\n  \"components.CollectionDetails.requestcollection\": \"Rezervacijų kolekcija\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} filmai\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} serialai\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} serialai\",\n  \"components.Discover.StudioSlider.studios\": \"Studijos\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Serialų žanrai\",\n  \"components.Discover.popularmovies\": \"Populiarūs filmai\",\n  \"components.Discover.populartv\": \"Populiarūs serialai\",\n  \"components.Discover.recentlyAdded\": \"Paskutiniai pridėti\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Serialų žanrai\",\n  \"components.Discover.trending\": \"Populiarėjantys\",\n  \"components.DownloadBlock.estimatedtime\": \"Liko {time}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Ar tikrai norite ištrinti šį komentarą?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Ištrinti komentarą\",\n  \"components.IssueDetails.IssueComment.edit\": \"Redaguoti komentarą\",\n  \"components.IssueDetails.IssueComment.postedby\": \"{username} paskelbė {relativeTime}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"{username} paskelbė {relativeTime} (Redaguota)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Privalote įrašyti tekstą\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Pašalinti problemą\",\n  \"components.IssueDetails.comments\": \"Komentarai\",\n  \"components.IssueDetails.closeissue\": \"Užbaigta problema\",\n  \"components.IssueDetails.closeissueandcomment\": \"Uždaryti su komentaru\",\n  \"components.IssueDetails.commentplaceholder\": \"Pridėti komentarą…\",\n  \"components.IssueDetails.deleteissue\": \"Pašalinti problemą\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Ar tikrai norite pašalinti šią problemą?\",\n  \"components.IssueDetails.episode\": \"{episodeNumber} epizodas\",\n  \"components.IssueDetails.issuepagetitle\": \"Problema\",\n  \"components.IssueDetails.nocomments\": \"Nėra komentarų.\",\n  \"components.IssueDetails.play4konplex\": \"Groti 4k per Plex\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Visi sezonai\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"{episodeNumber} epizodai\",\n  \"components.IssueList.issues\": \"Problemos\",\n  \"components.Layout.Sidebar.requests\": \"Rezervacijos\",\n  \"components.Layout.Sidebar.settings\": \"Nustatymai\",\n  \"components.Layout.Sidebar.users\": \"Vartotojai\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profilis\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueModal.issueSubtitles\": \"Subtitrai\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Ieškoti filmų ir laidų\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Visos kalbos\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Rodoma kalba\",\n  \"components.Login.forgotpassword\": \"Ar pamiršai slaptažodį?\",\n  \"components.Login.email\": \"El. paštas\",\n  \"components.Login.signinheader\": \"Prisijunkite, kad tęsti\",\n  \"components.Login.signinwithplex\": \"Naudokite savo Plex prisijungimą\",\n  \"components.Login.validationpasswordrequired\": \"Prašau pateikti slaptažodį\",\n  \"components.ManageSlideOver.alltime\": \"Visi\",\n  \"components.ManageSlideOver.downloadstatus\": \"Parsisiuntimai\",\n  \"components.ManageSlideOver.movie\": \"filmas\",\n  \"components.ManageSlideOver.tvshow\": \"serialas\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Visi aktoriai\",\n  \"components.MovieDetails.budget\": \"Biudžetas\",\n  \"components.MovieDetails.originaltitle\": \"Originalus pavadinimas\",\n  \"components.MovieDetails.overview\": \"Apžvalga\",\n  \"components.MovieDetails.revenue\": \"Pajamos\",\n  \"components.MovieDetails.viewfullcrew\": \"Visa komanda\",\n  \"components.MovieDetails.similar\": \"Panašūs\",\n  \"components.MovieDetails.streamingproviders\": \"Šiuo metu transliuojama per\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studija} other {Studijos}}\",\n  \"components.PermissionEdit.request\": \"Rezervuoti\",\n  \"components.PersonDetails.crewmember\": \"Komanda\",\n  \"components.PersonDetails.appearsin\": \"Vaidino\",\n  \"components.QuotaSelector.unlimited\": \"Neriboti\",\n  \"components.RequestButton.viewrequest\": \"Peržiūrėti rezervacijas\",\n  \"components.RequestCard.deleterequest\": \"Šalinti rezervacijas\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Atšaukti rezervaciją\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Ištrinti rezervaciją\",\n  \"components.RequestList.RequestItem.editrequest\": \"Redaguoti rezervaciją\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Rezervuota\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Detaliau\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Numatytasis)\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Kokybės profilis\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Serveris\",\n  \"components.RequestModal.edit\": \"Redaguoti rezervaciją\",\n  \"components.ResetPassword.email\": \"El. paštas\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Visa serialo komanda\",\n  \"components.TvDetails.cast\": \"Aktoriai\",\n  \"components.TvDetails.episodeRuntime\": \"Epizodo trukmė\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutės\",\n  \"components.TvDetails.firstAirDate\": \"Pirmą kartą transliuota\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Tinklas} other {Tinklai}}\",\n  \"components.TvDetails.nextAirDate\": \"Artimiausia transliacija\",\n  \"components.TvDetails.productioncountries\": \"Kurta {countryCount, plural, one {šalyje} other {šalyse}}\",\n  \"components.TvDetails.recommendations\": \"Rekomendacijos\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Sezonas} other {# Sezonai}}\",\n  \"components.TvDetails.showtype\": \"Serialo tipas\",\n  \"components.TvDetails.similar\": \"Panašūs serialai\",\n  \"components.TvDetails.streamingproviders\": \"Šiuo metu transliuoja\",\n  \"components.UserList.admin\": \"Administratorius\",\n  \"i18n.approve\": \"Patvirtinti\",\n  \"i18n.approved\": \"Patvirtintas\",\n  \"i18n.available\": \"Paruoštas\",\n  \"i18n.back\": \"Atgal\",\n  \"i18n.decline\": \"Atmesti\",\n  \"i18n.declined\": \"Atmestas\",\n  \"i18n.delete\": \"Ištrinti\",\n  \"i18n.deleting\": \"Trinama…\",\n  \"i18n.edit\": \"Redaguoti\",\n  \"i18n.failed\": \"Nepavyko\",\n  \"i18n.import\": \"Importuoti\",\n  \"i18n.importing\": \"Importuojama…\",\n  \"i18n.loading\": \"Kraunasi…\",\n  \"i18n.movie\": \"Filmas\",\n  \"i18n.noresults\": \"Nėra rezultatų.\",\n  \"i18n.notrequested\": \"Nerezervuotas\",\n  \"i18n.open\": \"Atidaryti\",\n  \"i18n.partiallyavailable\": \"Dalinai prieinamas\",\n  \"i18n.processing\": \"Apdorojama\",\n  \"i18n.resolved\": \"Išspręsta\",\n  \"i18n.resultsperpage\": \"{pageSize} rezultatų puslapyje\",\n  \"i18n.retry\": \"Bandyti iš naujo\",\n  \"i18n.retrying\": \"Bandoma iš naujo…\",\n  \"i18n.save\": \"Išsaugoti\",\n  \"i18n.showingresults\": \"Rodoma nuo <strong>{from}</strong> iki <strong>{to}</strong> iš <strong>{total}</strong> rezultatų\",\n  \"i18n.status\": \"Statusas\",\n  \"i18n.test\": \"Testas\",\n  \"i18n.testing\": \"Testuojama…\",\n  \"i18n.tvshow\": \"Serialas\",\n  \"i18n.tvshows\": \"Serialai\",\n  \"i18n.unavailable\": \"Neprieinamas\",\n  \"i18n.usersettings\": \"Vartotojo nustatymai\",\n  \"i18n.view\": \"Žiūrėti\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"Vidinė serverio klaida\",\n  \"pages.serviceunavailable\": \"Paslauga nepasiekiama\",\n  \"pages.somethingwentwrong\": \"Kažkas nepavyko\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} filmai\",\n  \"components.Discover.NetworkSlider.networks\": \"Tinklai\",\n  \"components.Discover.discover\": \"Naršyti\",\n  \"components.IssueDetails.IssueDescription.description\": \"Aprašymas\",\n  \"components.IssueDetails.allseasons\": \"Visi sezonai\",\n  \"components.CollectionDetails.requestcollection4k\": \"4k rezervacijų kolekcija\",\n  \"components.IssueDetails.allepisodes\": \"Visi epizodai\",\n  \"components.IssueDetails.issuetype\": \"Tipas\",\n  \"components.IssueDetails.playonplex\": \"Groti per Plex\",\n  \"components.IssueDetails.lastupdated\": \"Paskutinį kartą atnaujinta\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} filmai\",\n  \"components.IssueDetails.leavecomment\": \"Komentaras\",\n  \"components.IssueDetails.openinarr\": \"Atverti {arr}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Neteisingai sukonfigūruotas <code>{appDataPath}</code> disko prisijungimas. Visi duomenys bus išvalyti kai konteineris bus sustabdytas ir perkrautas.\",\n  \"components.Discover.upcomingtv\": \"Greit pasirodysiantys serialai\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} serialai\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Filmų žanrai\",\n  \"components.Discover.recentrequests\": \"Paskutinės rezervacijos\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Filmų žanrai\",\n  \"components.Discover.upcoming\": \"Greit pasirodysiantys filmai\",\n  \"components.Discover.upcomingmovies\": \"Greit pasirodysiantys filmai\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Redaguoti aprašymą\",\n  \"components.IssueDetails.openin4karr\": \"Atverti 4k {arr}\",\n  \"components.Layout.UserDropdown.signout\": \"Atsijungti\",\n  \"components.IssueDetails.season\": \"{seasonNumber} sezonas\",\n  \"components.Layout.Sidebar.dashboard\": \"Naršyti\",\n  \"components.Layout.Sidebar.issues\": \"Problemos\",\n  \"components.Layout.UserDropdown.settings\": \"Nustatymai\",\n  \"components.Login.password\": \"Slaptažodis\",\n  \"components.Login.signin\": \"Prisijungti\",\n  \"components.Login.signingin\": \"Prisijungia…\",\n  \"components.Layout.VersionStatus.outofdate\": \"Nebegaliojantis\",\n  \"components.Login.loginerror\": \"Kažkas nepavyko bandant prisijungti.\",\n  \"components.Login.signinwithoverseerr\": \"Naudokite {applicationTitle} prisijungimą\",\n  \"components.Login.validationemailrequired\": \"Prašau pateikti validų el. paštą\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4k medija\",\n  \"components.MovieDetails.cast\": \"Aktoriai\",\n  \"components.MovieDetails.recommendations\": \"Rekomendacijos\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Medija\",\n  \"components.ManageSlideOver.openarr4k\": \"Atverti 4k {arr}\",\n  \"components.ManageSlideOver.pastdays\": \"Per {days, number} dienas\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Daugiau\",\n  \"components.MovieDetails.originallanguage\": \"Originalo kalba\",\n  \"components.ManageSlideOver.openarr\": \"Atverti {arr}\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutės\",\n  \"components.MovieDetails.showless\": \"Mažiau\",\n  \"components.MovieDetails.showmore\": \"Rodyti daugiau\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Išleidimo data} other {Išleidimo datos}}\",\n  \"components.MovieDetails.watchtrailer\": \"Žiūrėti trailerį\",\n  \"components.PermissionEdit.admin\": \"Administratorius\",\n  \"components.PermissionEdit.autoapprove\": \"Auto patvirtinti\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Visi epizodai\",\n  \"components.MovieDetails.productioncountries\": \"Kurta {countryCount, plural, one {Šalyje} other {Šalyse}}\",\n  \"components.PermissionEdit.request4k\": \"Rezervuoti 4k\",\n  \"components.PermissionEdit.viewrequests\": \"Peržiūrėti rezervacijas\",\n  \"components.PersonDetails.birthdate\": \"Gimtadienis {birthdate}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {filmas} other {filmai}}\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Visa komanda\",\n  \"components.PersonDetails.ascharacter\": \"kaip {character}\",\n  \"components.PersonDetails.alsoknownas\": \"Žinomas kaip: {names}\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {diena} other {dienos}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Sezonas} other {Sezonai}}\",\n  \"components.RequestButton.requestmore\": \"Rezervuoti daugiau\",\n  \"components.RequestCard.failedretry\": \"Kažkas nepavyko kartojant rezervacijos užklausą.\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {sezonas} other {sezonai}}\",\n  \"components.RequestBlock.languageprofile\": \"Kalbų profilis\",\n  \"components.RegionSelector.regionDefault\": \"Visi regionai\",\n  \"components.RegionSelector.regionServerDefault\": \"Numatytasis ({region})\",\n  \"components.RequestButton.requestmore4k\": \"Rezervuoti daugiau 4K raiška\",\n  \"components.RequestList.RequestItem.failedretry\": \"Kažkas nepavyko kartojant rezervacijos užklausą.\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} - {user}\",\n  \"components.RequestList.showallrequests\": \"Rodyti visas rezervacijas\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Sezonas} other {Sezonai}}\",\n  \"components.RequestList.RequestItem.requested\": \"Rezervuota\",\n  \"components.RequestList.RequestItem.modified\": \"Redaguota\",\n  \"components.RequestModal.requesterror\": \"Kažkas nepavyko teikiant rezervaciją.\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Sezonas} other {Sezonai}}\",\n  \"components.RequestList.requests\": \"Rezervacijos\",\n  \"components.RequestList.sortAdded\": \"Naujausi\",\n  \"components.RequestList.sortModified\": \"Seniausi\",\n  \"components.RequestModal.alreadyrequested\": \"Jau rezervuotas\",\n  \"i18n.request4k\": \"Rezervuoti 4K raiška\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"filmas\",\n  \"components.RequestModal.requestedited\": \"<strong>{title}</strong> rezervacija redaguota sėkmingai!\",\n  \"components.ResetPassword.confirmpassword\": \"Patvirtinkite slaptažodį\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Aplankas\",\n  \"components.RequestModal.cancel\": \"Atšaukti rezervaciją\",\n  \"components.RequestModal.numberofepisodes\": \"# iš epizodų\",\n  \"components.RequestModal.errorediting\": \"Kažkas nepavyko redaguojant rezervaciją.\",\n  \"components.RequestModal.requestcancelled\": \"<strong>{title}</strong> rezervacija atšaukta.\",\n  \"components.RequestModal.requestmovies\": \"Rezervuota {count} {count, plural, one {filmas} other {filmų}}\",\n  \"components.RequestModal.season\": \"Sezonas\",\n  \"components.RequestModal.requestApproved\": \"<strong>{title}</strong> rezervacija patvirtinta!\",\n  \"components.RequestModal.requestadmin\": \"Rezervacija bus automatiškai patvirtinta.\",\n  \"components.RequestModal.selectmovies\": \"Pasirinkite filmą(-us)\",\n  \"components.RequestModal.selectseason\": \"Pasirinkite sezoną(-us)\",\n  \"components.Search.searchresults\": \"Paieškos rezultatai\",\n  \"components.RequestModal.requestCancel\": \"<strong>{title}</strong> rezervacija atšaukta.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> rezervuota sėkmingai!\",\n  \"components.RequestModal.requestfrom\": \"Rezervacija iš {username} laukia patvirtinimo.\",\n  \"components.Search.search\": \"Paieška\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Visi serialo aktoriai\",\n  \"components.RequestModal.seasonnumber\": \"{number} sezonas\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.originallanguage\": \"Originalo kalba\",\n  \"components.TvDetails.viewfullcrew\": \"Visa komanda\",\n  \"components.TvDetails.watchtrailer\": \"Žiūrėti trailerį\",\n  \"components.TvDetails.originaltitle\": \"Originalus pavadinimas\",\n  \"components.TvDetails.overview\": \"Santrauka\",\n  \"components.TvDetails.overviewunavailable\": \"Nėra santraukos.\",\n  \"i18n.requested\": \"Rezervuotas\",\n  \"i18n.advanced\": \"Pažangu\",\n  \"i18n.canceling\": \"Atšaukiama…\",\n  \"i18n.close\": \"Uždaryti\",\n  \"i18n.requesting\": \"Rezervuojama…\",\n  \"i18n.saving\": \"Saugoma…\",\n  \"i18n.settings\": \"Nustatymai\",\n  \"components.UserList.accounttype\": \"Tipas\",\n  \"i18n.areyousure\": \"Ar tu tikras?\",\n  \"i18n.cancel\": \"Atšaukti\",\n  \"i18n.all\": \"Visi\",\n  \"i18n.movies\": \"Filmai\",\n  \"i18n.next\": \"Kitas\",\n  \"i18n.pending\": \"Eilėje\",\n  \"i18n.previous\": \"Ankstesnis\",\n  \"i18n.request\": \"Rezervuoti\",\n  \"pages.oops\": \"Ups...\",\n  \"pages.returnHome\": \"Grįžti į pradžią\",\n  \"pages.pagenotfound\": \"Puslapis nerastas\",\n  \"components.IssueDetails.problemepisode\": \"Paveikti epizodai\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Atverti su komentaru\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Paveiktas epizodas\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Sezonas} other {Sezonai}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Nežinoma\",\n  \"components.IssueList.IssueItem.viewissue\": \"Peržiūrėti problemą\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Pažangiau\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Išvalyti duomenis\",\n  \"components.ManageSlideOver.opentautulli\": \"Atverti per Tautulli\",\n  \"components.ManageSlideOver.playedby\": \"Vaidino\",\n  \"components.MovieDetails.mark4kavailable\": \"Pažymėk kaip prieinamą 4k raiška\",\n  \"components.MovieDetails.markavailable\": \"Pažymėti kaip prieinamą\",\n  \"components.MovieDetails.overviewunavailable\": \"Apžvalgos nėra.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Rezervacija išpildyta\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Rezervacija atšaukta\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Rezervacija patvirtinta\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Rezervacijos procesas nepavyko\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Rezervacija laukia patvirtinimo\",\n  \"components.IssueDetails.problemseason\": \"Paveikti sezonai\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Epizodas} other {Epizodai}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Statusas\",\n  \"components.IssueDetails.reopenissue\": \"Iš naujo atverti problemą\",\n  \"components.IssueList.IssueItem.opened\": \"Atviros\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tipas\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} - {user}\",\n  \"components.PermissionEdit.autoapprove4k\": \"Auto patvirtinti 4K\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Įvyko klaida redaguojant problemos aprašymą.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Problemos aprašas redaguotas sėkmingai!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Įsivėlė klaida šalinant problemą.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Problemos statusas sėkmingai atnaujintas!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Įvyko klaida atnaujinant problemos statusą.\",\n  \"components.IssueDetails.unknownissuetype\": \"Nežinoma\",\n  \"components.IssueList.showallissues\": \"Rodyti visas problemas\",\n  \"components.IssueList.sortAdded\": \"Naujausi\",\n  \"components.IssueList.sortModified\": \"Paskutinės redaguotos\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Papildomos\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Paveikti epizodai\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Prašome pateikti detalų kilusios problemos aprašą.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Pranešti apie problemą\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Sezonas {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Pateikti problemą\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Įvyko klaida pateikiant problemą.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Problema <strong>{title}</strong> pateikta sėkmingai!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Peržiūrėti problemą\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Prašome pateikti aprašą\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Kas negerai?\",\n  \"components.IssueModal.issueOther\": \"Kita\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.LanguageSelector.languageServerDefault\": \"Numatytoji ({language})\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr kūrimas\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stabili\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Atviros problemos\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Nėra rezervacijų.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Rezervacijos\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Valdyti {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Pažymėti kaip prieinamą 4K raiška\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Pažymėti, kad visi sezonai prieinami 4K raiška\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Pažymėti, kad visi sezonai prieinami\",\n  \"components.ManageSlideOver.markavailable\": \"Pažymėti, kaip prieinamą\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {peržiūra} other {peržiūros}}\",\n  \"components.IssueDetails.toastissuedeleted\": \"Problema pašalinta sėkmingai!\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Paveikti sezonai\",\n  \"components.IssueDetails.openedby\": \"#{issueId} problema atverta {relativeTime}, {username}\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {komitas} other {komitai}} behind\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Tai negyžtamai pašalins {mediaType} tipo duomenis, įskaitant rezervacijas. {mediaServerName} bibliotekoje esančios medijos informacija bus atkurta kito skanavimo metu.\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Gauti pranešimus kai kiti vartotojai komentuoja problemą.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Gauti pranešimus kai kiti vartotojai uždaro problemą.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Problemos komentaras\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Siųsti pranešimus kai problema gauna nauja komentarą.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problema iš naujo atverta\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Siųsti pranešimus, kai problemos iš naujo atveriamos.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problema iš naujo atverta\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Siųsti pranešimus, kai problema iš naujo atveriamos.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problema išspręsta\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Siųsti pranešimus, kai problemos išspręstos.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Siųsti pranešimus, kai vartotojai pateikia naują medijos rezervaciją, kuri automatiškai patvirtina.\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Siųsti pranešimus, medijos rezervacijos patvirtinamos ranka.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Siųsti pranešimą, kai medijos rezervacijos tampa prieinamos.\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Siųsti pranešimą, kai medijos rezervacijos atmetamos.\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Siųsti pranešimą, kai medijos rezervacijos neišeina pridėti Radarr ar Sonarr.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Pranešimų tipai\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Gauti pranešimą, kai problemos, kurias tu pateikei iš naujo atveriamos.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Gauti pranešimą, kai kiti vartotojai pateikia naują medijos rezervaciją, kurie automatiškai patvirtinami.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Gauti pranešimą, kai tavo medijos rezervacija patirtinta.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Gauti pranešimą kai problema, kurią tu pateikei išsprendžiama.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Gauti pranešimą kai tavo medijos rezervacija tampa prieinama.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Gauti rezervaciją, kai tavo medijos rezervacija atšaukiama.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Gauti pranešimą, kai medijos rezervacijos nepavyksta pridėti Radarr ar Sonarr.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Gauti pranešimą kai kiti vartotojai pateikia naują medijos prašymą, kuriam reikalingas patvirtinimas.\",\n  \"components.PermissionEdit.adminDescription\": \"Pilnas administracinis rėžimas. Ignoruoti visus leidimų reikalavimus.\",\n  \"components.PermissionEdit.advancedrequest\": \"Detalesnės rezervacijos\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Sutiekti leidimus modifikuoti detalios rezervacijos pasirinkimus.\",\n  \"components.PermissionEdit.createissues\": \"Pateikti problemas\",\n  \"components.PermissionEdit.manageissues\": \"Valdyti problemas\",\n  \"components.PermissionEdit.managerequests\": \"Valdyti rezervacijas\",\n  \"components.PermissionEdit.request4kMovies\": \"Rezervuoti 4K filmus\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Sutiekti leidimus pateikti rezervacijas 4K filmams.\",\n  \"components.PermissionEdit.request4kTv\": \"Rezervuoti 4K Serialus\",\n  \"components.PermissionEdit.requestMovies\": \"Rezervuoti filmus\",\n  \"components.PermissionEdit.requestTv\": \"Rezervuoti serialus\",\n  \"components.PermissionEdit.users\": \"Valdyti vartotojus\",\n  \"components.PermissionEdit.viewissues\": \"Peržiūrėti problemas\",\n  \"components.RequestBlock.profilechanged\": \"Kokybės profilis\",\n  \"components.RequestBlock.requestoverrides\": \"Rezervacijos pakeitimai\",\n  \"components.RequestBlock.rootfolder\": \"Pirminis aplankas\",\n  \"components.RequestBlock.server\": \"Numatytasis serveris\",\n  \"components.RequestButton.approve4krequests\": \"Tvirtinti {requestCount, plural, one {4K rezervacijas} other {{requestCount} 4K rezervacijas}}\",\n  \"components.RequestButton.approverequest4k\": \"Tvirtinti 4K rezervacijas\",\n  \"components.RequestButton.approverequests\": \"Tvirtinti {requestCount, plural, one {Rezervaciją} other {{requestCount} Rezervacijas}}\",\n  \"components.RequestButton.decline4krequests\": \"Atmesti {requestCount, plural, one {4K rezervaciją} other {{requestCount} 4K rezervacijas}}\",\n  \"components.RequestButton.declinerequests\": \"Atmesti {requestCount, plural, one {rezervaciją} other {{requestCount} rezervacijas}}\",\n  \"components.RequestButton.viewrequest4k\": \"Peržiūrėti 4K rezervacijas\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} Nerasta\",\n  \"components.RequestList.RequestItem.mediaerror\": \"Susijusio pavadinimo nebeprieinama rezervacijai.\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Šis serialas yra anime.\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Kalbų profilis\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Nėra žymių.\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Rezervuoti kaip\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Pasirinkti žymę\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Žymės\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Šiam vartotojui leidžiama rezervuoti iki <strong>{limit}</strong> {type} kas <strong>{days}</strong> dienas.\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {filmas} other {filmai}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Nepakankamai sezonų rezervacijų liko\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Galite peržiūrėti rezervacijų limitų apžvalgą savo <ProfileLink>profilio puslapyje</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Galima peržiūrėti vartotojo rezervacijų limitų santrauką jų <ProfileLink>profilio puslapyje</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {rezervacija} other {rezervacijų}} liko\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Jums reikia bent <strong>{seasons}</strong> {seasons, plural, one {sezono rezervacijos} other {sezonų rezervacijos}} likučio, kad rezervuoti šį serialą.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Šiam vartootjui reikia <strong>{seasons}</strong> {seasons, plural, one {sezono rezervacijos} other {sezonų rezervacijų}}, kad rezervuoti šį serialą.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"sezonas\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {sezonas} other {sezonai}}\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Negalėjome automatiškai surasti jūsų rezervacijos. Prašau pasirinkti tinkamą variantą iš galimų.\",\n  \"components.RequestModal.approve\": \"Tvirtinti rezervaciją\",\n  \"components.RequestModal.autoapproval\": \"Automatinis patvirtinimas\",\n  \"components.RequestModal.pending4krequest\": \"\",\n  \"components.RequestModal.pendingrequest\": \"\",\n  \"components.RequestModal.requestmovies4k\": \"Rezervacijos {count} {count, plural, one {filmo} other {filmų}} 4K raiška\",\n  \"components.RequestModal.requestseasons4k\": \"Rezervuoti {seasonCount} {seasonCount, plural, one {sezoną} other {sezonus}} 4K raiška\",\n  \"components.ResetPassword.emailresetlink\": \"El. pašto atkūrimo nuoroda\",\n  \"components.ResetPassword.gobacklogin\": \"Grįžti į prisijungimo puslapį\",\n  \"components.ResetPassword.password\": \"Slaptažodis\",\n  \"components.ResetPassword.passwordreset\": \"Slaptažodžio atstatymas\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Slaptažodžio atkūrimo nuoroda bus atsiųsta pateiktu el. paštu, jei yra paskyra su kuria susijęs vartotojas.\",\n  \"components.ResetPassword.resetpassword\": \"Atstatyti slaptažodį\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Slaptažodis atstatytas sėkmingai!\",\n  \"components.ResetPassword.validationemailrequired\": \"Prašome pateikti el. pašto adresą\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Slaptažodžiai turi sutapti\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Slaptažodis per trumpas; jis turėtų būti mažiai 8 simbolių\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Privalote pateikti slaptažodį\",\n  \"components.Settings.SettingsAbout.about\": \"Apie\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Duomenų aplankas\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentacija\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Viso rezervacijų\",\n  \"components.Settings.SettingsAbout.timezone\": \"Laiko zona\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Viso medijos\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Atnaujinta\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} kešo valdymas.\",\n  \"components.Settings.SettingsAbout.version\": \"Versija\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Kešas\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Kvietimai\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Viso raktų\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Rakto dydis\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Praleisti\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Kešo vardas\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Dydis\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Paleisti dabar\",\n  \"components.Settings.SettingsLogs.filterError\": \"Klaida\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Informacija\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Perspėjimas\",\n  \"components.Settings.SettingsLogs.label\": \"Etiketė\",\n  \"components.Settings.SettingsLogs.level\": \"Rimtumas\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Rezervacija automatiškai patvirtina\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Gauti pranešimus kai kiti vartotojai atveria problemą.\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Siųsti pranešimą, kai vartotojas patiekia naują medijos rezervaciją, kuriai reikalingas patvirtinimas.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Gauti pranešimą, kai problemas, kurias tu pateikei naujai pakomentuojamos.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Gauti pranešimą, kai kiti vartotojai pateikia problemą.\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} per {quotaDays} {days}</quotaUnits>\",\n  \"components.RequestButton.approverequest\": \"Tvirtinti rezervacijas\",\n  \"components.RequestButton.declinerequest\": \"Atmesti rezervacijas\",\n  \"components.RequestButton.declinerequest4k\": \"Atmesti 4K rezervacijas\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Jūs galite rezervuoti iki <strong>{limit}</strong> {type} kas <strong>{days}</strong> dienas.\",\n  \"components.RequestModal.pendingapproval\": \"Rezervacija laukia patvirtinimo.\",\n  \"components.RequestModal.requestseasons\": \"Rezervuoti {seasonCount} {seasonCount, plural, one {sezoną} other {sezonus}}\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Suteikti automatinius patvirtinimus visoms 4K medijos rezervacijoms.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Auto-patvirtinti 4K filmus\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Įgalinti agentą\",\n  \"components.Settings.RadarrModal.add\": \"Pridėti serverį\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL pagrindas\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Pridėti naują 4K Radarr serverį\",\n  \"components.Settings.RadarrModal.createradarr\": \"Pridėti naują Radarr serverį\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Numatytasis serveris\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Redaguoti 4K Radarr serverį\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Numatyti automatinę paiešką\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Išorinė nuoroda\",\n  \"components.Settings.RadarrModal.hostname\": \"Domenas ar IP adresas\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Kinuose\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Kraunamos žymos…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Kraunami kokybės profiliai…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Kraunami šakniniai aplankai…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimalus prieinamumas\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Nėra žymių.\",\n  \"components.Settings.RadarrModal.port\": \"Portas\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Kokybės profilis\",\n  \"components.Settings.RadarrModal.released\": \"Išleisti\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Šakninis aplankas\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Pasirinkti minimalų prieinamumą\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Pasirinkti kokybės profilį\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Pasirinkti šakinį aplanką\",\n  \"components.Settings.RadarrModal.selecttags\": \"Pasirinkti žymes\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Esama\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Vėliausia\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Išleidimo data šiuo metu neprieinama.\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Leidimai\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Parsiuntimų sinchronizacijos atstatymas\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modifikuoti darbą\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Parsisiuntimų sinchronizavimas\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Dažnis\",\n  \"components.Settings.SettingsJobsCache.process\": \"Procesas\",\n  \"components.Settings.SettingsLogs.logs\": \"Logai\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Numatytieji leidimai\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Pradiniai leidimai numatyti naujiems vartotojams\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Įgalinti lokalų prisijungimą\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Leisti vartotojams prisijungti naudojantis jų el.paštu ir slaptažodžiu, vietoje Plex OAuth\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Globalus filmų rezervacijos limitas\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Įgalinti naujus Plex prisijungimus\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Leisti Plex vadotojams prisijungti praleidžiant jų importavimą\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Kažkas nepavyko išsaugant nustatymus.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Vartotojos nustatymai sėkmingai išsaugoti!\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Konfigūruoti globalius ir numatytuosius vartojų nustatymus.\",\n  \"components.Settings.SettingsUsers.users\": \"Vartotojai\",\n  \"components.Settings.SonarrModal.add\": \"Pridėti serverį\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime žymos\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime kalbos profilis\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime kokybės profilis\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime šakninis aplankas\",\n  \"components.Settings.SonarrModal.apiKey\": \"API raktas\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL pagrindas\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Numatytasis 4K serveris\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Numatytasis serveris\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Redaguoti 4K Sonarr serverį\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Redaguoti Sonarr serverį\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Išorinė nuoroda\",\n  \"components.Settings.SonarrModal.hostname\": \"Domenas ar IP adresas\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Kalbų profilis\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Kraunamos žymos…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Įkeliami kalbų profiliai…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Kraunami kokybės profiliai…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Kraunami šakniniai aplankai…\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Nėra žymių.\",\n  \"components.Settings.SonarrModal.port\": \"Portas\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Šakninis aplankas\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Pasirinkite kalbos profilį\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Pasirinkti kokybės profilį\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Pasirinkti šakinį aplanką\",\n  \"components.Settings.SonarrModal.selecttags\": \"Pasirinkti žymes\",\n  \"components.Settings.SonarrModal.server4k\": \"4K serveris\",\n  \"components.Settings.SonarrModal.servername\": \"Serverio pavadinimas\",\n  \"components.Settings.SonarrModal.ssl\": \"Naudokite SSL\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Vartotojo nustatymai\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Globalus serialų rezervacijos limitas\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Pridėti naują Sonarr serverį\",\n  \"components.Settings.SonarrModal.tags\": \"Žymės\",\n  \"components.Settings.RadarrModal.announced\": \"Paskelbti\",\n  \"components.Settings.RadarrModal.apiKey\": \"API raktas\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Numatytasis 4K serveris\",\n  \"components.Settings.RadarrModal.editradarr\": \"Redaguoti Radarr serverį\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Įjungti automatinę paiešką\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Pridėti naują 4K Sonarr serverį\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Kokybės profilis\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Sezono aplankai\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Įjungti nuskaitymą\",\n  \"components.Discover.CreateSlider.nooptions\": \"Nėra rezultatų.\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmai\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Serialai\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Nuo mažiausiai populiarių\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Nuo seniausiai išleistų\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Nuo populiariausių\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Šalinti\",\n  \"components.StatusBadge.openinarr\": \"Atverti {arr}\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Pavadinimus (A-Z) pagal abėcėlę\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Nuo aukščiausio TMDB reitingo\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# aktyvus filtras} other {# aktyvūs filtrai}}\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Pavadinimus (Z-A) nuo abėcėlės galo\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Nuo žemiausio TMDB reitingo\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# aktyvus filtras} other {# aktyvūs filtrai}}\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# aktyvus filtras} other {# aktyvūs filtrai}}\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Ieškoti žanrų…\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Nuo naujausių\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Nuo seniausiai išleistų\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Nuo aukščiausio TMDB reitingo\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Transliavimo paslaugos\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Nuo naujausių\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Nuo mažiausiai populiarių\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Nuo populiariausių\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Pavadinimus (A-Z) pagal abėcėlę\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Pavadinimus (Z-A) nuo abėcėlės galo\",\n  \"components.Discover.FilterSlideover.genres\": \"Žanrai\",\n  \"components.Discover.FilterSlideover.keywords\": \"Raktažodžiai\",\n  \"components.Discover.FilterSlideover.to\": \"iki\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Nuo žemiausio TMDB reitingo\",\n  \"components.Discover.FilterSlideover.from\": \"Nuo\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Parodymo data\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Pašalinti aktyvius filtrus\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Originali kalba\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Reitingas tarp {minValue} ir {maxValue}\",\n  \"components.Discover.moviegenres\": \"Filmų žanrai\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtrai\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Pirmo parodymo data\",\n  \"components.Discover.FilterSlideover.runtime\": \"Trukmė\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minučių trukmė\",\n  \"components.Discover.FilterSlideover.studio\": \"Studija\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB naudotojų balai\",\n  \"components.Discover.networks\": \"Tinklai\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Automatiškai patvirtinti serialą\",\n  \"components.PermissionEdit.createissuesDescription\": \"Suteikite leidimą pranešti apie medijos problemas.\",\n  \"components.RequestBlock.decline\": \"Atmesti rezervacijas\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Automatiškai patvirtinti 4K filmus\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.editrequest\": \"Redaguoti rezervaciją\",\n  \"components.RequestCard.tvdbid\": \"TVDB ID\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestBlock.edit\": \"Redaguoti rezervaciją\",\n  \"components.RequestBlock.lastmodifiedby\": \"Paskutinį kartą pakeitė\",\n  \"components.RequestBlock.requestedby\": \"Rezervuota\",\n  \"components.RequestCard.declinerequest\": \"Atmesti rezervaciją\",\n  \"components.RequestBlock.delete\": \"Ištrinti rezervaciją\",\n  \"components.RequestCard.cancelrequest\": \"Atšaukti rezervaciją\",\n  \"components.RequestBlock.requestdate\": \"Rezervacijos data\",\n  \"components.RequestCard.approverequest\": \"Tvirtinti rezervaciją\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB naudotojų balai\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Suteikite leidimą peržiūrėti neseniai pridėtos medijos sąrašą.\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} Nerasta\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tvdbid\": \"TVDB ID\",\n  \"components.StatusBadge.playonplex\": \"Groti per Plex\",\n  \"components.TitleCard.cleardata\": \"Išvalyti duomenis\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} filmai\",\n  \"components.Discover.tvgenres\": \"Serialų žanrai\",\n  \"components.PermissionEdit.viewrecent\": \"Peržiūrėti neseniai pridėtus\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TVDB ID\",\n  \"components.RequestBlock.approve\": \"Tvirtinti rezervacijas\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Ieškoti raktažodžių…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Ieškoti studijų…\",\n  \"components.Discover.CreateSlider.starttyping\": \"Pradėjus rašyti bus ieškoma.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Turite pateikti duomenų.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Turite pateikti pavadinimą.\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} serialai\",\n  \"components.Discover.resettodefault\": \"Atstatyti į numatytuosius\",\n  \"components.Discover.stopediting\": \"Nustoti redaguoti\",\n  \"components.Discover.studios\": \"Studijos\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB filmo žanras\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB filmo raktažodis\",\n  \"components.Discover.tmdbnetwork\": \"TMDB tinklas\",\n  \"components.Discover.tmdbsearch\": \"TMDB paieška\",\n  \"components.Discover.tmdbstudio\": \"TMDB studijos\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB serialo žanras\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB serialo raktažodis\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Suteikite automatinį patvirtinimą ne 4K filmų rezervacijoms.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"4k rezervacijų kolekcija\",\n  \"components.RequestModal.requestcollectiontitle\": \"Rezervacijų kolekcija\",\n  \"components.RequestModal.requestmovietitle\": \"Rezervuoti filmą\",\n  \"components.RequestModal.requestseries4ktitle\": \"Rezervuoti serialą 4K formatu\",\n  \"components.RequestModal.requestseriestitle\": \"Rezervuoti serialą\",\n  \"components.StatusBadge.managemedia\": \"Valdyti {mediaType}\",\n  \"components.TvDetails.rtaudiencescore\": \"\\\"Rotten Tomatoes\\\" žiūrovų balai\",\n  \"components.Settings.SettingsJobsCache.command\": \"Komanda\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Automatiškai patvirtinti 4K serialų rezervacijas\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Tęsti\",\n  \"components.Settings.address\": \"Adresas\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.Settings.SettingsMain.general\": \"Bendri\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Jūsų Plex grojaraštis\",\n  \"components.Settings.menuUsers\": \"Vartotojai\",\n  \"components.Settings.SettingsLogs.message\": \"Žinutė\",\n  \"components.UserList.owner\": \"Savininkas\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex grojaraštis\",\n  \"components.MovieDetails.reportissue\": \"Pranešti apie problemą\",\n  \"components.PermissionEdit.autorequest\": \"Auto rezervacija\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tipas\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rolė\",\n  \"components.MovieDetails.managemovie\": \"Tvarkyti filmą\",\n  \"components.UserList.user\": \"Vartotojas\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Savininkas\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Slaptažodis\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB filmų transliavimo paslaugos\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TV transliacijos paslaugos\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmai\",\n  \"components.Layout.Sidebar.browsetv\": \"Serialai\",\n  \"components.MovieDetails.digitalrelease\": \"Skaitmeninė premjera\",\n  \"components.MovieDetails.physicalrelease\": \"Fizinė premjera\",\n  \"components.MovieDetails.rtaudiencescore\": \"\\\"Rotten Tomatoes\\\" žiūrovų balai\",\n  \"components.MovieDetails.rtcriticsscore\": \"\\\"Rotten Tomatoes\\\" Tomatometras\",\n  \"components.MovieDetails.theatricalrelease\": \"Teatrinė premjera\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Suteikite automatinį patvirtinimą 4K filmų rezervacijoms.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Suteikite automatinį patvirtinimą 4K serialų rezervacijoms.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Sutiekti teisę prašyti 4K filmų rezervacijų.\",\n  \"components.Settings.Notifications.encryptionNone\": \"Joks\",\n  \"components.Settings.RadarrModal.tags\": \"Žymės\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Darbai\",\n  \"components.Settings.default\": \"Numatytasis\",\n  \"components.Settings.mediaTypeMovie\": \"filmas\",\n  \"components.Settings.mediaTypeSeries\": \"serialas\",\n  \"components.Settings.menuAbout\": \"Apie\",\n  \"components.Settings.menuGeneralSettings\": \"Bendri\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.notifications\": \"Pranešimai\",\n  \"components.Settings.scanning\": \"Sinchronizuojama…\",\n  \"components.Setup.continue\": \"Tęsti\",\n  \"components.Setup.finishing\": \"Baigiama…\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.TvDetails.seasonstitle\": \"Sezonai\",\n  \"components.UserList.create\": \"Sukurti\",\n  \"components.UserList.password\": \"Slaptažodis\",\n  \"components.UserList.role\": \"Rolė\",\n  \"components.UserList.totalrequests\": \"Rezervacijos\",\n  \"components.UserList.users\": \"Vartotojai\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administratorius\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Vartotojas\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"El. paštas\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Slaptažodis\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Bendri\",\n  \"components.AirDateBadge.airsrelative\": \"Premjera {relativeTime}\",\n  \"components.Discover.plexwatchlist\": \"Jūsų Plex grojaraštis\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB naudotojų balai\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Nepavyko ištrinti rėžio.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Rėžis sėkmingai ištrintas.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Pakeisti matomumą\",\n  \"components.Discover.createnewslider\": \"Sukurti naują rėžį\",\n  \"components.Discover.customizediscover\": \"Koreguoti Naršymo skiltį\",\n  \"components.Discover.updatesuccess\": \"Atnaujinti naršymo pritaikymo nustatymus.\",\n  \"components.Settings.SettingsLogs.time\": \"Laiko žyma\",\n  \"components.AirDateBadge.airedrelative\": \"Premjera {relativeTime}\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Rėžio pavadiniams\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Paskutiniai pridėti\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Suteikti automatinius patvirtinimus visoms ne 4K medijos rezervacijoms.\",\n  \"components.UserList.creating\": \"Kuriama…\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: sezonas {seasonNumber} epizodas {episodeNumber}\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Filmų rezervacijos\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Serijų rezervacijos\",\n  \"components.Layout.UserDropdown.requests\": \"Rezervacijos\",\n  \"components.Settings.email\": \"El. paštas\",\n  \"components.Settings.is4k\": \"4K\",\n  \"i18n.experimental\": \"Eksperimentinis\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Jūsų Plex grojaraštis\",\n  \"components.Discover.CreateSlider.addSlider\": \"Pridėti slankiklį\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Sukurti rėžį\",\n  \"components.Discover.CreateSlider.addfail\": \"Nepavyko sukurti naujo rėžio.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Redaguoti rėžį\",\n  \"components.Discover.CreateSlider.editfail\": \"Nepavyko redaguoti rėžio.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Sukurti naują rėžį ir išsaugoti nestandartinius naršyko nustatymus.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Redaguotas rėžį ir išsaugoti nestandartinius naršymo nustatymus.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Pateikite TMDB žanro ID\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Pateikite TMDB raktažodžio ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Pateikite TMDB tinklo ID\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Pateikite paieškos užklausą\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Pateikite TMDB studijos ID\",\n  \"components.Discover.CreateSlider.needresults\": \"Turite turėti bent 1 rezultatą.\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB vartotojų balsų skaičius\",\n  \"components.Discover.resetfailed\": \"Kažkas nepavyko atstatant į pirminius atradimo korekcijų nustatymus.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Suteikite automatinį patvirtinimą ne 4K serialų rezervacijoms.\",\n  \"components.Discover.emptywatchlist\": \"Čia bus rodoma medija, pridėta prie <PlexWatchlistSupportLink> Plex grojaraščio</PlexWatchlistSupportLink>.\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Čia bus rodoma į <PlexWatchlistSupportLink> Plex grojaraštyje </PlexWatchlistSupportLink> pridėta medija.\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Balsų skaičius nuo {minValue} iki {maxValue}\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.Discover.resetsuccess\": \"\",\n  \"components.Discover.resetwarning\": \"\",\n  \"components.Discover.updatefailed\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.imdbuserscore\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"\",\n  \"components.PermissionEdit.autorequestDescription\": \"\",\n  \"components.PermissionEdit.autorequestMovies\": \"\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"\",\n  \"components.PermissionEdit.autorequestSeries\": \"\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"\",\n  \"components.PermissionEdit.manageissuesDescription\": \"\",\n  \"components.PermissionEdit.managerequestsDescription\": \"\",\n  \"components.PermissionEdit.request4kDescription\": \"\",\n  \"components.PermissionEdit.requestDescription\": \"\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"\",\n  \"components.PermissionEdit.requestTvDescription\": \"\",\n  \"components.PermissionEdit.usersDescription\": \"\",\n  \"components.PermissionEdit.viewissuesDescription\": \"\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"\",\n  \"components.PermissionEdit.viewwatchlists\": \"\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"\",\n  \"components.QuotaSelector.tvRequests\": \"\",\n  \"components.RequestCard.unknowntitle\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"\",\n  \"components.RequestModal.requestmovie4ktitle\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.nooptions\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchGenres\": \"\",\n  \"components.Selector.searchKeywords\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchStudios\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Selector.showless\": \"\",\n  \"components.Selector.showmore\": \"\",\n  \"components.Selector.starttyping\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.Settings.Notifications.agentenabled\": \"\",\n  \"components.Settings.Notifications.allowselfsigned\": \"\",\n  \"components.Settings.Notifications.authPass\": \"\",\n  \"components.Settings.Notifications.authUser\": \"\",\n  \"components.Settings.Notifications.botAPI\": \"\",\n  \"components.Settings.Notifications.botApiTip\": \"\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"\",\n  \"components.Settings.Notifications.botUsername\": \"\",\n  \"components.Settings.Notifications.botUsernameTip\": \"\",\n  \"components.Settings.Notifications.chatId\": \"\",\n  \"components.Settings.Notifications.chatIdTip\": \"\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"\",\n  \"components.Settings.Notifications.emailsender\": \"\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.enableMentions\": \"\",\n  \"components.Settings.Notifications.encryption\": \"\",\n  \"components.Settings.Notifications.encryptionDefault\": \"\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"\",\n  \"components.Settings.Notifications.encryptionTip\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.pgpPassword\": \"\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"\",\n  \"components.Settings.Notifications.sendSilently\": \"\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"\",\n  \"components.Settings.Notifications.senderName\": \"\",\n  \"components.Settings.Notifications.smtpHost\": \"\",\n  \"components.Settings.Notifications.smtpPort\": \"\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"\",\n  \"components.Settings.Notifications.validationEmail\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"\",\n  \"components.Settings.Notifications.validationTypes\": \"\",\n  \"components.Settings.Notifications.validationUrl\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.Notifications.webhookUrl\": \"\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.server4k\": \"\",\n  \"components.Settings.RadarrModal.servername\": \"\",\n  \"components.Settings.RadarrModal.ssl\": \"\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"\",\n  \"components.Settings.RadarrModal.tagRequests\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"\",\n  \"components.Settings.SettingsAbout.outofdate\": \"\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsLogs.extraData\": \"\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"\",\n  \"components.Settings.SettingsLogs.logDetails\": \"\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"\",\n  \"components.Settings.SettingsLogs.showall\": \"\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"\",\n  \"components.Settings.SettingsMain.apikey\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"\",\n  \"components.Settings.SettingsMain.applicationurl\": \"\",\n  \"components.Settings.SettingsMain.cacheImages\": \"\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.generalsettings\": \"\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.locale\": \"\",\n  \"components.Settings.SettingsMain.originallanguage\": \"\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.activeProfile\": \"\",\n  \"components.Settings.addradarr\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.addsonarr\": \"\",\n  \"components.Settings.advancedTooltip\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.cancelscan\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.currentlibrary\": \"\",\n  \"components.Settings.default4k\": \"\",\n  \"components.Settings.deleteServer\": \"\",\n  \"components.Settings.deleteserverconfirm\": \"\",\n  \"components.Settings.enablessl\": \"\",\n  \"components.Settings.experimentalTooltip\": \"\",\n  \"components.Settings.externalUrl\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.hostname\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.librariesRemaining\": \"\",\n  \"components.Settings.manualscan\": \"\",\n  \"components.Settings.manualscanDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuJobs\": \"\",\n  \"components.Settings.menuLogs\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.menuNotifications\": \"\",\n  \"components.Settings.menuServices\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noDefault4kServer\": \"\",\n  \"components.Settings.noDefaultNon4kServer\": \"\",\n  \"components.Settings.noDefaultServer\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"\",\n  \"components.Settings.notificationsettings\": \"\",\n  \"components.Settings.notrunning\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.plexlibraries\": \"\",\n  \"components.Settings.plexlibrariesDescription\": \"\",\n  \"components.Settings.plexsettings\": \"\",\n  \"components.Settings.plexsettingsDescription\": \"\",\n  \"components.Settings.port\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.radarrsettings\": \"\",\n  \"components.Settings.restartrequiredTooltip\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scan\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.serverLocal\": \"\",\n  \"components.Settings.serverRemote\": \"\",\n  \"components.Settings.serverSecure\": \"\",\n  \"components.Settings.serverpreset\": \"\",\n  \"components.Settings.serverpresetLoad\": \"\",\n  \"components.Settings.serverpresetManualMessage\": \"\",\n  \"components.Settings.serverpresetRefreshing\": \"\",\n  \"components.Settings.serviceSettingsDescription\": \"\",\n  \"components.Settings.services\": \"\",\n  \"components.Settings.settingUpPlexDescription\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.sonarrsettings\": \"\",\n  \"components.Settings.ssl\": \"\",\n  \"components.Settings.startscan\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.tautulliApiKey\": \"\",\n  \"components.Settings.tautulliSettings\": \"\",\n  \"components.Settings.tautulliSettingsDescription\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.toastPlexConnecting\": \"\",\n  \"components.Settings.toastPlexConnectingFailure\": \"\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"\",\n  \"components.Settings.toastPlexRefresh\": \"\",\n  \"components.Settings.toastPlexRefreshFailure\": \"\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.urlBase\": \"\",\n  \"components.Settings.validationApiKey\": \"\",\n  \"components.Settings.validationHostnameRequired\": \"\",\n  \"components.Settings.validationPortRequired\": \"\",\n  \"components.Settings.validationUrl\": \"\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Settings.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.webAppUrl\": \"\",\n  \"components.Settings.webAppUrlTip\": \"\",\n  \"components.Settings.webhook\": \"\",\n  \"components.Settings.webpush\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.configureservices\": \"\",\n  \"components.Setup.finish\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.setup\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinMessage\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.Setup.welcome\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.StatusBadge.status4k\": \"\",\n  \"components.StatusChecker.appUpdated\": \"\",\n  \"components.StatusChecker.appUpdatedDescription\": \"\",\n  \"components.StatusChecker.reloadApp\": \"\",\n  \"components.StatusChecker.restartRequired\": \"\",\n  \"components.StatusChecker.restartRequiredDescription\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.Season.noepisodes\": \"\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.episodeCount\": \"\",\n  \"components.TvDetails.manageseries\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.reportissue\": \"\",\n  \"components.TvDetails.rtcriticsscore\": \"\",\n  \"components.TvDetails.seasonnumber\": \"\",\n  \"components.TvDetails.status4k\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.autogeneratepassword\": \"\",\n  \"components.UserList.autogeneratepasswordTip\": \"\",\n  \"components.UserList.bulkedit\": \"\",\n  \"components.UserList.created\": \"\",\n  \"components.UserList.createlocaluser\": \"\",\n  \"components.UserList.deleteconfirm\": \"\",\n  \"components.UserList.deleteuser\": \"\",\n  \"components.UserList.edituser\": \"\",\n  \"components.UserList.email\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importedfromplex\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.importfromplex\": \"\",\n  \"components.UserList.importfromplexerror\": \"\",\n  \"components.UserList.localLoginDisabled\": \"\",\n  \"components.UserList.localuser\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.newplexsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.nouserstoimport\": \"\",\n  \"components.UserList.passwordinfodescription\": \"\",\n  \"components.UserList.plexuser\": \"\",\n  \"components.UserList.sortCreated\": \"\",\n  \"components.UserList.sortDisplayName\": \"\",\n  \"components.UserList.sortRequests\": \"\",\n  \"components.UserList.usercreatedfailed\": \"\",\n  \"components.UserList.usercreatedfailedexisting\": \"\",\n  \"components.UserList.usercreatedsuccess\": \"\",\n  \"components.UserList.userdeleted\": \"\",\n  \"components.UserList.userdeleteerror\": \"\",\n  \"components.UserList.userfail\": \"\",\n  \"components.UserList.userlist\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.userssaved\": \"\",\n  \"components.UserList.validationEmail\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserList.validationpasswordminchars\": \"\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"\",\n  \"components.UserProfile.ProfileHeader.profile\": \"\",\n  \"components.UserProfile.ProfileHeader.settings\": \"\",\n  \"components.UserProfile.ProfileHeader.userid\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"\",\n  \"components.UserProfile.emptywatchlist\": \"\",\n  \"components.UserProfile.limit\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"components.UserProfile.movierequests\": \"\",\n  \"components.UserProfile.pastdays\": \"\",\n  \"components.UserProfile.plexwatchlist\": \"\",\n  \"components.UserProfile.recentlywatched\": \"\",\n  \"components.UserProfile.recentrequests\": \"\",\n  \"components.UserProfile.requestsperdays\": \"\",\n  \"components.UserProfile.seriesrequest\": \"\",\n  \"components.UserProfile.totalrequests\": \"\",\n  \"components.UserProfile.unlimited\": \"\",\n  \"i18n.collection\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.delimitedlist\": \"\",\n  \"i18n.restartRequired\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/nb_NO.json",
    "content": "{\n  \"components.Discover.popularmovies\": \"Populære Filmer\",\n  \"components.Discover.populartv\": \"Populære Serier\",\n  \"components.Discover.recentlyAdded\": \"Nylig lagt til\",\n  \"components.Discover.recentrequests\": \"Nylig Forespurt\",\n  \"components.Discover.trending\": \"Trender\",\n  \"components.Discover.upcoming\": \"Kommende Filmer\",\n  \"components.Discover.upcomingmovies\": \"Kommende Filmer\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Søk i Filmer & TV-serier\",\n  \"components.Layout.Sidebar.dashboard\": \"Utforsk\",\n  \"components.Layout.Sidebar.requests\": \"Forespørsler\",\n  \"components.Layout.Sidebar.settings\": \"Innstillinger\",\n  \"components.Layout.Sidebar.users\": \"Brukere\",\n  \"components.Layout.UserDropdown.signout\": \"Logg ut\",\n  \"components.MovieDetails.budget\": \"Budsjett\",\n  \"components.MovieDetails.cast\": \"Roller\",\n  \"components.MovieDetails.originallanguage\": \"Originalspråk\",\n  \"components.MovieDetails.overview\": \"Oversikt\",\n  \"components.MovieDetails.overviewunavailable\": \"Informasjon utilgjengelig.\",\n  \"components.MovieDetails.recommendations\": \"Anbefalinger\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Utgivelsesdato} other {Utgivelsesdatoer}}\",\n  \"components.MovieDetails.revenue\": \"Inntekter\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutter\",\n  \"components.MovieDetails.similar\": \"Lignende titler\",\n  \"components.PersonDetails.appearsin\": \"Finnes i\",\n  \"components.PersonDetails.ascharacter\": \"som {character}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Sesong} other {Sesonger}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Sesong} other {Sesonger}}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Sesong} other {Sesonger}}\",\n  \"components.RequestList.requests\": \"Forespørsler\",\n  \"components.RequestModal.cancel\": \"Avbryt Forespørsel\",\n  \"components.RequestModal.numberofepisodes\": \"Antall episoder\",\n  \"components.RequestModal.pendingrequest\": \"Ventende forespørsel\",\n  \"components.RequestModal.requestCancel\": \"Forespørsel for <strong>{title}</strong> kansellert.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> forespurt!\",\n  \"components.RequestModal.requestadmin\": \"Denne forespørselen vil bli godkjent automagisk.\",\n  \"components.RequestModal.requestfrom\": \"{username} sin forespørsel venter på godkjenning.\",\n  \"components.RequestModal.requestseasons\": \"Forespør {seasonCount} {seasonCount, plural, one {Sesong} other {Sesonger}}\",\n  \"components.RequestModal.season\": \"Sesong\",\n  \"components.RequestModal.seasonnumber\": \"Sesong {number}\",\n  \"components.RequestModal.selectseason\": \"Velg sesong(er)\",\n  \"components.Search.searchresults\": \"Søkeresultater\",\n  \"components.Settings.Notifications.agentenabled\": \"Aktiver Tjeneste\",\n  \"components.Settings.Notifications.authPass\": \"SMTP Passord\",\n  \"components.Settings.Notifications.authUser\": \"SMTP brukernavn\",\n  \"components.Settings.Notifications.emailsender\": \"Avsenderadresse\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP-vert\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP-port\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Du må oppgi et gyldig vertsnavn eller en IP-adresse\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Du må oppgi et gyldig port-nummer\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook-nettadresse\",\n  \"components.Settings.RadarrModal.add\": \"Legg til tjener\",\n  \"components.Settings.RadarrModal.apiKey\": \"API-nøkkel\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL Base\",\n  \"components.Settings.RadarrModal.createradarr\": \"Legg til ny Radarr-tjener\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Standard tjener\",\n  \"components.Settings.RadarrModal.editradarr\": \"Rediger Radarr-tjener\",\n  \"components.Settings.RadarrModal.hostname\": \"Vertsnavn eller IP-adresse\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimumstilgjengelighet\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Grunnmappe\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Velg minimumstilgjengelighet\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Velg en kvalitetsprofil\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Legg til en grunnmappe\",\n  \"components.Settings.RadarrModal.server4k\": \"4K-tjener\",\n  \"components.Settings.RadarrModal.servername\": \"Tjenernavn\",\n  \"components.Settings.RadarrModal.ssl\": \"Aktiver SSL\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Klarte ikke å koble til Radarr.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Koblet til Radarr!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Du må oppgi en API-nøkkel\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Du må oppgi et gyldig vertsnavn eller IP-adresse\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Du må oppgi et gyldig port-nummer\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Du må velge en kvalitetsprofil\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Du må velge en grunnmappe\",\n  \"components.Settings.SonarrModal.add\": \"Legg til tjener\",\n  \"components.Settings.SonarrModal.apiKey\": \"API-nøkkel\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL Base\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Legg til ny Sonarr-tjener\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Standard tjener\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Rediger Sonarr-tjener\",\n  \"components.Settings.SonarrModal.hostname\": \"Vertsnavn eller IP-adresse\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Grunnmappe\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Sesongmapper\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Velg en kvalitetsprofil\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Velg grunnmappe\",\n  \"components.Settings.SonarrModal.server4k\": \"4K-tjener\",\n  \"components.Settings.SonarrModal.servername\": \"Tjenernavn\",\n  \"components.Settings.SonarrModal.ssl\": \"Aktiver SSL\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Du må oppgi en API-nøkkel\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Du må oppgi et gyldig vertsnavn eller en IP-adresse\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Du må oppgi et gyldig port-nummer\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Du må velge en kvalitetsprofil\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Du må velge en grunnmappe\",\n  \"components.Settings.activeProfile\": \"Aktiv profil\",\n  \"components.Settings.addradarr\": \"Legg til Radarr-tjener\",\n  \"components.Settings.address\": \"Adresse\",\n  \"components.Settings.addsonarr\": \"Legg til Sonarr-tjener\",\n  \"components.Settings.cancelscan\": \"Avbryt skanning\",\n  \"components.Settings.currentlibrary\": \"Nåværende bibliotek: {name}\",\n  \"components.Settings.default\": \"Standard\",\n  \"components.Settings.default4k\": \"Standard 4K\",\n  \"components.Settings.deleteserverconfirm\": \"Er du sikker på at du vil slette denne tjeneren?\",\n  \"components.Settings.hostname\": \"Vertsnavn eller IP-adresse\",\n  \"components.Settings.librariesRemaining\": \"Bibliotek som gjenstår: {count}\",\n  \"components.Settings.manualscan\": \"Manuell skanning av Biblioteket\",\n  \"components.Settings.manualscanDescription\": \"Normalt vil dette kjøres kun én gang i døgnet. Seerr vil sjekke Plex oftere etter nylige tillagte titler. Hvis dette er din første gang du konfigurerer Plex vil en enkelt manuell biblioteksskanning anbefales!\",\n  \"components.Settings.menuAbout\": \"Om\",\n  \"components.Settings.menuGeneralSettings\": \"Generelt\",\n  \"components.Settings.menuJobs\": \"Oppgaver & Mellomlager\",\n  \"components.Settings.menuLogs\": \"Logger\",\n  \"components.Settings.menuNotifications\": \"Varsler\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Tjenester\",\n  \"components.Settings.notificationsettings\": \"Varsel-innstillinger\",\n  \"components.Settings.notrunning\": \"Kjører ikke\",\n  \"components.Settings.plexlibraries\": \"Plex-bibliotek\",\n  \"components.Settings.plexlibrariesDescription\": \"Bibliotekene Seerr skanner for media. Sett opp og lagre dine Plex-tilkoblingsinnstillinger; klikk deretter på knappen under hvis ingen bibliotek vises.\",\n  \"components.Settings.plexsettings\": \"Plex-innstillinger\",\n  \"components.Settings.plexsettingsDescription\": \"Sett opp innstillingene for din Plex-tjener. Seerr vil skanne de valgte bibliotekene på din Plex-tjener med jevne mellomrom for å se hvilket innhold som er tilgjengelig.\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.radarrsettings\": \"Radarr-innstillinger\",\n  \"components.Settings.sonarrsettings\": \"Sonarr-innstillinger\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Start skanning\",\n  \"components.Setup.configureservices\": \"Sett opp tjenester\",\n  \"components.Setup.continue\": \"Fortsett\",\n  \"components.Setup.finish\": \"Fullfør oppsett\",\n  \"components.Setup.finishing\": \"Fullfører…\",\n  \"components.Setup.signinMessage\": \"Start med å logge inn på din Plex-konto\",\n  \"components.Setup.welcome\": \"Velkommen til Seerr\",\n  \"components.TvDetails.cast\": \"Roller\",\n  \"components.TvDetails.originallanguage\": \"Originalspråk\",\n  \"components.TvDetails.overview\": \"Oversikt\",\n  \"components.TvDetails.overviewunavailable\": \"Informasjon utilgjengelig.\",\n  \"components.TvDetails.recommendations\": \"Anbefalinger\",\n  \"components.TvDetails.similar\": \"Lignende Serier\",\n  \"components.UserList.admin\": \"Administrator\",\n  \"components.UserList.created\": \"Opprettet\",\n  \"components.UserList.plexuser\": \"Plex-bruker\",\n  \"components.UserList.role\": \"Rolle\",\n  \"components.UserList.totalrequests\": \"Forespørsler\",\n  \"components.UserList.user\": \"Bruker\",\n  \"components.UserList.userlist\": \"Brukerliste\",\n  \"i18n.approve\": \"Godkjenn\",\n  \"i18n.approved\": \"Godkjent\",\n  \"i18n.available\": \"Tilgjengelig\",\n  \"i18n.cancel\": \"Avbryt\",\n  \"i18n.decline\": \"Avslå\",\n  \"i18n.declined\": \"Avslått\",\n  \"i18n.delete\": \"Slett\",\n  \"i18n.movies\": \"Filmer\",\n  \"i18n.partiallyavailable\": \"Delvis tilgjengelig\",\n  \"i18n.pending\": \"Venter\",\n  \"i18n.processing\": \"Behandler\",\n  \"i18n.tvshows\": \"Serier\",\n  \"i18n.unavailable\": \"Utilgjengelig\",\n  \"pages.oops\": \"Oida\",\n  \"pages.returnHome\": \"Gå hjem\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Varsel-innstillinger\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Varsler\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"<FindDiscordIdLink>ID-nummeret</FindDiscordIdLink> til din brukerkonto\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Bruker ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Bruker\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Innstillingene ble lagret!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Noe gikk galt ved lagring av innstillingene.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rolle\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtrer innhold basert på regiontilgjengelighet\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Utforskelsesregion\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex-bruker\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Eier\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtrer innhold basert på originalspråk\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Utforskelsesspråk\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Lokal bruker\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Generelle innstillinger\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Generelt\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Visningsnavn\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrator\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Kontotype\",\n  \"components.UserList.userssaved\": \"Brukertillatelsene ble lagret!\",\n  \"components.UserList.users\": \"Brukere\",\n  \"components.UserList.importfromplexerror\": \"Noe gikk galt ved importering av brukere fra Plex.\",\n  \"components.UserList.importfromplex\": \"Importer brukere fra Plex\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> {userCount, plural, one {ny bruker} other {nye brukere}} ble importert fra Plex!\",\n  \"components.Settings.menuUsers\": \"Brukere\",\n  \"components.Settings.SettingsUsers.users\": \"Brukere\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Konfigurer globale og standard brukerinnstillinger.\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Brukerinnstillinger\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Brukerinnstillingene ble lagret!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Noe gikk galt ved lagring av innstillingene.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Aktiver lokal innlogging\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Standard tilganger\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Gi tillatelse til å vise forespørsler sendt av andre brukere.\",\n  \"components.PermissionEdit.usersDescription\": \"Gi tilgang til å administrere brukere. Brukere med dette tilgangsnivået har ikke mulighet til å endre brukertilganger eller gi administratorrettigheter.\",\n  \"components.PermissionEdit.users\": \"Administrer Brukere\",\n  \"components.Layout.UserDropdown.settings\": \"Innstillinger\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Discover.upcomingtv\": \"Kommende TV-serier\",\n  \"components.Discover.discover\": \"Utforsk\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"TV-sjangere\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"TV-sjangere\",\n  \"components.Discover.StudioSlider.studios\": \"Studio\",\n  \"components.Discover.NetworkSlider.networks\": \"TV-nettverk\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Filmsjangere\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Filmsjangere\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Serier\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Serier\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} Filmer\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} Serier\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Filmer\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} Filmer\",\n  \"components.CollectionDetails.requestcollection4k\": \"Forespør samling i 4K\",\n  \"components.CollectionDetails.requestcollection\": \"Forespør samling\",\n  \"components.CollectionDetails.overview\": \"Oversikt\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Filmer\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Vis profil\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Nullstill\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Alle Roller\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Alle Roller\",\n  \"components.TvDetails.viewfullcrew\": \"Vis hele Staben\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Hele Staben\",\n  \"components.MovieDetails.viewfullcrew\": \"Vis hele Staben\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Hele Staben\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Kunne ikke lagre instillingene for Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Innstillingene for Pushbullet ble lagret!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Aktiver Tjeneste\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Tilgangsnøkkel\",\n  \"components.Search.search\": \"Søk\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Du må oppgi et passord\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Passordet er for kort; det må bestå av minimum 8 tegn\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Passord må være like\",\n  \"components.ResetPassword.validationemailrequired\": \"Du må oppgi en gyldig E-postadresse\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Passord nullstilt!\",\n  \"components.ResetPassword.resetpassword\": \"Nullstill passord\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"En passordnullstillingslenke vil bli sendt til E-postadressen dersom den er koblet mot en gyldig bruker.\",\n  \"components.ResetPassword.passwordreset\": \"Nullstill Passord\",\n  \"components.ResetPassword.password\": \"Passord\",\n  \"components.ResetPassword.gobacklogin\": \"Gå tilbake til innloggingssiden\",\n  \"components.ResetPassword.emailresetlink\": \"Send E-post med gjenopprettelseslink\",\n  \"components.ResetPassword.email\": \"E-postadresse\",\n  \"components.ResetPassword.confirmpassword\": \"Verifiser passord\",\n  \"components.RequestModal.requesterror\": \"Noe gikk galt ved sending av forespørsel.\",\n  \"components.RequestModal.requestcancelled\": \"Forespørsel for <strong>{title}</strong> kansellert.\",\n  \"components.RequestModal.pending4krequest\": \"Ventende forespørsel i 4K\",\n  \"components.RequestModal.errorediting\": \"Noe gikk galt under endring av forespørselen.\",\n  \"components.RequestModal.autoapproval\": \"Automagisk Godkjenning\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Grunnmappe\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Forespør som\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Språk-profil\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Måltjener\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Standard)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Dette er en anime-serie.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avansert\",\n  \"components.RequestList.sortModified\": \"Sist Endret\",\n  \"components.RequestList.sortAdded\": \"Nylig Lagt til\",\n  \"components.RequestList.showallrequests\": \"Vis Alle Forespørsler\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} av {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Endret\",\n  \"components.RequestList.RequestItem.failedretry\": \"Noe gikk galt mens du prøvde forespørselen på nytt.\",\n  \"components.RequestButton.viewrequest4k\": \"Vis forespørsel i 4K\",\n  \"components.RequestButton.viewrequest\": \"Vis Forespørsel\",\n  \"components.RequestButton.requestmore4k\": \"Forespør mer i 4K\",\n  \"components.RequestButton.requestmore\": \"Forespør Mer\",\n  \"components.RequestButton.declinerequests\": \"Avvis {requestCount, plural, one {Forespørsel} other {{requestCount} Forespørsler}}\",\n  \"components.RequestButton.declinerequest4k\": \"Avvis forespørsel i 4K\",\n  \"components.RequestButton.declinerequest\": \"Avvis Forespørsel\",\n  \"components.RequestButton.decline4krequests\": \"Avvis {requestCount, plural, one {Forespørsel i 4K} other {{requestCount} Forespørsler i 4K}}\",\n  \"components.RequestButton.approverequests\": \"Godkjenn {requestCount, plural, one {Forespørsel} other {{requestCount} Forespørsler}}\",\n  \"components.RequestButton.approverequest4k\": \"Godkjenn forespørsel i 4K\",\n  \"components.RequestButton.approverequest\": \"Godkjenn Forespørsel\",\n  \"components.RequestButton.approve4krequests\": \"Godkjenn {requestCount, plural, one {Forespørsel i 4K} other {{requestCount} Forespørsler i 4K}}\",\n  \"components.RequestBlock.server\": \"Måltjener\",\n  \"components.RequestBlock.rootfolder\": \"Grunnmappe\",\n  \"components.RequestBlock.requestoverrides\": \"Overstyrer forespørsel\",\n  \"components.RequestBlock.profilechanged\": \"Kvalitetsprofil\",\n  \"components.RegionSelector.regionServerDefault\": \"Standard {{region}}\",\n  \"components.RegionSelector.regionDefault\": \"Alle Regioner\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.crewmember\": \"Stab\",\n  \"components.PersonDetails.birthdate\": \"Født {birthdate}\",\n  \"components.PersonDetails.alsoknownas\": \"Også kjent som: {names}\",\n  \"components.PermissionEdit.viewrequests\": \"Vis Forespørsler\",\n  \"components.PermissionEdit.requestDescription\": \"Gi tilgang til å forespørre matriale som ikke er i 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Gi tilgang til å forespørre serier i 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"Forespør Serier i 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Gi tilgang til å forespørre filmer i 4K.\",\n  \"components.PermissionEdit.request4kMovies\": \"Forespør Filmer i 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Gi tillatelse til å forespørre matriale i 4K.\",\n  \"components.PermissionEdit.request4k\": \"Forespør i 4K\",\n  \"components.PermissionEdit.request\": \"Forespør\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Gi tilgang til å administrere forespørsler. Alle forespørsler utført av en bruker med denne tilgangen vil automagisk bli godkjent.\",\n  \"components.PermissionEdit.managerequests\": \"Administrer Forespørsler\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Godkjenn serieforespørsler som ikke er i 4K automagisk.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Godkjenn serieforespørsler automagisk\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Godkjenn filmforespørsler som ikke er i 4K automagisk.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Godkjenn filmforespørsler automagisk\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Godkjenn alle forespørsler som ikke er i 4K automagisk.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Godkjenn serieforespørsler i 4K automagisk.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Automagisk godkjenning av serier i 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Godkjenn filmforespørsler i 4K automagisk.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Automagisk godkjenning av filmer i 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Godkjenn alle forespørsler av 4K automagisk.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Godkjenn 4K Automagisk\",\n  \"components.PermissionEdit.autoapprove\": \"Godkjenn Automagisk\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Gi tilgang til å endre avanserte forespørsler.\",\n  \"components.PermissionEdit.advancedrequest\": \"Avanserte Forespørsler\",\n  \"components.PermissionEdit.adminDescription\": \"Full administrator tilgang. Overstyrer alle andre tillatelser.\",\n  \"components.PermissionEdit.admin\": \"Administrator\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Forespørsel Feilet\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Bli varslet når en forespørsel om nytt matriale blir avvist.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Forespørsel Avvist\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Forespørsel Tilgjengelig\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Forespørsel Godkjent\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Forespørsel Automagisk Godkjent\",\n  \"components.MovieDetails.watchtrailer\": \"Se Trailer\",\n  \"components.MovieDetails.markavailable\": \"Merk som Tilgjengelig\",\n  \"components.MovieDetails.mark4kavailable\": \"Marker som Tilgjengelig i 4K\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Vis mer\",\n  \"components.Login.validationpasswordrequired\": \"Du må skrive et passord\",\n  \"components.Login.validationemailrequired\": \"Du må bruke en gyldig E-postadresse\",\n  \"components.Login.signinwithplex\": \"Bruk din Plex-konto\",\n  \"components.Login.signinwithoverseerr\": \"Bruk {applicationTitle}-konto\",\n  \"components.Login.signinheader\": \"Logg inn for å fortsette\",\n  \"components.Login.signingin\": \"Logger inn…\",\n  \"components.Login.signin\": \"Logg inn\",\n  \"components.Login.password\": \"Passord\",\n  \"components.Login.loginerror\": \"Noe gikk galt under innlogging.\",\n  \"components.Login.forgotpassword\": \"Glemt passord?\",\n  \"components.Login.email\": \"E-postadresse\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Volum Mount <code>{appDataPath}</code> er ikke konfigurert korrekt. All data vil slettes når containeren stoppes eller startes på nytt.\",\n  \"i18n.requested\": \"Forespurt\",\n  \"components.RequestModal.requestedited\": \"Redigerte forespørsel for <strong>{title}</strong>!\",\n  \"components.RequestModal.alreadyrequested\": \"Allerede forespurt\",\n  \"components.RequestList.RequestItem.requested\": \"Forespurt\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Bli varslet når nytt matriale blir forespurt og krever godkjenning.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Forespørsel venter Godkjenning\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Bli varslet når forespurt matriale ikke kan bli lagt til i Radarr eller Sonarr.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Bli varslet når forespurt matriale blir tilgjengelig.\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Bli varslet når forespurt matriale blir manuelt godkjent.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Bli varslet når nytt matriale blir forespurt og forespørselen blir automagisk godkjent.\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.tvshow\": \"Serie\",\n  \"components.UserProfile.seriesrequest\": \"Serieforespørsler\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Begrensning av Serieforespørseler\",\n  \"components.TvDetails.showtype\": \"Serietype\",\n  \"i18n.notrequested\": \"Ikke forespurt\",\n  \"components.QuotaSelector.unlimited\": \"Ubegrenset\",\n  \"components.MovieDetails.originaltitle\": \"Originaltittel\",\n  \"i18n.all\": \"Alle\",\n  \"components.UserList.deleteconfirm\": \"Er du sikker på at du ønsker å slette denne brukeren? All forespørseldata for denne brukeren vil bli slettet.\",\n  \"components.UserList.autogeneratepassword\": \"Generer passord automagisk\",\n  \"components.Settings.SettingsLogs.showall\": \"Vis all logg\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr mellomlagrer forespørsler til eksterne APIer for å optimalisere ytelsen samt unngå unødvendige API-kall.\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Godta selvsignerte sertifikater\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Vi klarte ikke å koble denne serien automagisk. Vennligst velg riktig serie under.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Denne brukeren har tillatelse til å forespørre <strong>{limit}</strong> {type} hver <strong>{days}.</strong> dag.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Du har tillatelse til å forespørre <strong>{limit}</strong> {type} hver <strong>{days}.</strong> dag.\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Global begrensning av Serieforespørseler\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Denne brukeren trenger minst <strong>{seasons}</strong> gjenværende {seasons, plural, one {sesongforespørsel} other {sesongforespørsler}} for å sende en forespørsel for denne serien.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Du trenger minst <strong>{seasons}</strong> gjenværende {seasons, plural, one {sesongforespørsel} other {sesongforespørsler}} for å sende en forespørsel for denne serien.\",\n  \"i18n.advanced\": \"Avansert\",\n  \"i18n.experimental\": \"Eksperimentelt\",\n  \"i18n.movie\": \"Film\",\n  \"components.UserProfile.movierequests\": \"Filmforespørsler\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Begrensning av Filmforespørseler\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Global begrensning av Filmforespørseler\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {filmer}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studio}}\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Oppgaver\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Oppgave\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} stanset.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Tøm mellomlager\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Avbryt\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Navn på mellomlager\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Bom\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Treff\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Slettet mellomlager for {cachename}.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Mellomlager\",\n  \"components.Settings.SettingsAbout.version\": \"Versjon\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Totalt antall tilgjengelig\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Forespørsler totalt\",\n  \"components.Settings.SettingsAbout.timezone\": \"Tidssone\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Diskuter på GitHub\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Få hjelp\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentasjon\",\n  \"components.Settings.SettingsAbout.about\": \"Om\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Vis på GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Vis endringslogg\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Endringslogg\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Utgivelser\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Utgivelsesdata er for øyeblikket utilgjengelig.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Siste versjon\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Nåværende versjon\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Du må oppgi et tjenernavn\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Du må velge en minimum tilgjengelighet\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Base URL kan ikke slutte med en skråstrek\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Nettadressen må starte med en skråstrek\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"Nettadressen kan ikke slutte med en skråstrek\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Du må oppgi en gyldig nettadresse\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Test tilkoblingen for å laste inn grunnmapper\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Test tilkoblingen for å laste inn kvalitetsprofiler\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Aktiver skanning\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Laster grunnmapper…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Laster kvalitetsprofiler…\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Ekstern nettadresse\",\n  \"components.Settings.Notifications.validationUrl\": \"Du må oppgi en gyldig nettadresse\",\n  \"components.Settings.Notifications.validationEmail\": \"Du må oppgi en gyldig E-postadresse\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Du må oppgi en gyldig prat ID\",\n  \"components.Settings.Notifications.senderName\": \"Avsendernavn\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Send varsler uten lyd\",\n  \"components.Settings.Notifications.sendSilently\": \"Send lydløst\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Privat PGP-nøkkel\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP-passord\",\n  \"components.Settings.Notifications.chatId\": \"Chat ID\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Aktiver Tjeneste\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Du må oppgi en gyldig nettadresse\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Aktiver Tjeneste\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Aktiver Tjeneste\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Applikasjon/API-nøkkel\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Du må oppgi en tilgangsnøkkel\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {sesong} other {sesonger}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"sesong\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Ingen} other {<strong>#</strong>}} gjenværende {type} {remaining, plural, one {forespørsel} other {forespørsler}}\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Du kan se en oppsummering av denne brukerens forespørselbegrensninger på <ProfileLink>profilsiden deres</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Du kan se en oppsummering av dine forespørselbegrensninger på <ProfileLink>profilsiden</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Ikke nok gjenværende sesongforespørsler\",\n  \"components.UserList.owner\": \"Eier\",\n  \"components.UserList.sortDisplayName\": \"Visningsnavn\",\n  \"components.UserList.sortRequests\": \"Antall forespørsler\",\n  \"components.UserList.sortCreated\": \"Opprettelsesdato\",\n  \"components.UserList.createlocaluser\": \"Opprett lokal bruker\",\n  \"components.UserList.accounttype\": \"Kontotype\",\n  \"i18n.edit\": \"Rediger\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Rediger innstillinger\",\n  \"components.UserList.edituser\": \"Rediger brukertilganger\",\n  \"components.UserList.bulkedit\": \"Rediger flere\",\n  \"components.Settings.SettingsLogs.extraData\": \"Mer data\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Kopier til utklippstavlen\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Kopierte loggmelding til utklippstavlen.\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Ukjent jobb\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr-skann\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Kjør nå\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr-skann\",\n  \"components.Settings.SettingsJobsCache.process\": \"Prosess\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Sjekk for nye titler i Plex-biblioteket\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Full Skanning av Plex-biblioteket\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Kjøres igjen\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Type\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} startet.\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Oppgaver & Mellomlager\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Nullstill nedlastningssynkronisering\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Nedlastningssynkronisering\",\n  \"components.Settings.SettingsJobsCache.command\": \"Kommando\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Du må oppgi en gyldig nettadresse\",\n  \"components.Settings.scanning\": \"Synkroniserer…\",\n  \"components.Settings.scan\": \"Synkroniser bibliotek\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Varsler\",\n  \"components.Settings.enablessl\": \"Aktiver SSL\",\n  \"components.Settings.email\": \"E-post\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Du må oppgi et tjenernavn\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Du må velge en språkprofil\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Koblet til Sonarr!\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Test tilkobling for å laste inn merker\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Test tilkobling for å laste inn grunnmapper\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Test tilkobling for å laste inn kvalitetsprofiler\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Test tilkobling for å laste inn språkprofiler\",\n  \"components.Settings.SonarrModal.tags\": \"Merker\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Aktiver skanning\",\n  \"components.Settings.SonarrModal.selecttags\": \"Velg merker\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Velg språkprofil\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Ingen merker.\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Laster grunnmapper…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Laster kvalitetsprofiler…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Laster språkprofiler…\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Laster merker…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Språkprofil\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Ekstern nettadresse\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Rediger 4K Sonarr-tjener\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Standard 4K-tjener\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Legg til ny 4K Sonarr-tjener\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime-grunnmappe\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime-kvalitetsprofil\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime-språkprofil\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime-merker\",\n  \"components.Settings.SettingsLogs.time\": \"Tidspunkt\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Fortsett\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Sett på pause\",\n  \"components.Settings.SettingsLogs.message\": \"Rapport\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Du kan også se disse loggene direkte i <code>stdout</code>, eller i <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.logs\": \"Logger\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Logg-detaljer\",\n  \"components.Settings.SettingsLogs.level\": \"Alvorlighetsgrad\",\n  \"components.Settings.SettingsLogs.label\": \"Merkelapp\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Detaljert\",\n  \"components.Settings.SettingsLogs.filterError\": \"Feil\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Varsel\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Test tilkobling for å laste inn merker\",\n  \"components.Settings.RadarrModal.tags\": \"Merker\",\n  \"components.Settings.RadarrModal.selecttags\": \"Velg merker\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Ingen merker.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Laster merker…\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Rediger 4K Radarr-tjener\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Standard tjener for 4K\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Innstillingene for Telegram ble lagret!\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Innstillingene for E-post ble lagret!\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Innstillingene for Discord ble lagret!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Innstillingene for Webhook ble lagret!\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook-nettadresse\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Innstillingene for Slack ble lagret!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Innstillingene for Pushover ble lagret!\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Merker\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Velg merker\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Ingen merker.\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Alle språk\",\n  \"components.LanguageSelector.languageServerDefault\": \"Standard ({language})\",\n  \"i18n.areyousure\": \"Er du sikker?\",\n  \"i18n.failed\": \"Mislykket\",\n  \"components.UserList.usercreatedfailed\": \"Noe gikk galt ved oppretting av brukeren.\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Kunne ikke hente listen over Plex-tjenere.\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Kunne ikke koble til Plex.\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Kunne ikke koble til Sonarr.\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Kunne ikke lagre instillingene for Telegram.\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Kunne ikke lagre instillingene for E-post.\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Kunne ikke lagre instillingene for Discord.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Kunne ikke lagre instillingene for Webhook.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Kunne ikke lagre instillingene for Slack.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Kunne ikke lagre instillingene for Pushover.\",\n  \"i18n.requesting\": \"Forespør…\",\n  \"i18n.request4k\": \"Forespør i 4K\",\n  \"i18n.request\": \"Forespør\",\n  \"components.UserProfile.totalrequests\": \"Totalt antall forespørsler\",\n  \"components.UserProfile.requestsperdays\": \"{limit} gjenstår\",\n  \"components.UserProfile.recentrequests\": \"Nylig Forespurt\",\n  \"components.Settings.noDefaultServer\": \"Minst én {serverType} server må være definert som standard for at {mediaType}-forespørsler skal kunne bli håndtert.\",\n  \"components.RequestModal.pendingapproval\": \"Forespørselen din avventer godkjenning.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} Finnes ikke\",\n  \"components.RequestCard.deleterequest\": \"Slett forespørsel\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Slett forespørsel\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Avbryt Forespørsel\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} Finnes ikke\",\n  \"components.Settings.noDefaultNon4kServer\": \"Dersom du har én {serverType} server for både ikke-4K og 4K-media (eller hvis du kun laster ned 4K-innhold), skal {serverType} server <strong>IKKE</strong> være huket av som en 4K server.\",\n  \"components.Settings.noDefault4kServer\": \"En 4K {serverType} server må være satt som standard for at brukere skal kunne forspørre 4K {mediaType}.\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Standard tilganger gitt til nye brukere\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Bruk STARTTLS om tilgjengelig\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Generelt\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Standard ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Overstyr globale begrensninger\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Visningsspråk\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Du må oppgi en gyldig bruker ID\",\n  \"components.UserProfile.ProfileHeader.userid\": \"BrukerID: {userid}\",\n  \"components.UserProfile.unlimited\": \"Ubegrenset\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Gå til Pushbullet sine<PushbulletSettingsLink>kontoinnstillinger</PushbulletSettingsLink> for opprette en tilgangsnøkkel\",\n  \"components.RequestModal.edit\": \"Rediger forespørsel\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Forespurt\",\n  \"components.RequestList.RequestItem.editrequest\": \"Rediger forespørsel\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{sesonger} per {quotaDays} {dager}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {sesong} other {sesonger}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {filmer}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{filmer} per {quotaDays} {dager}</quotaUnits>\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {dag} other {dager}}\",\n  \"components.PermissionEdit.requestTvDescription\": \"Gi tilgang til å forespørre serier som ikke er i 4K.\",\n  \"components.PermissionEdit.requestTv\": \"Forespør Serier\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Gi tilgang til å forespørre filmer som ikke er i 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Forespør Filmer\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Bli varslet når andre brukere forespør nytt matriale hvor forespørselen krever godkjenning.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Bli varslet når dine forespørsler ikke kan bli lagt til Radarr eller Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Bli varslet når dine forespørsler blir avvist.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Bli varslet når andre brukere forespør nytt matriale og forespørselen er automagisk godkjent.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Bli varslet når dine forespørsler blir godkjent.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Bli varslet når dine forespørsler blir tilgjengelig.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Varselstyper\",\n  \"components.MovieDetails.showmore\": \"Vis mer\",\n  \"components.MovieDetails.showless\": \"Vis mindre\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stable\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Develop\",\n  \"components.Layout.VersionStatus.outofdate\": \"Utdatert\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} etter\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Visningsspråk\",\n  \"components.RequestCard.failedretry\": \"Noe gikk galt mens du prøvde forespørselen på nytt.\",\n  \"components.DownloadBlock.estimatedtime\": \"Estimert {time}\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Tillatelsene ble lagret!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Passord laget!\",\n  \"i18n.save\": \"Lagre\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Du må velge minst én varseltype\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Du må velge minst én varseltype\",\n  \"components.Settings.Notifications.validationTypes\": \"Du må velge minst én varseltype\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Varsler\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Aktiver Tjeneste\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Du må velge minst én varseltype\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Du må oppgi en gyldig tilgangsnøkkel\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Du må velge minst én varseltype\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.closeissueandcomment\": \"Lukk med Kommentar\",\n  \"components.IssueModal.issueOther\": \"Annet\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Forespørsler\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Administrer {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Marker som Tilgjengelig i 4K\",\n  \"components.ManageSlideOver.openarr\": \"Vis i {arr}\",\n  \"components.MovieDetails.streamingproviders\": \"Tilgjengelig på\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Bli varslet når avvik blir gjenåpnet av andre brukere.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Bli varslet når avvik blir utbedret av andre brukere.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Avvikskommentar\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Avviksrapport for <strong>{title}</strong> er nå sendt inn!\",\n  \"components.IssueModal.issueAudio\": \"Lyd\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Endre Beskrivelse\",\n  \"components.IssueModal.issueVideo\": \"Bilde\",\n  \"components.ManageSlideOver.tvshow\": \"serier\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Gi tillatelse til å vise avvik som er rapportert av andre brukere.\",\n  \"components.IssueDetails.allepisodes\": \"Alle Episoder\",\n  \"components.IssueDetails.playonplex\": \"Spill av med Plex\",\n  \"components.IssueDetails.problemseason\": \"Gjelder Sessong\",\n  \"components.IssueDetails.reopenissue\": \"Åpne Avvik\",\n  \"components.IssueDetails.commentplaceholder\": \"Legg til kommentar…\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Episode} other {Episoder}}\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Åpne Avvik med kommentar\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Beskrivelsen av avviket ble regdigert!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Avviket ble slettet!\",\n  \"components.IssueDetails.toaststatusupdated\": \"Statusen til Avviket ble endret!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Se Avvik\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Du må skrive en forklaring av problemet\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Hva er problemet?\",\n  \"components.IssueModal.issueSubtitles\": \"Undertekster\",\n  \"components.Layout.Sidebar.issues\": \"Avvik\",\n  \"components.ManageSlideOver.downloadstatus\": \"Nedlastningsstatus\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Fjern all Info\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Åpne et Avvik\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Ingen forespørsler.\",\n  \"components.ManageSlideOver.markavailable\": \"Marker som Tilgjengelig\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.ManageSlideOver.openarr4k\": \"Åpne i 4K {arr}\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Bli varslet når avviket får en ny kommentar.\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Bli varslet når avvik blir rapportert.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Avvik gjenåpnet\",\n  \"components.PermissionEdit.viewissues\": \"Vis Avvik\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Avvik Rapportert\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Vil du slette denne kommentaren?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Slett Kommentar\",\n  \"components.IssueDetails.IssueComment.edit\": \"Rediger Kommentar\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Publisert {relativeTime} av {username} (Endret)\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Slett Avviket\",\n  \"components.IssueDetails.comments\": \"Kommentarer\",\n  \"components.IssueDetails.deleteissue\": \"Slett Avvik\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Vil du slette dette Avviket?\",\n  \"components.IssueDetails.episode\": \"Episode {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Avvik\",\n  \"components.IssueDetails.lastupdated\": \"Sist oppdatert\",\n  \"components.IssueDetails.leavecomment\": \"Kommentar\",\n  \"components.IssueDetails.openinarr\": \"Vis i {arr}\",\n  \"components.IssueDetails.season\": \"Sesong {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Noe gikk galt under redigering av avviksbeskrivelsen.\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Noe gikk galt under sletting av avviket.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Noe gikk galt under endring av statusen til Avviket.\",\n  \"components.IssueDetails.unknownissuetype\": \"Ukjent\",\n  \"components.IssueDetails.issuetype\": \"Type\",\n  \"components.IssueDetails.nocomments\": \"Ingen Kommentar.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} ble registert {relativeTime} av {username}\",\n  \"components.IssueDetails.openin4karr\": \"Vis i 4K {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Spill av i 4K med Plex\",\n  \"components.IssueDetails.problemepisode\": \"Gjelder Episode\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Sessong} other {Sessonger}}\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Bli varslet når andre brukere kommenterer på avvik.\",\n  \"components.IssueDetails.closeissue\": \"Lukk Avvik\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Alle Sesonger\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Bli varslet når avviket du sendte inn er utbedret.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Bli varslet når andre brukere rapporterer avvik.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Gi tillatelse til å rapportere avvik.\",\n  \"components.RequestModal.requestmovies4k\": \"Forespør {count} {count, plural, one {Film} other {Filmer}} i 4K\",\n  \"components.UserList.email\": \"E-postadresse\",\n  \"components.UserList.validationpasswordminchars\": \"Passordet er for kort; det må bestå av minimum 8 tegn\",\n  \"i18n.status\": \"Status\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Aktiver Tjeneste\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Kunne ikke lagre instillingene for Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Innstillingene for Gotify ble lagret!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify mislykkes med å sende test-varsel.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Gotify sender test-varsel…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Test-varsel ble sendt med Gotify!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Applikasjon/API-nøkkel\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Vertsadresse\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Du må oppgi en gyldig nettadresse\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"Nettadressen kan ikke slutte med en skråstrek\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Du må velge minst én varseltype\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Register en tjeneste</ApplicationRegistrationLink> til bruk sammen med Seerr\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet mislykkes med å sende test-varsel.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Pushbullet sender test-varsel…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Test-varsel ble sendt med Pushover!\",\n  \"components.Settings.Notifications.encryptionTip\": \"I de fleste tilfeller bruker Implisitt TLS port 465 og STARTTLS bruker port 587\",\n  \"components.Settings.RadarrModal.inCinemas\": \"På Kino\",\n  \"components.Settings.validationHostnameRequired\": \"Du må oppgi et gyldig vertsnavn eller IP-adresse\",\n  \"components.UserProfile.pastdays\": \"{type} (siste {days} dager)\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Du må oppgi en gyldig prat ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Du må oppgi en gyldig bruker- eller gruppe nøkkel\",\n  \"i18n.back\": \"Tilbake\",\n  \"i18n.close\": \"Avbryt\",\n  \"i18n.canceling\": \"Avbryter…\",\n  \"i18n.showingresults\": \"Viser <strong>{from}</strong> til <strong>{to}</strong> av <strong>{total}</strong> resultater\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Du må oppgi en applikasjon/API-nøkkel\",\n  \"i18n.next\": \"Neste\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Endre Oppgave\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Ny Frekvens\",\n  \"components.TvDetails.firstAirDate\": \"Første gang sendt\",\n  \"i18n.deleting\": \"Sletter…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Innstillingene for E-post ble lagret!\",\n  \"components.UserList.creating\": \"Oppretter…\",\n  \"components.Settings.is4k\": \"4K\",\n  \"pages.somethingwentwrong\": \"Noe gikk galt\",\n  \"pages.serviceunavailable\": \"Tjenste Utilgjenglig\",\n  \"components.UserList.create\": \"Opprett\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Alltid bruk STARTTLS\",\n  \"components.RequestModal.requestmovies\": \"Forespør {count} {count, plural, one {Film} other {Filmer}}\",\n  \"components.Settings.Notifications.encryption\": \"Krypteringsmetode\",\n  \"i18n.import\": \"Importer\",\n  \"i18n.importing\": \"Importerer…\",\n  \"components.Setup.setup\": \"Oppsett\",\n  \"components.TvDetails.network\": \"TV-nettverk\",\n  \"components.Settings.validationPortRequired\": \"Du må oppgi et gyldig port-nummer\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Gi tillatelse til å administre avvik.\",\n  \"i18n.retrying\": \"Prøver på nytt…\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Aktiver Automagisk Søk\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Du må oppgi en gyldig PGP-privatnøkkel\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Totalt antall nøkkler\",\n  \"components.MovieDetails.productioncountries\": \"Produksjonsland\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"Nettadressen kan ikke slutte med en skråstrek\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Register en tjeneste</ApplicationRegistrationLink> til bruk sammen med {applicationTitle}\",\n  \"components.Settings.serverRemote\": \"eksternt\",\n  \"components.Settings.serverpreset\": \"Tjener\",\n  \"components.Settings.serverpresetLoad\": \"Trykk for å laste tilgjenglige tjenere\",\n  \"components.Settings.serverpresetManualMessage\": \"Manuelt oppsett\",\n  \"components.Settings.serverpresetRefreshing\": \"Henter tjenere…\",\n  \"components.Settings.settingUpPlexDescription\": \"For å sette opp Plex, kan du enten fylle inn instillingene manuelt eller du kan velge en tjener hentet fra <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Trykk på knappen til høyre for å hente oversikten over tilgjenglige tjenere.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover mislykkes å sende test-varsel.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Pushover sender test-varsel…\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Status\",\n  \"components.IssueList.IssueItem.issuetype\": \"Type\",\n  \"components.IssueList.IssueItem.opened\": \"Registert\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Alle Episoder\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episode {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Gjelder Episode\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Tillegg\",\n  \"components.IssueList.sortAdded\": \"Nylig Lagt til\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Gjelder Sesong\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Vennligst gi en forklaring av problemet som oppsto, gjerne så detaljert som mulig.\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Sesong {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Rapporter Avvik\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Registrer Avvik\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Noe gikk galt under registering av avviket.\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Bli varslet hvis avviket blir gjennåpnet.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Avvik Utbedret\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Bli varslet når avviket er utbedret.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Bli varslet når ditt innsendte avvik får nye kommentarer.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Bli varslet når avvik du sendte inn blir gjenåpnet.\",\n  \"components.PermissionEdit.createissues\": \"Rapporter Avvik\",\n  \"components.RequestModal.requestseasons4k\": \"Forspør {seasonCount} {seasonCount, plural, one {Sesong} other {Sesonger}} i 4K\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Bruker- eller Gruppe-nøkkel\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook-adresse\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Bruk Implisitt TLS\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Legg til ny Radarr-tjener for 4K\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Utdatert\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Base URL må starte med en skråstrek\",\n  \"components.Settings.services\": \"Tjenester\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Listen med Plex-tjenere ble hentet!\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutter\",\n  \"components.TvDetails.nextAirDate\": \"Neste Sendedato\",\n  \"components.TvDetails.watchtrailer\": \"Vis Trailer\",\n  \"components.TvDetails.streamingproviders\": \"Tilgjengelig på\",\n  \"components.UserList.deleteuser\": \"Slett Bruker\",\n  \"components.UserList.localLoginDisabled\": \"Muligheten for <strong>Aktiver lokal innlogging </strong> er deaktivert.\",\n  \"components.UserList.userfail\": \"Noe gikk galt ved endring av bruker-tillatelsene.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Innstillingene for Discord ble lagret!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Innstillingene for Pushbullet ble lagret!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Send varsler uten lyd\",\n  \"i18n.loading\": \"Laster…\",\n  \"i18n.saving\": \"Lagerer…\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Opprettet {joindate}\",\n  \"components.Settings.serverLocal\": \"lokal\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Tilgangsnøkkel\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Du må skrive en melding\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Publisert {relativeTime} av {username}\",\n  \"components.IssueList.issues\": \"Avvik\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr kjører enkelte vedlikeholdsoppgaver med fast tidsintervall, men de kan også velges å kjøres manuelt under. En oppgave som blir trigget manuelt forstyrrer ikke det faste tidsintervalet.\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Tillatelser\",\n  \"components.IssueDetails.IssueDescription.description\": \"Beskrivelse\",\n  \"components.IssueDetails.allseasons\": \"Alle Sesonger\",\n  \"components.PermissionEdit.manageissues\": \"Administrer Avvik\",\n  \"components.RequestModal.approve\": \"Godkjenn Forespørsel\",\n  \"components.RequestModal.requestApproved\": \"Forespørsel av <strong>{title}</strong> er godkjent!\",\n  \"components.RequestModal.selectmovies\": \"Velg Film(er)\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Du må oppgi et PGP passord\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"i18n.testing\": \"Tester…\",\n  \"components.Settings.serverSecure\": \"sikker\",\n  \"components.Settings.RadarrModal.announced\": \"Annonsert\",\n  \"components.Settings.RadarrModal.released\": \"Utgitt\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Oppdatert\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Oppgaven ble endret!\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Hver {jobScheduleHours}. time\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Hvert {jobScheduleMinutes}. minutt\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Tilllat brukere å logge på med e-postadresse og passord, istedenfor med {mediaServerName} OAuth\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Tillat {mediaServerName} brukere å logge inn uten å være importert på forhånd\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Du må oppgi en gyldig nettadresse\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Base URL kan ikke slutte med en skråstrek\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.mediaTypeSeries\": \"serier\",\n  \"components.Settings.toastPlexConnecting\": \"Forsøker å koble til Plex…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Forbindelse til Plex ble opprettet!\",\n  \"components.Settings.toastPlexRefresh\": \"Henter listen over tjenere fra Plex…\",\n  \"components.TvDetails.episodeRuntime\": \"Spilletid Episode\",\n  \"components.TvDetails.productioncountries\": \"Produksjonsland\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Sesong} other {# Sesonger}}\",\n  \"components.TvDetails.originaltitle\": \"Originaltittel\",\n  \"components.TvDetails.anime\": \"Animasjon\",\n  \"components.UserList.localuser\": \"Lokal bruker\",\n  \"components.UserList.password\": \"Passord\",\n  \"components.UserList.nouserstoimport\": \"Det er ingen brukere å importere fra Plex.\",\n  \"components.UserList.userdeleteerror\": \"Noe gikk galt under sletting av brukeren.\",\n  \"components.UserList.passwordinfodescription\": \"Sett opp en nettadresse for Seerr og aktiver E-postvarsler for å kunne sende ut automagisk genererte passord.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Denne E-postadressen er allerede i bruk av en annen bruker.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Kunne ikke lagre instillingene for Discord.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-post\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Kunne ikke lagre instillingene for E-post.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Applikasjon/API-nøkkel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Kunne ikke lagre instillingene for Pushbullet.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Gå til Pushbullet <PushbulletSettingsLink>kontoinnstillinger</PushbulletSettingsLink> for opprette en tilgangsnøkkel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Bruker- eller Gruppe-nøkkel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Kunne ikke lagre instillingene for Pushover.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Innstillingene for Pushover ble lagret!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Send lydløst\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Du må oppgi en gyldig offentlig PGP-nøkkel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Innstillingene for Telegram ble lagret!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Du må oppgi en gyldig applikasjon/API-nøkkel\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Passord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Gjenta Passord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Du har ikke tillatelse til å endre denne brukerens passord.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nytt Passord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Nåværende Passord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Noe gikk galt under lagring av passordet.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Du må bekrefte det nye passordet\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Passordene må stemme overens\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Tillatelser\",\n  \"components.UserProfile.limit\": \"{remaining} av {limit}\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Du må oppgi et nytt passord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Du må oppgi ditt nåværende passord\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Passord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Passordet er for kort; det må bestå av minimum 8 tegn\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Du kan ikke endre dine egne tillatelser.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Noe gikk galt under lagring av instillingene.\",\n  \"i18n.noresults\": \"Ingen Resultater.\",\n  \"i18n.open\": \"Åpen\",\n  \"i18n.previous\": \"Forrige\",\n  \"i18n.resolved\": \"Utbedret\",\n  \"i18n.retry\": \"Prøv på nytt\",\n  \"i18n.view\": \"Vis\",\n  \"pages.pagenotfound\": \"Side ble ikke funnet\",\n  \"i18n.test\": \"Test\",\n  \"i18n.usersettings\": \"Bruker-instillinger\",\n  \"pages.internalservererror\": \"Intern Tjenerfeil\",\n  \"i18n.resultsperpage\": \"Vis {pageSize} resultater per side\",\n  \"i18n.settings\": \"Innstillinger\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Ukjent\",\n  \"components.IssueList.IssueItem.viewissue\": \"Vis Avvik\",\n  \"components.IssueList.showallissues\": \"Vis alle Avvik\",\n  \"components.IssueList.sortModified\": \"Sist Endret\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} av {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Gjelder Episode\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Test-varsel ble sendt med Pushbullet!\",\n  \"components.Settings.Notifications.encryptionNone\": \"Ingen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Kunne ikke lagre instillingene for Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chat ID\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Aktiver ny {mediaServerName}-pålogging\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Aktiver Automagisk Søk\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Konfigurer og aktiver varslingstjenester.\",\n  \"components.UserList.autogeneratepasswordTip\": \"Send et automagisk generet passord til bruken på E-post\",\n  \"components.UserList.usercreatedsuccess\": \"Bruker opprettet!\",\n  \"components.UserList.userdeleted\": \"Bruker slettet!\",\n  \"components.UserList.validationEmail\": \"Du må oppgi en gyldig E-postadresse\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Du må oppgi en tilgangsnøkkel\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Web push mislykkes med å sende test-varsel.\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Lag en <WebhookLink>inkommende Webhook</WebhookLink> integrasjon\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack mislykkes med å sende test-varsel.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Slack sender test-varsel…\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Innstillingene for Web Push ble lagret!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Web Push sender test-varsel…\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Hvordan bruke Variabler\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Test-varsel ble sendt med Webhook!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Du må oppgi en gyldig JSON payload\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Bruk<OpenPgpLink>OpenPGP</OpenPgpLink> til å signere krypterte E-postmeldinger\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord mislykkes med å sende test-varsel.\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Web-tjeneste</WebAppLink> nettadresse\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Offentlig PGP-nøkkel\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Du har ikke tillatelse til å endre innstillingene til denne brukeren.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Test-varsel ble sendt med Web Push!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Kunne ikke lagre instillingene for Web Push.\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Lag en <DiscordWebhookLink>webhook integasjon</DiscordWebhookLink> med din tjener\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Lag en bot</CreateBotLink> til bruk sammen med Seerr\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Test-varsel ble sendt med Slack!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Bruk <OpenPgpLink>OpenPGP</OpenPgpLink> til å kryptere E-post\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Webhook mislykkes med å sende test-varsel.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Telegram sender test-varsel…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Webhook sender test-varsel…\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Bruk<OpenPgpLink>OpenPGP</OpenPgpLink> til å signere krypterte E-postmeldinger\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Du må oppgi en gyldig bruker- eller gruppe nøkkel\",\n  \"components.Settings.webAppUrlTip\": \"Alternativt send brukerne direkte til Web-Tjenesten på din tjener istedenfor Plex sin Web-tjener\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"For å kunne sende Web Push varsler, må Seerr kommunisere over HTTPS.\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Test-varsel ble sendt med Telegram!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Mislykkes å sende test-varsel med E-post.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Sender test-varsel med E-post…\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Discord sender test-varsel…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Test-varsel ble sendt med Discord!\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Test-varsel ble sendt med E-post!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram mislykkes med å sende test-varsel.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Noe gikk galt under lagring av oppgaven.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Din konto har ikke noe passord på nåværende tidspunkt. Lag et passord under for å kunne logge inn med din E-postadresse som \\\"lokal-bruker\\\".\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Noe gikk galt under lagring av passordet. Var ditt nåværende passord skrevet korrekt?\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON payload tilbakestilt!\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Din 30-tegns <UsersGroupsLink>bruker- eller gruppe-nøkkel</UsersGroupsLink>\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Verdistørrelse\",\n  \"components.Settings.serviceSettingsDescription\": \"Konfigurer dine {serverType}tjener(e) nedenfor. Du kan koble til flere forskellige {serverType}tjenere men kun to av dem kan markeres som standard (en som ikke er 4K og en 4K). Administratorer kan endre hvilken tjener som brukes før godkjennelse av nye forespørsler.\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Dette vil slette all data for denne tittelen uten mulighet for å bli gjennopprettet, det inkluderer alle forespørsler, avvik osv. Hvis denne tittelen finnes i ditt {mediaServerName} bibliotek vil medieinformasjon bli opprettet på nytt under neste skanning.\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Autorisasjonshode\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Nøkkelstørrelse\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON Payload\",\n  \"components.Settings.Notifications.botAPI\": \"\\\"Bot\\\" Autorisasjonsnøkkel\",\n  \"components.Settings.Notifications.botUsername\": \"\\\"Bot\\\" Brukernavn\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Nettdresse for \\\"Bot\\\" avatar\",\n  \"components.Settings.Notifications.chatIdTip\": \"Start en prat med din \\\"Bot\\\", legg til <GetIdBotLink>@get_id_bot</GetIdBotLink> og send kommandoen <code>/my_id</code>\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Du må oppgi en gyldig autorisasjonsnøkkel for \\\"Boten\\\"\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Tillat brukere å kunne starte en prat med din \\\"Bot\\\" for å konfigurere deres egne varsler\",\n  \"components.UserList.newplexsigninenabled\": \"Innstillingen <strong>Aktiver ny Plex-pålogging</strong> er nå aktivert. Plex-brukere med tilgang til biblioteket trenger ikke å importeres for å kunne logge på første gang.\",\n  \"components.Settings.Notifications.enableMentions\": \"Aktiver \\\"Mentions\\\"\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Du bruker nå <code>develop</code> utgaven av Seerr. Denne er kun anbefalt for dem som bidrar i utviklingen eller assisterer med testing av nye funksjoner.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Din 30-tegns <UsersGroupsLink>bruker- eller gruppe-ID</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Denne brukerkontoen har for øyeblikket ikke et passord. Konfigurer et passord nedenfor så denne kontoen kan logge inn som en \\\"lokal bruker.\\\"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Start en prat</TelegramBotLink>, legg til <GetIdBotLink>@get_id_bot</GetIdBotLink> og benytt <code>/my_id</code> kommandoen\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avansert\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Media\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K Media\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Marker alle sesonger som Tilgjenglig\",\n  \"components.ManageSlideOver.opentautulli\": \"Åpne i Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Siste {days, number} Dager\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Noe gikk galt under lagring av innstillingene for Tautulli.\",\n  \"components.Settings.urlBase\": \"URL Base\",\n  \"components.Settings.validationApiKey\": \"Du må oppgi en API-nøkkel\",\n  \"components.Settings.validationUrl\": \"Du må oppgi en gyldig nettadresse\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Nettadressen må starte med en skråstrek\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Innstillingene for Tautulli ble lagret!\",\n  \"components.UserProfile.recentlywatched\": \"Sist Sett\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Marker alle sesonger som Tilgjenglig i 4K\",\n  \"components.ManageSlideOver.playedby\": \"Sett av\",\n  \"components.Settings.externalUrl\": \"Ekstern nettadresse\",\n  \"components.Settings.tautulliSettings\": \"Tautulli innstillinger\",\n  \"components.Settings.tautulliApiKey\": \"API-nøkkel\",\n  \"components.Settings.validationUrlTrailingSlash\": \"Nettadressen kan ikke slutte med en skråstrek\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"Base URL kan ikke slutte med en skråstrek\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {avspilling} other {avspillinger}}\",\n  \"components.ManageSlideOver.alltime\": \"Totalt\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Kanal-merke\",\n  \"components.Settings.tautulliSettingsDescription\": \"Seerr kan hente avspillingshistorikk for Plex fra Tautulli. Fyll inn innstilingene under for å etablere kommunikasjon med din Tautulli-tjener.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord Bruker ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Du må oppgi en gyldig Bruker ID for Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"<FindDiscordIdLink>ID-nummeret</FindDiscordIdLink> til din brukerkonto\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Datakatalog\",\n  \"components.RequestBlock.languageprofile\": \"Språkprofil\",\n  \"components.MovieDetails.digitalrelease\": \"Digital utgivelse\",\n  \"components.MovieDetails.physicalrelease\": \"Fysisk Utgivelse\",\n  \"components.MovieDetails.theatricalrelease\": \"Kinopremiere\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Oppdatert\",\n  \"components.PermissionEdit.viewrecent\": \"Vis nylig lag til\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Gi tillatelse til å vise nylig lagt til.\",\n  \"components.Settings.deleteServer\": \"Slett {serverType} tjener\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Vennligst klikk her for å laste applikasjonen på nytt.\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Din Visningsliste\",\n  \"components.Discover.plexwatchlist\": \"Din Visningsliste\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Få varsler når nye medieforspørsler automatisk sendes inn for elementer på Din Visningsliste.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Forespør Serier Automagisk\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Gi tilgang til å automatisk sende film forespørsler som ikke er i 4K via Din Visningsliste.\",\n  \"components.PermissionEdit.autorequest\": \"Auto-Forespørsel\",\n  \"components.PermissionEdit.autorequestDescription\": \"Gi tilgang til å automatisk sende forespørsler som ikke er i 4K via Din Plex Visningsliste.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Forespør Serier Automagisk\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex Visningsliste\",\n  \"components.MovieDetails.managemovie\": \"Administrer Film\",\n  \"components.MovieDetails.reportissue\": \"Rapporter Avvik\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Forespørsel Automagisk Forespurt\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Gi tilgang til å automatisk sende serie forespørsler som ikke er i 4K via Din Visningsliste.\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Vis Detaljer\",\n  \"components.AirDateBadge.airedrelative\": \"Sendt {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Sendes {relativeTime}\",\n  \"components.MovieDetails.rtaudiencescore\": \"Publikumspoeng for Rotten Tomatoes\",\n  \"components.PermissionEdit.viewwatchlists\": \"Vis Visningsliste\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Gi tilgang til å vise andre brukere sin Visningsliste.\",\n  \"components.RequestBlock.requestdate\": \"Tidspunkt for Forespørsel\",\n  \"components.RequestBlock.requestedby\": \"Forespurt av\",\n  \"components.RequestCard.approverequest\": \"Godkjenn Forespørsel\",\n  \"components.RequestCard.cancelrequest\": \"Avbryt Forespørsel\",\n  \"components.RequestCard.declinerequest\": \"Avvis Forespørsel\",\n  \"components.RequestCard.editrequest\": \"Rediger forespørsel\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Filmforespørsler\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Serieforespørsler\",\n  \"components.Layout.UserDropdown.requests\": \"Forespørsler\",\n  \"components.MovieDetails.tmdbuserscore\": \"Brukerpoeng for TMDb\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatometer for Rotten Tomatoes\",\n  \"components.RequestBlock.edit\": \"Rediger forespørsel\",\n  \"components.RequestBlock.lastmodifiedby\": \"Sist endret av\",\n  \"components.RequestBlock.approve\": \"Godkjenn Forespørsel\",\n  \"components.RequestBlock.delete\": \"Slett forespørsel\",\n  \"components.RequestBlock.decline\": \"Avvis Forespørsel\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} Finnes ikke\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDb ID\",\n  \"i18n.restartRequired\": \"Omstart Nødvendig\",\n  \"components.TitleCard.cleardata\": \"Fjern all Info\",\n  \"components.TitleCard.tmdbid\": \"TMDb ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Forespør Filmer Automagisk\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Synkronisering av Plex Visningsliste\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr må startes på nytt for at de nye innstillingene skal tre i kraft\",\n  \"components.TvDetails.reportissue\": \"Rapporter Avvik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Automagisk forespør serier som ligger på <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Forespør Serier Automagisk\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Automagisk forespør filmer som ligger på <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.plexwatchlist\": \"Plex Visningsliste\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDb ID\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Start tjeneren på nytt for å ta i bruk de nye innstillingene.\",\n  \"components.StatusChecker.restartRequired\": \"Omstart av tjener nødvendig\",\n  \"components.TitleCard.tvdbid\": \"TheTVDb ID\",\n  \"components.Settings.experimentalTooltip\": \"Aktivering av denne innstillingen kan føre til uventet oppførsel av programmet\",\n  \"components.Settings.advancedTooltip\": \"Feil konfigurering av denne innstillingen kan føre til defekt funksjonalitet\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Noe gikk galt under henting av data for denne sesongen.\",\n  \"components.StatusChecker.reloadApp\": \"Last inn {applicationTitle} på nytt\",\n  \"components.StatusBadge.playonplex\": \"Spill av med {mediaServerName}\",\n  \"components.StatusBadge.openinarr\": \"Vis i {arr}\",\n  \"components.StatusBadge.managemedia\": \"Administrer {mediaType}\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Episode} other {# Episoder}}\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomatometer for Rotten Tomatoes\",\n  \"components.TvDetails.manageseries\": \"Administrer Serie\",\n  \"components.TvDetails.rtaudiencescore\": \"Publikumspoeng for Rotten Tomatoes\",\n  \"components.TvDetails.seasonstitle\": \"Sesonger\",\n  \"components.TvDetails.seasonnumber\": \"Sesong {seasonNumber}\",\n  \"components.RequestModal.requestseriestitle\": \"Forespør Serier\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.tmdbuserscore\": \"Brukerpoeng for TMDb\",\n  \"components.RequestModal.requestseries4ktitle\": \"Forespør Serier i 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Forespør Film\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Forespør hele samlingen i 4K\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Forespør Film i 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Forespør hele samlingen\",\n  \"components.Discover.emptywatchlist\": \"Matriale som du legger til via <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> vil dukke opp her.\",\n  \"components.UserProfile.emptywatchlist\": \"Matriale som du legger til via <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink> vil dukke opp her.\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Vi klarte ikke å koble denne serien med et søkbart treff.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Nåværende frekvens\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Generelle Innstillinger\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"E-postadressen er ugyldig.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"En e-postadresse er påkrevd.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Et passord er påkrevd.\",\n  \"components.Settings.SettingsMain.general\": \"Generell\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Denne e-postadressen er allerede i bruk!\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Feil ved sletting av skyveknappen.\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Tittel (A-Å) Stigende\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Originalspråk\",\n  \"components.TitleCard.watchlistError\": \"Noe gikk galt, prøv på nytt.\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Nylig Lagt Til\",\n  \"components.MovieDetails.addtowatchlist\": \"Legg til i Visningsliste\",\n  \"components.Discover.CreateSlider.addSlider\": \"Legg til Skyveknapp\",\n  \"components.Discover.resetwarning\": \"Tilbakestill alle skyveknapper til standardinnstillinger. Dette sletter også egendefinerte skyveknapper!\",\n  \"components.Layout.Sidebar.browsetv\": \"Serier\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Angi et søkeord\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Populæritet Stigende\",\n  \"components.UserProfile.localWatchlist\": \"{username}'s Visningsliste\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Utgivelsesdato\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmer\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Du må oppgi en applikasjonstittel\",\n  \"components.TitleCard.addToWatchList\": \"Legg til i Visningsliste\",\n  \"components.TvDetails.watchlistError\": \"Noe gikk galt, prøv på nytt.\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Lag Egendefinert Skyveknapp\",\n  \"components.Discover.CreateSlider.addfail\": \"Feil ved opprettelse av ny skyveknapp.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Rediger Skyveknapp\",\n  \"components.Discover.FilterSlideover.keywords\": \"Nøkkelord\",\n  \"components.Discover.resettodefault\": \"Tilbakestill til standard\",\n  \"components.Login.username\": \"Brukernavn\",\n  \"components.MovieDetails.removefromwatchlist\": \"Fjern fra Visningsliste\",\n  \"components.MovieDetails.watchlistError\": \"Noe gikk galt, prøv på nytt.\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Applikasjonstittel\",\n  \"components.TvDetails.addtowatchlist\": \"Legg til i Visningsliste\",\n  \"components.TvDetails.removefromwatchlist\": \"Fjern Fra Visningsliste\",\n  \"components.UserList.importfrommediaserver\": \"Importer {mediaServerName} Brukere\",\n  \"components.Discover.CreateSlider.editfail\": \"Feil ved redigering av skyveknapp.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Ingen treff.\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Søk i sjangre…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Søk etter nøkkelord…\",\n  \"components.Discover.CreateSlider.starttyping\": \"Begynn å skrive for å søke.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Du må oppgi en tittel.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Filmer\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmer\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Populæritet Fallende\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Utgivelsesdato Stigende\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Utgivelsesdato Fallende\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Tittel (A-Å) Stigende\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Tittel (A-Å) Fallende\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB-vurdering Stigende\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB-vurdering Fallende\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Sletting av skyveknappen var vellykket.\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Fjern\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Serier\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Første sendingsdato Stigende\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Første sendingsdato Fallende\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Populæritet Stigende\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Populæritet Fallende\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Tittel (A-Å) Fallende\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB-vurdering Stigende\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB-vurdering Fallende\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Serier\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Tøm Aktive Filtre\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtre\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Første Sendingsdato\",\n  \"components.Discover.FilterSlideover.from\": \"Fra\",\n  \"components.Discover.FilterSlideover.genres\": \"Sjangere\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Din Visningsliste\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Vurderinger mellom {minValue} og {maxValue}\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Oppgi en TMDB nøkkelord-ID\",\n  \"components.Discover.FilterSlideover.certification\": \"Aldersklassifisering\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Eksluder søkeord\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Medier lagt til din <PlexWatchlistSupportLink>Plex Se Senere-liste</PlexWatchlistSupportLink> vises her.\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Kommende serier\",\n  \"components.Discover.createnewslider\": \"Opprett ny slider\",\n  \"components.Discover.customizediscover\": \"Tilpass Oppdag-siden\",\n  \"components.Discover.moviegenres\": \"Filmsjangrer\",\n  \"components.Discover.networks\": \"Nettverk\",\n  \"components.Discover.resetfailed\": \"Noe gikk galt ved lagring av instillinger for oppdagelsestilpassing.\",\n  \"components.Discover.resetsuccess\": \"Innstillinger for tilpassing av Oppdag-siden er nullstilt.\",\n  \"components.Discover.stopediting\": \"Avslutt redigering\",\n  \"components.Discover.studios\": \"Studioer\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB Filmsjanger\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB film-nøkkelord\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB Film-strømmetjenester\",\n  \"components.Discover.tmdbnetwork\": \"TMDB nettverk\",\n  \"components.Discover.tmdbsearch\": \"TMDB Søk\",\n  \"components.Discover.tmdbstudio\": \"TMDB Studio\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB Seriesjanger\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB Serie-nøkkelord\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB TV-strømmetjenester\",\n  \"components.Discover.tvgenres\": \"Seriesjangrer\",\n  \"components.Discover.updatefailed\": \"Noe gikk galt ved lagring av tilpassing av Utforsk.\",\n  \"components.Discover.updatesuccess\": \"\",\n  \"components.DownloadBlock.formattedTitle\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.imdbuserscore\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.RequestCard.unknowntitle\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.nooptions\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchGenres\": \"\",\n  \"components.Selector.searchKeywords\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchStudios\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Selector.showless\": \"\",\n  \"components.Selector.showmore\": \"\",\n  \"components.Selector.starttyping\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.tagRequests\": \"\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsMain.apikey\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.locale\": \"\",\n  \"components.Settings.SettingsMain.originallanguage\": \"\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.Season.noepisodes\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"i18n.collection\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Discover.FilterSlideover.runtime\": \"Spilletid\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minutt spilletid\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"\",\n  \"components.Settings.SettingsMain.applicationurl\": \"\",\n  \"components.Settings.SettingsMain.cacheImages\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.StatusBadge.seasonepisodenumber\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Opprettet en ny slider og lagret innstillinger for Oppdagelsestilpassing.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Redigerte slider og lagret innstillinger for Oppdagelsestilpassing.\",\n  \"components.Discover.CreateSlider.needresults\": \"Du må ha minst ett resultat.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Oppgi en TMDB Sjanger ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Oppgi en TMDB nettverks-ID\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Oppgi en TMDB studio-ID\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Søk etter studio…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Slidernavn\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Du må oppgi en dataverdi.\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Aktivt filter} other {# Aktive filter}}\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Bytt synlighet\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Aktivt filter} other {# Aktive filter}}\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Aktivt filter} other {# Aktive filter}}\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streamingtjenester\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB Brukerscore\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB Brukerstemmer\",\n  \"components.Discover.FilterSlideover.to\": \"Til\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Antal stemmer mellom {minValue} og {maxValue}\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\",\n  \"component.BlocklistBlock.blocklistdate\": \"Skjult dato\",\n  \"component.BlocklistBlock.blocklistedby\": \"Skjult av\",\n  \"component.BlocklistModal.blocklisting\": \"Skjul\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> er ikke skjult.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Administrer skjult medie.\",\n  \"components.Blocklist.blocklistdate\": \"dato\",\n  \"components.Blocklist.blocklistedby\": \"{date} av {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Skjulingsinstillinger\",\n  \"components.Blocklist.filterManual\": \"Manuell\",\n  \"components.Blocklist.mediaName\": \"Navn\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb-ID\",\n  \"components.Blocklist.mediaType\": \"Type\",\n  \"components.Blocklist.showAllBlocklisted\": \"Vil alle skjulte medier\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Kunne ikke koble til {services}. Noe information kan være utilgjengelig.\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Skjulte tagger\"\n}\n"
  },
  {
    "path": "src/i18n/locale/nl.json",
    "content": "{\n  \"components.Discover.popularmovies\": \"Populaire films\",\n  \"components.Discover.populartv\": \"Populaire series\",\n  \"components.Discover.recentlyAdded\": \"Onlangs toegevoegd\",\n  \"components.Discover.recentrequests\": \"Recente aanvragen\",\n  \"components.Discover.trending\": \"Trending\",\n  \"components.Discover.upcoming\": \"Verwachte films\",\n  \"components.Discover.upcomingmovies\": \"Verwachte films\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Films en series zoeken\",\n  \"components.Layout.Sidebar.dashboard\": \"Ontdekken\",\n  \"components.Layout.Sidebar.requests\": \"Aanvragen\",\n  \"components.Layout.Sidebar.settings\": \"Instellingen\",\n  \"components.Layout.Sidebar.users\": \"Gebruikers\",\n  \"components.Layout.UserDropdown.signout\": \"Afmelden\",\n  \"components.MovieDetails.budget\": \"Budget\",\n  \"components.MovieDetails.cast\": \"Cast\",\n  \"components.MovieDetails.originallanguage\": \"Oorspronkelijke taal\",\n  \"components.MovieDetails.overview\": \"Overzicht\",\n  \"components.MovieDetails.overviewunavailable\": \"Overzicht niet beschikbaar.\",\n  \"components.MovieDetails.recommendations\": \"Aanbevelingen\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Verschijningsdatum} other {Verschijningsdata}}\",\n  \"components.MovieDetails.revenue\": \"Omzet\",\n  \"components.MovieDetails.runtime\": \"{minutes} minuten\",\n  \"components.MovieDetails.similar\": \"Vergelijkbare titels\",\n  \"components.PersonDetails.appearsin\": \"Verschijningen\",\n  \"components.PersonDetails.ascharacter\": \"als {character}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Seizoen} other {Seizoenen}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Seizoen} other {Seizoenen}}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Seizoen} other {Seizoenen}}\",\n  \"components.RequestList.requests\": \"Aanvragen\",\n  \"components.RequestModal.cancel\": \"Aanvraag annuleren\",\n  \"components.RequestModal.numberofepisodes\": \"Aantal afleveringen\",\n  \"components.RequestModal.pendingrequest\": \"Aanvraag in behandeling\",\n  \"components.RequestModal.requestCancel\": \"Aanvraag voor <strong>{title}</strong> geannuleerd.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> is aangevraagd!\",\n  \"components.RequestModal.requestadmin\": \"Deze aanvraag zal automatisch goedgekeurd worden.\",\n  \"components.RequestModal.requestfrom\": \"De aanvraag van {user} is in afwachting van goedkeuring.\",\n  \"components.RequestModal.requestseasons\": \"{seasonCount} {seasonCount, plural, one {seizoen} other {seizoenen}} aanvragen\",\n  \"components.RequestModal.season\": \"Seizoen\",\n  \"components.RequestModal.seasonnumber\": \"Seizoen {number}\",\n  \"components.RequestModal.selectseason\": \"Seizoenen selecteren\",\n  \"components.Search.searchresults\": \"Zoekresultaten\",\n  \"components.Settings.Notifications.agentenabled\": \"Dienst inschakelen\",\n  \"components.Settings.Notifications.authPass\": \"SMTP-wachtwoord\",\n  \"components.Settings.Notifications.authUser\": \"SMTP-gebruikersnaam\",\n  \"components.Settings.Notifications.emailsender\": \"E-mailadres afzender\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP-host\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP-poort\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Je moet een geldig(e) hostnaam of IP-adres opgeven\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Je moet een geldig poortnummer opgeven\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.RadarrModal.add\": \"Server toevoegen\",\n  \"components.Settings.RadarrModal.apiKey\": \"API-sleutel\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL-basis\",\n  \"components.Settings.RadarrModal.createradarr\": \"Nieuwe Radarr-server toevoegen\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Standaardserver\",\n  \"components.Settings.RadarrModal.editradarr\": \"Radarr-server wijzigen\",\n  \"components.Settings.RadarrModal.hostname\": \"Hostnaam of IP-adres\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimale beschikbaarheid\",\n  \"components.Settings.RadarrModal.port\": \"Poort\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Kwaliteitsprofiel\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Hoofdmap\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Minimale beschikbaarheid selecteren\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Kwaliteitsprofiel selecteren\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Hoofdmap selecteren\",\n  \"components.Settings.RadarrModal.server4k\": \"4K-server\",\n  \"components.Settings.RadarrModal.servername\": \"Servernaam\",\n  \"components.Settings.RadarrModal.ssl\": \"SSL gebruiken\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Kon niet verbinden met Radarr.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Succesvol verbonden met Radarr!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Je moet een API-sleutel opgeven\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Je moet een geldige hostnaam of geldig IP-adres opgeven\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Je moet een geldig poortnummer opgeven\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Je moet een kwaliteitsprofiel selecteren\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Je moet een hoofdmap selecteren\",\n  \"components.Settings.SonarrModal.add\": \"Server toevoegen\",\n  \"components.Settings.SonarrModal.apiKey\": \"API-sleutel\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL-basis\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Nieuwe Sonarr-server toevoegen\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Standaardserver\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Sonarr-server wijzigen\",\n  \"components.Settings.SonarrModal.hostname\": \"Hostnaam of IP-adres\",\n  \"components.Settings.SonarrModal.port\": \"Poort\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Kwaliteitsprofiel\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Hoofdmap\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Seizoensmappen\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Kwaliteitsprofiel selecteren\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Hoofdmap selecteren\",\n  \"components.Settings.SonarrModal.server4k\": \"4K-server\",\n  \"components.Settings.SonarrModal.servername\": \"Servernaam\",\n  \"components.Settings.SonarrModal.ssl\": \"SSL gebruiken\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Je moet een API-sleutel opgeven\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Je moet een geldige hostnaam of geldig IP-adres opgeven\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Je moet een geldig poortnummer opgeven\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Je moet een kwaliteitsprofiel selecteren\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Je moet een hoofdmap selecteren\",\n  \"components.Settings.activeProfile\": \"Actief profiel\",\n  \"components.Settings.addradarr\": \"Radarr-server toevoegen\",\n  \"components.Settings.address\": \"Adres\",\n  \"components.Settings.addsonarr\": \"Sonarr-server toevoegen\",\n  \"components.Settings.cancelscan\": \"Scan annuleren\",\n  \"components.Settings.currentlibrary\": \"Huidige bibliotheek: {name}\",\n  \"components.Settings.default\": \"Standaard\",\n  \"components.Settings.default4k\": \"Standaard 4K\",\n  \"components.Settings.deleteserverconfirm\": \"Weet je zeker dat je deze server wilt verwijderen?\",\n  \"components.Settings.hostname\": \"Hostnaam of IP-adres\",\n  \"components.Settings.librariesRemaining\": \"Resterende bibliotheken: {count}\",\n  \"components.Settings.manualscan\": \"Handmatige bibliotheekscan\",\n  \"components.Settings.manualscanDescription\": \"Normaliter wordt dit eenmaal per 24 uur uitgevoerd. Seerr zal de lijst met onlangs toegevoegde media op je Plex-server vaker controleren. Als dit de eerste keer is dat je Plex instelt, wordt aanbevolen eenmalig een handmatige, volledige bibliotheekscan uit te voeren!\",\n  \"components.Settings.menuAbout\": \"Over\",\n  \"components.Settings.menuGeneralSettings\": \"Algemeen\",\n  \"components.Settings.menuJobs\": \"Taken en cache\",\n  \"components.Settings.menuLogs\": \"Logboeken\",\n  \"components.Settings.menuNotifications\": \"Meldingen\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Diensten\",\n  \"components.Settings.notificationsettings\": \"Meldingsinstellingen\",\n  \"components.Settings.notrunning\": \"Niet actief\",\n  \"components.Settings.plexlibraries\": \"Plex-bibliotheken\",\n  \"components.Settings.plexlibrariesDescription\": \"De bibliotheken die Seerr scant op titels. Stel je Plex-verbinding in en sla ze op. Klik daarna op de onderstaande knop als er geen bibliotheken staan.\",\n  \"components.Settings.plexsettings\": \"Plex-instellingen\",\n  \"components.Settings.plexsettingsDescription\": \"Configureer de instellingen voor je Plex-server. Seerr scant je Plex-bibliotheken om te zien welke inhoud beschikbaar is.\",\n  \"components.Settings.port\": \"Poort\",\n  \"components.Settings.radarrsettings\": \"Radarr-instellingen\",\n  \"components.Settings.sonarrsettings\": \"Sonarr-instellingen\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Scan starten\",\n  \"components.Setup.configureservices\": \"Diensten configureren\",\n  \"components.Setup.continue\": \"Doorgaan\",\n  \"components.Setup.finish\": \"Installatie voltooien\",\n  \"components.Setup.finishing\": \"Voltooien…\",\n  \"components.Setup.signinMessage\": \"Ga aan de slag door je aan te melden\",\n  \"components.Setup.welcome\": \"Welkom bij Seerr\",\n  \"components.TvDetails.cast\": \"Cast\",\n  \"components.TvDetails.originallanguage\": \"Oorspronkelijke taal\",\n  \"components.TvDetails.overview\": \"Overzicht\",\n  \"components.TvDetails.overviewunavailable\": \"Overzicht niet beschikbaar.\",\n  \"components.TvDetails.recommendations\": \"Aanbevelingen\",\n  \"components.TvDetails.similar\": \"Vergelijkbare series\",\n  \"components.UserList.admin\": \"Beheerder\",\n  \"components.UserList.created\": \"Lid geworden\",\n  \"components.UserList.plexuser\": \"Plex-gebruiker\",\n  \"components.UserList.role\": \"Rol\",\n  \"components.UserList.totalrequests\": \"Aanvragen\",\n  \"components.UserList.user\": \"Gebruiker\",\n  \"components.UserList.userlist\": \"Gebruikerslijst\",\n  \"i18n.approve\": \"Goedkeuren\",\n  \"i18n.approved\": \"Goedgekeurd\",\n  \"i18n.available\": \"Beschikbaar\",\n  \"i18n.cancel\": \"Annuleren\",\n  \"i18n.decline\": \"Weigeren\",\n  \"i18n.declined\": \"Geweigerd\",\n  \"i18n.delete\": \"Verwijderen\",\n  \"i18n.movies\": \"Films\",\n  \"i18n.partiallyavailable\": \"Deels beschikbaar\",\n  \"i18n.pending\": \"In behandeling\",\n  \"i18n.processing\": \"Verwerken\",\n  \"i18n.tvshows\": \"Series\",\n  \"i18n.unavailable\": \"Niet beschikbaar\",\n  \"pages.oops\": \"Oeps\",\n  \"pages.returnHome\": \"Terug naar de startpagina\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Volledige cast\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Volledige cast van de serie\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Instellingen voor e-mailmeldingen opgeslagen!\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Instellingen voor e-mailmeldingen konden niet opgeslagen worden.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Instellingen voor Discord-meldingen opgeslagen!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Instellingen voor Discord-meldingen konden niet opgeslagen worden.\",\n  \"components.Settings.validationPortRequired\": \"Je moet een geldig poortnummer opgeven\",\n  \"components.Settings.validationHostnameRequired\": \"Je moet een geldig(e) hostnaam of IP-adres opgeven\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Je moet een servernaam opgeven\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Je moet een servernaam opgeven\",\n  \"components.Settings.SettingsAbout.version\": \"Versie\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Totaal aantal aanvragen\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Totaal aantal media\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub-discussies\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Test verbinding om hoofdmappen te laden\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Test verbinding om kwaliteitsprofielen te laden\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Hoofdmappen laden…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Kwaliteitsprofielen laden…\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Ondersteuning krijgen\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Je moet een minimale beschikbaarheid selecteren\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Test verbinding om hoofdmappen te laden\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Test verbinding om kwaliteitsprofielen te laden\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Hoofdmappen laden…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Kwaliteitsprofielen laden…\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Versiegegevens zijn momenteel niet beschikbaar.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Nieuwste\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Huidig\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studio's}}\",\n  \"components.CollectionDetails.overview\": \"Overzicht\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} films\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Verwerking van aanvraag mislukt\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Een melding sturen wanneer media-aanvragen handmatig worden goedgekeurd.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Een melding sturen wanneer een media-aanvraag beschikbaar is.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Aanvraag goedgekeurd\",\n  \"i18n.retry\": \"Opnieuw proberen\",\n  \"i18n.requested\": \"Aangevraagd\",\n  \"i18n.failed\": \"Mislukt\",\n  \"i18n.deleting\": \"Verwijderen…\",\n  \"i18n.close\": \"Sluiten\",\n  \"components.UserList.userdeleteerror\": \"Er ging iets mis bij het verwijderen van de gebruiker.\",\n  \"components.UserList.userdeleted\": \"Gebruiker verwijderd!\",\n  \"components.UserList.importfromplexerror\": \"Er is iets misgegaan bij het importeren van Plex-gebruikers.\",\n  \"components.UserList.importfrommediaserver\": \"{mediaServerName}-gebruikers importeren\",\n  \"components.UserList.importfromplex\": \"Plex-gebruikers importeren\",\n  \"components.UserList.deleteuser\": \"Gebruiker verwijderen\",\n  \"components.UserList.deleteconfirm\": \"Weet je zeker dat je deze gebruiker wilt verwijderen? Al diens bestaande aanvraaggegevens zullen worden verwijderd.\",\n  \"components.TvDetails.watchtrailer\": \"Trailer bekijken\",\n  \"components.TvDetails.viewfullcrew\": \"Volledige crew bekijken\",\n  \"components.TvDetails.showtype\": \"Type serie\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Netwerk} other {Netwerken}}\",\n  \"components.TvDetails.firstAirDate\": \"Datum eerste uitzending\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Hoofdmap anime\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Kwaliteitsprofiel anime\",\n  \"components.Settings.SettingsAbout.timezone\": \"Tijdzone\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentatie\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Bekijken op GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Changelog bekijken\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Je moet een geldige chat-ID opgeven\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Je moet een bot-authorisatietoken opgeven\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Instellingen Telegrammeldingen opgeslagen!\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"De instellingen voor Telegrammeldingen konden niet opgeslagen worden.\",\n  \"components.Settings.Notifications.senderName\": \"Naam afzender\",\n  \"components.Settings.Notifications.chatId\": \"Chat-ID\",\n  \"components.Settings.Notifications.botAPI\": \"Bot-autorisatietoken\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Self-signed certificaten toestaan\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Dienst inschakelen\",\n  \"components.RequestList.RequestItem.failedretry\": \"Er ging opnieuw iets mis tijdens het aanvragen.\",\n  \"components.PersonDetails.crewmember\": \"Crew\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Aanvraag in afwachting van goedkeuring\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Aanvraag beschikbaar\",\n  \"components.MovieDetails.watchtrailer\": \"Trailer bekijken\",\n  \"components.MovieDetails.viewfullcrew\": \"Volledige crew bekijken\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Volledige crew\",\n  \"components.CollectionDetails.requestcollection\": \"Collectie aanvragen\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex-{userCount, plural, one {gebruiker} other {gebruikers}} geïmporteerd!\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Changelog voor {version}\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Versies\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Instellingen voor Slack-meldingen opgeslagen!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Instellingen voor Slack-meldingen konden niet opgeslagen worden.\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Een melding sturen wanneer gebruikers een nieuwe media-aanvraag indienen die goedkeuring vereist.\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Een melding sturen wanneer een media-aanvraag niet kan worden toegevoegd aan Radarr of Sonarr.\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Volledige crew van de serie\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Instellingen voor Pushover-meldingen opgeslagen!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Instellingen voor Pushover-meldingen konden niet opgeslagen worden.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Dienst inschakelen\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token toepassings-API\",\n  \"components.RequestList.sortModified\": \"Laatst gewijzigd\",\n  \"components.RequestList.sortAdded\": \"Meest recent\",\n  \"components.RequestList.showallrequests\": \"Alle aanvragen tonen\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Je moet een geldige gebruikers- of groepssleutel opgeven\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Je moet een geldig toepassingstoken opgeven\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Gebruikers- of groepssleutel\",\n  \"i18n.request\": \"Aanvragen\",\n  \"components.RequestButton.requestmore4k\": \"Meer in 4K aanvragen\",\n  \"components.RequestButton.approverequests\": \"{requestCount, plural, one {Aanvraag} other {{requestCount} Aanvragen}} goedkeuren\",\n  \"components.RequestButton.approve4krequests\": \"{requestCount, plural, one {4K-aanvraag} other {{requestCount} 4K-aanvragen}} goedkeuren\",\n  \"components.RequestButton.declinerequests\": \"{requestCount, plural, one {Aanvraag} other {{requestCount} Aanvragen}} weigeren\",\n  \"components.RequestButton.decline4krequests\": \"{requestCount, plural, one {4K-aanvraag} other {{requestCount} 4K-aanvragen}} weigeren\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Instellingen voor webhook-meldingen opgeslagen!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Instellingen voor webhook-meldingen konden niet opgeslagen worden.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Je moet een geldige JSON-payload opgeven\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Hulp met sjabloonvariabelen\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON-payload teruggezet!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Terugzetten naar standaard\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON-payload\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Autorisatie-header\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Dienst inschakelen\",\n  \"components.RequestModal.pending4krequest\": \"4K-aanvraag in behandeling\",\n  \"components.RequestButton.viewrequest4k\": \"4K-aanvraag bekijken\",\n  \"components.RequestButton.viewrequest\": \"Aanvraag bekijken\",\n  \"components.RequestButton.requestmore\": \"Meer aanvragen\",\n  \"components.RequestButton.declinerequest4k\": \"4K-aanvraag weigeren\",\n  \"components.RequestButton.declinerequest\": \"Aanvraag weigeren\",\n  \"components.RequestButton.approverequest4k\": \"4K-aanvraag goedkeuren\",\n  \"components.RequestButton.approverequest\": \"Aanvraag goedkeuren\",\n  \"components.UserList.autogeneratepassword\": \"Automatisch wachtwoord genereren\",\n  \"components.UserList.create\": \"Aanmaken\",\n  \"components.UserList.createlocaluser\": \"Lokale gebruiker aanmaken\",\n  \"components.UserList.usercreatedfailed\": \"Er ging iets mis bij het aanmaken van de gebruiker.\",\n  \"components.UserList.creating\": \"Aanmaken…\",\n  \"components.UserList.validationpasswordminchars\": \"Wachtwoord is te kort; moet minimaal 8 tekens bevatten\",\n  \"components.UserList.usercreatedsuccess\": \"Gebruiker aangemaakt!\",\n  \"components.UserList.passwordinfodescription\": \"Stel een toepassings-URL in en schakel e-mailmeldingen in om automatische wachtwoordgeneratie mogelijk te maken.\",\n  \"components.UserList.password\": \"Wachtwoord\",\n  \"components.UserList.localuser\": \"Lokale gebruiker\",\n  \"components.UserList.email\": \"E-mailadres\",\n  \"components.Login.validationpasswordrequired\": \"Je moet een wachtwoord opgeven\",\n  \"components.Login.validationemailrequired\": \"Je moet een geldig e-mailadres opgeven\",\n  \"components.Login.signinwithoverseerr\": \"{applicationTitle}-account gebruiken\",\n  \"components.Login.password\": \"Wachtwoord\",\n  \"components.Login.loginerror\": \"Er ging iets mis bij het aanmelden.\",\n  \"components.Login.email\": \"E-mailadres\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Meer\",\n  \"i18n.edit\": \"Bewerken\",\n  \"components.RequestModal.requestedited\": \"Aanvraag voor <strong>{title}</strong> aangepast!\",\n  \"components.RequestModal.requestcancelled\": \"Aanvraag voor <strong>{title}</strong> geannuleerd.\",\n  \"components.RequestModal.errorediting\": \"Er is iets misgegaan bij het aanpassen van de aanvraag.\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Hoofdmap\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Kwaliteitsprofiel\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Doelserver\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Standaard)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Deze serie is anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Geavanceerd\",\n  \"components.RequestBlock.server\": \"Doelserver\",\n  \"components.RequestBlock.rootfolder\": \"Hoofdmap\",\n  \"components.RequestBlock.profilechanged\": \"Kwaliteitsprofiel\",\n  \"components.RequestBlock.requestoverrides\": \"Overschrijvingen van aanvraag\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Een melding sturen wanneer een media-aanvraag wordt afgewezen.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Aanvraag geweigerd\",\n  \"components.RequestModal.autoapproval\": \"Automatische goedkeuring\",\n  \"i18n.experimental\": \"Experimenteel\",\n  \"components.RequestModal.requesterror\": \"Er ging iets mis bij het aanvragen.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Er is geen automatische overeenkomst voor deze serie gevonden. Selecteer hieronder de overeenkomstige serie.\",\n  \"components.Login.signinwithplex\": \"Plex-account gebruiken\",\n  \"components.Login.signinheader\": \"Log in om verder te gaan\",\n  \"components.Login.signingin\": \"Aanmelden…\",\n  \"components.Login.signin\": \"Aanmelden\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Meldingsdiensten configureren en inschakelen.\",\n  \"components.PermissionEdit.advancedrequest\": \"Geavanceerde aanvragen\",\n  \"components.PermissionEdit.admin\": \"Beheerder\",\n  \"components.UserList.userssaved\": \"Gebruikersrechten opgeslagen!\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Serverlijst van Plex opgehaald!\",\n  \"components.Settings.toastPlexRefresh\": \"Bezig met serverlijst ophalen van Plex…\",\n  \"components.Settings.toastPlexConnecting\": \"Verbinden met Plex…\",\n  \"components.UserList.bulkedit\": \"Meerdere bewerken\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Kan serverlijst van Plex niet ophalen.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Succesvol verbonden met Plex!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Kan geen verbinding maken met Plex.\",\n  \"components.Settings.settingUpPlexDescription\": \"Om Plex in te stellen, kan je de gegevens handmatig invoeren of een server selecteren die is opgehaald van <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Druk op de knop rechts van de vervolgkeuzelijst om de lijst van beschikbare servers op te halen.\",\n  \"components.Settings.serverpresetRefreshing\": \"Servers ophalen…\",\n  \"components.Settings.serverpresetManualMessage\": \"Handmatige configuratie\",\n  \"components.Settings.serverpresetLoad\": \"Klik op de knop om de beschikbare servers te laden\",\n  \"components.Settings.serverpreset\": \"Server\",\n  \"components.Settings.serverRemote\": \"extern\",\n  \"components.Settings.serverLocal\": \"lokaal\",\n  \"components.PermissionEdit.usersDescription\": \"Toestemming geven om gebruikers te beheren. Gebruikers met deze toestemming kunnen gebruikers met beheerdersrechten niet wijzigen of die rechten verlenen.\",\n  \"components.PermissionEdit.users\": \"Gebruikers beheren\",\n  \"components.PermissionEdit.requestDescription\": \"Toestemming geven om niet-4K-media aan te vragen.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Toestemming geven om series in 4K aan te vragen.\",\n  \"components.PermissionEdit.request4kTv\": \"4K-series aanvragen\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Toestemming geven om films in 4K aan te vragen.\",\n  \"components.PermissionEdit.request4k\": \"4K aanvragen\",\n  \"components.PermissionEdit.request\": \"Aanvragen\",\n  \"components.PermissionEdit.request4kMovies\": \"4K-films aanvragen\",\n  \"components.PermissionEdit.request4kDescription\": \"Toestemming geven om 4K-media aan te vragen.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Toestemming geven om media-aanvragen te beheren. Alle aanvragen die door een gebruiker met deze toestemming worden gedaan, worden automatisch goedgekeurd.\",\n  \"components.PermissionEdit.managerequests\": \"Aanvragen beheren\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Serie-aanvragen (niet-4K) automatisch goedkeuren.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Films automatisch goedkeuren\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Series automatisch goedkeuren\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Filmaanvragen (niet-4K) automatisch goedkeuren.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Alle media-aanvragen (niet-4K) automatisch goedkeuren.\",\n  \"components.PermissionEdit.autoapprove\": \"Automatische goedkeuring\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Toestemming geven om geavanceerde aanvraagopties voor media te wijzigen.\",\n  \"components.PermissionEdit.adminDescription\": \"Volledige beheerderstoegang. Omzeilt alle andere machtigingscontroles.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Succesvol verbonden met Sonarr!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Kon niet verbinden met Sonarr.\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Scan inschakelen\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Externe URL\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Scan inschakelen\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Externe URL\",\n  \"components.MovieDetails.mark4kavailable\": \"Als beschikbaar in 4K markeren\",\n  \"components.MovieDetails.markavailable\": \"Als beschikbaar markeren\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} cache leeggemaakt.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Missers\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr voert bepaalde onderhoudstaken uit als regelmatig ingeplande taken, maar ze kunnen hieronder ook handmatig worden gestart. Het handmatig uitvoeren van een taak verandert de planning niet.\",\n  \"i18n.advanced\": \"Geavanceerd\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Nu uitvoeren\",\n  \"components.Settings.SettingsJobsCache.process\": \"Proces\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Volgende uitvoering\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Type\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} gestart.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Taken\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Taaknaam\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} geannuleerd.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Cache wissen\",\n  \"components.Settings.SettingsJobsCache.command\": \"Commando\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Taak annuleren\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Waardegrootte\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Cachenaam\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Sleutelgrootte\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Totaal aantal sleutels\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Treffers\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr cachet verzoeken aan externe API-eindpunten om prestatie te optimaliseren en onnodige API-aanroepen te vermijden.\",\n  \"components.UserList.users\": \"Gebruikers\",\n  \"components.Search.search\": \"Zoeken\",\n  \"components.Setup.setup\": \"Configuratie\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Aanvragen als\",\n  \"components.Discover.discover\": \"Ontdekken\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"De volumekoppeling <code>{appDataPath}</code> is niet correct geconfigureerd. Alle gegevens zullen worden gewist wanneer de container wordt gestopt of opnieuw wordt gestart.\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL mag niet eindigen op een schuine streep\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Je moet een geldige URL opgeven\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL mag niet eindigen op een schuine streep\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Je moet een geldige URL opgeven\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Toestemming geven om media-aanvragen van andere gebruikers te bekijken.\",\n  \"components.PermissionEdit.viewrequests\": \"Aanvragen weergeven\",\n  \"components.UserList.validationEmail\": \"E-mailadres vereist\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Basis-URL mag niet eindigen op een schuine streep\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Basis-URL moet met een schuine streep beginnen\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL-basis mag niet eindigen op een schuine streep\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL-basis moet met een schuine streep beginnen\",\n  \"components.Settings.Notifications.validationEmail\": \"Je moet een geldig e-mailadres opgeven\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Je moet een geldige URL opgeven\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Je moet een geldige URL opgeven\",\n  \"components.ResetPassword.resetpassword\": \"Wachtwoord herstellen\",\n  \"components.ResetPassword.email\": \"E-mailadres\",\n  \"components.TvDetails.nextAirDate\": \"Volgende uitzenddatum\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Je moet een wachtwoord opgeven\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Wachtwoord is te kort; moet minimaal 8 tekens bevatten\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Wachtwoorden moeten overeenkomen\",\n  \"components.ResetPassword.validationemailrequired\": \"Je moet een geldig e-mailadres opgeven\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Wachtwoord is opnieuw ingesteld!\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Er wordt een link om het wachtwoord te resetten naar het opgegeven e-mailadres gestuurd als dat gekoppeld is aan een geldige gebruiker.\",\n  \"components.ResetPassword.password\": \"Wachtwoord\",\n  \"components.ResetPassword.gobacklogin\": \"Terug naar aanmeldpagina\",\n  \"components.ResetPassword.emailresetlink\": \"Herstellink e-mailen\",\n  \"components.ResetPassword.confirmpassword\": \"Wachtwoord bevestigen\",\n  \"components.Login.forgotpassword\": \"Wachtwoord vergeten?\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Taalprofiel\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Je moet een taalprofiel selecteren\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Verbinding testen en taalprofielen laden\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Taalprofiel selecteren\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Taalprofielen laden…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Taalprofiel\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Taalprofiel anime\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Meldingen versturen zonder geluid\",\n  \"components.Settings.Notifications.sendSilently\": \"Stil verzenden\",\n  \"components.UserList.sortRequests\": \"Aantal aanvragen\",\n  \"components.UserList.sortDisplayName\": \"Weergavenaam\",\n  \"components.UserList.sortCreated\": \"Aanmeldingsdatum\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Serie-aanvragen in 4K automatisch goedkeuren.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Series automatisch goedkeuren\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Filmaanvragen in 4K automatisch goedkeuren.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Automatische goedkeuring van films in 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Alle 4K-media-aanvragen automatisch goedkeuren.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Automatische goedkeuring 4K\",\n  \"components.UserProfile.recentrequests\": \"Recente aanvragen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Algemene instellingen\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Meldingen\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Algemeen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Gebruikers-ID\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Wachtwoord is te kort; moet minimaal 8 tekens bevatten\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Je moet een nieuw wachtwoord opgeven\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Je moet jouw huidige wachtwoord opgeven\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Wachtwoorden moeten overeenkomen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Je moet het nieuwe wachtwoord bevestigen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Wachtwoord gewijzigd!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Er ging iets mis bij het opslaan van het wachtwoord.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Wachtwoord\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Wachtwoord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nieuw wachtwoord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Huidig wachtwoord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Wachtwoord bevestigen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Instellingen opgeslagen!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Machtigingen opgeslagen!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Er ging iets mis bij het opslaan van de instellingen.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Er ging iets mis bij het opslaan van de instellingen.\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Machtigingen\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Machtigingen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex-gebruiker\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Meldingsinstellingen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Lokale gebruiker\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Weergavenaam\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Profiel bekijken\",\n  \"components.UserList.userfail\": \"Er ging iets mis bij het opslaan van de gebruikersrechten.\",\n  \"components.UserList.edituser\": \"Gebruikersrechten bewerken\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Instellingen bewerken\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Je moet een toegangstoken opgeven\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Instellingen voor Pushbullet-meldingen opgeslagen!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Instellingen voor Pushbullet-meldingen konden niet opgeslagen worden.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Dienst inschakelen\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Toegangstoken\",\n  \"components.Layout.UserDropdown.settings\": \"Instellingen\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profiel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Je moet een geldige gebruikers-ID opgeven\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"Het <FindDiscordIdLink>meercijferige ID-nummer</FindDiscordIdLink> van je gebruikersaccount\",\n  \"components.CollectionDetails.requestcollection4k\": \"Collectie aanvragen in 4K\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Inhoud filteren op regionale beschikbaarheid\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Regio van Ontdekken\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Inhoud filteren op oorspronkelijke taal\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Taal voor Ontdekken\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.email\": \"E-mail\",\n  \"components.RegionSelector.regionDefault\": \"Alle regio’s\",\n  \"components.Discover.upcomingtv\": \"Verwachte series\",\n  \"components.RegionSelector.regionServerDefault\": \"Standaard ({region})\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Je bent niet gemachtigd om het wachtwoord van deze gebruiker te wijzigen.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Gebruiker\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rol\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Eigenaar\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Beheerder\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Accounttype\",\n  \"components.UserList.owner\": \"Eigenaar\",\n  \"components.UserList.accounttype\": \"Type\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Onbekende taak\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Reset download sync\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Synchronisatie downloads\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# seizoen} other {# seizoenen}}\",\n  \"i18n.loading\": \"Laden…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Je moet een geldige chat-ID opgeven\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Een chat starten</TelegramBotLink>, <GetIdBotLink>@get_id_bot</GetIdBotLink> toevoegen en de opdracht <code>/my_id</code> geven\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chat-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Meldingen versturen zonder geluid\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Stil versturen\",\n  \"components.Settings.Notifications.botUsername\": \"Gebruikersnaam bot\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} series\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Films van {studio}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Series van {network}\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} films\",\n  \"components.Settings.scanning\": \"Synchroniseren…\",\n  \"components.Settings.scan\": \"Bibliotheken synchroniseren\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr-scan\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr-scan\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plex recent toegevoegde scan\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plex volledige bibliotheekscan\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Volledige bibliotheekscan Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Scan van 'onlangs toegevoegd' in Jellyfin\",\n  \"components.Settings.Notifications.validationUrl\": \"Je moet een geldige URL opgeven\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL bot-avatar\",\n  \"components.RequestList.RequestItem.requested\": \"Aangevraagd\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} door {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Gewijzigd\",\n  \"components.Discover.StudioSlider.studios\": \"Studio's\",\n  \"components.Discover.NetworkSlider.networks\": \"Netwerken\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Series in het {language}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Films in het {language}\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Gebruikers-ID: {userid}\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Lid geworden op {joindate}\",\n  \"components.Settings.menuUsers\": \"Gebruikers\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Algemene en standaard gebruikersinstellingen configureren.\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Gebruikersinstellingen\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Gebruikersinstellingen opgeslagen!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Er ging iets mis bij het opslaan van de instellingen.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Lokaal aanmelden inschakelen\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Standaard machtigingen\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Een melding sturen wanneer een gebruiker nieuwe media aanvraagt die automatisch wordt goedgekeurd.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Aanvraag automatisch goedgekeurd\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Je hebt geen toestemming om de instellingen van deze gebruiker te wijzigen.\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Je kan je eigen machtigingen niet wijzigen.\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minuten\",\n  \"components.TvDetails.episodeRuntime\": \"Afleveringsduur\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Versleutelde e-mailberichten ondertekenen met <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Privésleutel PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Versleutelde e-mailberichten ondertekenen met <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPassword\": \"Wachtwoord PGP\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Seriegenres\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Filmgenres\",\n  \"components.RequestModal.alreadyrequested\": \"Al aangevraagd\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Seriegenres\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Filmgenres\",\n  \"components.Settings.SettingsLogs.filterError\": \"Fout\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Foutopsporing\",\n  \"components.Settings.SettingsLogs.time\": \"Tijdstip\",\n  \"components.Settings.SettingsLogs.showall\": \"Alle logboeken weergeven\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Hervatten\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pauze\",\n  \"components.Settings.SettingsLogs.message\": \"Bericht\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Je kunt deze logboeken ook rechtstreeks bekijken via <code>stdout</code>, of in <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.logs\": \"Logboeken\",\n  \"components.Settings.SettingsLogs.level\": \"Ernst\",\n  \"components.Settings.SettingsLogs.label\": \"Label\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Waarschuwing\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"pages.somethingwentwrong\": \"Er ging iets mis\",\n  \"pages.serviceunavailable\": \"Service niet beschikbaar\",\n  \"pages.pagenotfound\": \"Pagina niet gevonden\",\n  \"pages.internalservererror\": \"Interne serverfout\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"i18n.usersettings\": \"Gebruikersinstellingen\",\n  \"i18n.settings\": \"Instellingen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Er ging iets mis bij het opslaan van het wachtwoord. Is je huidige wachtwoord correct ingevoerd?\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Meldingen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Algemeen\",\n  \"components.Settings.services\": \"Diensten\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Meldingen\",\n  \"components.Settings.SettingsUsers.users\": \"Gebruikers\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Taken en cache\",\n  \"components.Settings.SettingsAbout.about\": \"Over\",\n  \"components.ResetPassword.passwordreset\": \"Wachtwoord opnieuw instellen\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Loggegevens\",\n  \"components.Settings.SettingsLogs.extraData\": \"Aanvullende gegevens\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Naar klembord kopiëren\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Logbericht naar klembord gekopieerd.\",\n  \"components.Settings.enablessl\": \"SSL gebruiken\",\n  \"components.UserList.nouserstoimport\": \"Er zijn geen Plex-gebruikers om te importeren.\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Geboren op {geboortedatum}\",\n  \"components.PersonDetails.alsoknownas\": \"Ook bekend als: {names}\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"components.UserProfile.unlimited\": \"Onbeperkt\",\n  \"components.UserProfile.totalrequests\": \"Totaal aantal aanvragen\",\n  \"components.UserProfile.seriesrequest\": \"Serie-aanvragen\",\n  \"components.UserProfile.requestsperdays\": \"{limit} resterend\",\n  \"components.UserProfile.pastdays\": \"{type} (afgelopen {days} dagen)\",\n  \"components.UserProfile.movierequests\": \"Filmaanvragen\",\n  \"components.UserProfile.limit\": \"{remaining} van {limit}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Aanvraaglimiet voor series\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Aanvraaglimiet voor films\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Globale limiet overschrijven\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Globale aanvraaglimiet voor films\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Globale aanvraaglimiet voor series\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {seizoen} other {seizoenen}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"seizoen\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Je hebt nog minstens <strong>{seasons}</strong> {seasons, plural, one {seizoensaanvraag} other {seizoensaanvragen}} nodig om deze serie aan te vragen.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Geen} other {<strong>#</strong>}} {type}{remaining, plural, one {aanvraag} other {aanvragen}} over\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Je kunt een overzicht van de aanvraaglimieten van deze gebruiker bekijken op diens <ProfileLink>profielpagina</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Je kan een overzicht van je aanvraaglimieten bekijken op jouw <ProfileLink>profielpagina</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Onvoldoende seizoensaanvragen over\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {films}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Deze gebruiker mag elke <strong>{days}</strong> dagen <strong>{limit}</strong> {type} aanvragen.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Je mag elke <strong>{days}</strong> dagen <strong>{limit}</strong> {type} aanvragen.\",\n  \"components.QuotaSelector.unlimited\": \"Onbeperkt\",\n  \"i18n.view\": \"Bekijken\",\n  \"i18n.tvshow\": \"Serie\",\n  \"i18n.testing\": \"Testen…\",\n  \"i18n.test\": \"Testen\",\n  \"i18n.status\": \"Status\",\n  \"i18n.showingresults\": \"Resultaten <strong>{from}</strong> t/m <strong>{to}</strong> van <strong>{total}</strong> weergegeven\",\n  \"i18n.saving\": \"Opslaan…\",\n  \"i18n.save\": \"Wijzigingen opslaan\",\n  \"i18n.resultsperpage\": \"{pageSize} resultaten per pagina weergeven\",\n  \"i18n.requesting\": \"Aanvragen…\",\n  \"i18n.request4k\": \"Aanvragen in 4K\",\n  \"i18n.previous\": \"Vorige\",\n  \"i18n.notrequested\": \"Niet aangevraagd\",\n  \"i18n.noresults\": \"Geen resultaten.\",\n  \"i18n.next\": \"Volgende\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.canceling\": \"Annuleren…\",\n  \"i18n.back\": \"Terug\",\n  \"i18n.areyousure\": \"Weet je het zeker?\",\n  \"i18n.all\": \"Alle\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Deze gebruiker heeft nog minstens <strong>{seasons}</strong> {seasons, plural, one {seizoensaanvraag} other {seizoensaanvragen}} nodig om deze serie aan te vragen.\",\n  \"components.TvDetails.originaltitle\": \"Oorspronkelijke titel\",\n  \"components.MovieDetails.originaltitle\": \"Oorspronkelijke titel\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Alle talen\",\n  \"components.LanguageSelector.languageServerDefault\": \"Standaard ({language})\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Test de verbinding om labels te laden\",\n  \"components.Settings.SonarrModal.tags\": \"Labels\",\n  \"components.Settings.SonarrModal.selecttags\": \"Labels selecteren\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Geen labels.\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Labels laden…\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"4K Sonarr-server bewerken\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Standaard 4K-server\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Nieuwe 4K Sonarr-server toevoegen\",\n  \"components.Settings.SonarrModal.animeTags\": \"Animelabels\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Test de verbinding om labels te laden\",\n  \"components.Settings.RadarrModal.tags\": \"Labels\",\n  \"components.Settings.RadarrModal.selecttags\": \"Labels selecteren\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Geen labels.\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"4K Radarr-server bewerken\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Standaard 4K-server\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Nieuwe 4K Radarr-server toevoegen\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Labels\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Labels selecteren\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Geen labels.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Labels laden…\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} niet gevonden\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Aanvraag verwijderen\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} niet gevonden\",\n  \"components.RequestCard.deleterequest\": \"Aanvraag verwijderen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Je moet een geldige openbare PGP-sleutel opgeven\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Instellingen Telegrammeldingen opgeslagen!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"De instellingen voor Telegrammeldingen konden niet opgeslagen worden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"E-mailberichten versleutelen met <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Openbare PGP-sleutel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Instellingen voor e-mailmeldingen opgeslagen!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Instellingen voor e-mailmeldingen konden niet opgeslagen worden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Instellingen voor Discord-meldingen opgeslagen!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Instellingen voor Discord-meldingen konden niet opgeslagen worden.\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Je moet een geldige PGP-privésleutel opgeven\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Je moet een PGP-wachtwoord opgeven\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Sta gebruikers toe ook een chat met jouw bot te starten en hun eigen meldingen te configureren\",\n  \"components.RequestModal.pendingapproval\": \"Je aanvraag is in afwachting van goedkeuring.\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Aanvraag annuleren\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Meldingtypes\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Er is voor jouw account momenteel geen wachtwoord ingesteld. Stel hieronder een wachtwoord in om aanmelden als \\\"lokale gebruiker\\\" (met je e-mailadres) in te schakelen.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Dit gebruikersaccount heeft momenteel geen ingesteld wachtwoord. Configureer hieronder een wachtwoord zodat dit account zich kan aanmelden als een \\\"lokale gebruiker.\\\"\",\n  \"components.Settings.serviceSettingsDescription\": \"Stel je {serverType}-server(s) hieronder in. Je kunt meerdere {serverType}-servers verbinden, maar slechts twee ervan kunnen als standaard worden gemarkeerd (één niet-4K en één 4K). Beheerders kunnen vóór goedkeuring de server aanpassen die voor nieuwe aanvragen gebruikt wordt.\",\n  \"components.Settings.noDefaultServer\": \"Ten minste één {serverType}-server moet als standaard worden aangemerkt om {mediaType}aanvragen te kunnen verwerken.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Als je slechts één enkele {serverType} server hebt voor zowel niet-4K als 4K-inhoud (of als je alleen 4K-inhoud downloadt), dan moet je {serverType} server <strong>NIET</strong> aangeduid worden als een 4K-server.\",\n  \"components.Settings.mediaTypeSeries\": \"serie\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Bijgewerkt\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Verouderd\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr ontwikkelversie\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr stabiel\",\n  \"components.Layout.VersionStatus.outofdate\": \"Verouderd\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} achter\",\n  \"components.UserList.autogeneratepasswordTip\": \"Een door de server gegenereerd wachtwoord naar de gebruiker e-mailen\",\n  \"i18n.retrying\": \"Opnieuw proberen…\",\n  \"components.Settings.serverSecure\": \"veilig\",\n  \"components.UserList.usercreatedfailedexisting\": \"Het opgegeven e-mailadres wordt al gebruikt door een andere gebruiker.\",\n  \"components.RequestModal.edit\": \"Aanvraag aanpassen\",\n  \"components.RequestList.RequestItem.editrequest\": \"Aanvraag aanpassen\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Automatisch zoeken inschakelen\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Automatisch zoeken inschakelen\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Dienst inschakelen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web-push\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Weergavetaal\",\n  \"components.Settings.webpush\": \"Web-push\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Instellingen voor web-pushmeldingen opgeslagen!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Instellingen voor web-pushmeldingen zijn niet opgeslagen.\",\n  \"components.Settings.noDefault4kServer\": \"Een 4K-{serverType}server moet als standaard worden gemarkeerd om gebruikers toe te laten om 4K-{mediaType} aan te vragen.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"{mediaServerName}-gebruikers toestaan zich aan te melden zonder eerst geïmporteerd te zijn\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Nieuwe {mediaServerName}-aanmelding inschakelen\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Testmelding Telegram verzonden!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Testmelding Telegram verzenden…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Testmelding Telegram niet verzonden.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Testmail verzonden!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Testmail verzenden…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Testmail niet verzonden.\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Testmelding Discord verzonden!\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Testmelding Discord verzenden…\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Testmelding Discord niet verzonden.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Testmelding webhook verzonden!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Testmelding webhook verzenden…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Testmelding webhook niet verzonden.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Testmelding web-push verzonden!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Testmelding web-push verzenden…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Testmelding web-push niet verzonden.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Testmelding Slack verzonden!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Testmelding Slack verzenden…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Testmelding Slack niet verzonden.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Testmelding Pushover verzonden!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Testmelding Pushover verzenden…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Testmelding Pushover niet verzonden.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Testmelding Pushbullet verzonden!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Testmelding Pushbullet verzenden…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Testmelding Pushbullet niet verzonden.\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Toestemming geven om niet-4K-films aan te vragen.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Toestemming geven om niet-4K-series aan te vragen.\",\n  \"components.PermissionEdit.requestTv\": \"Series aanvragen\",\n  \"components.PermissionEdit.requestMovies\": \"Films aanvragen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Standaard ({language})\",\n  \"components.DownloadBlock.estimatedtime\": \"Geschat {time}\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Maak een <WebhookLink>inkomende webhook</WebhookLink>integratie aan\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Maak een bot</CreateBotLink> om te gebruiken met Seerr\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Maak een <DiscordWebhookLink>webhook-integratie</DiscordWebhookLink> op je server\",\n  \"components.Settings.Notifications.chatIdTip\": \"Start een chat met je bot, voeg <GetIdBotLink>@get_id_bot</GetIdBotLink> toe, en geef het <code>/my_id</code> commando\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Je <UsersGroupsLink>gebruikers- of groepsidentifier</UsersGroupsLink> van 30 tekens\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Een toepassing registreren</ApplicationRegistrationLink> om te gebruiken met Seerr\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Maak een token aan vanuit je <PushbulletSettingsLink>accountinstellingen</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.encryptionTip\": \"In de meeste gevallen gebruikt impliciete TLS poort 465 en STARTTLS poort 587\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Altijd STARTTLS gebruiken\",\n  \"components.Settings.Notifications.encryptionNone\": \"Geen\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Impliciete TLS gebruiken\",\n  \"components.Settings.Notifications.encryptionDefault\": \"STARTTLS gebruiken indien beschikbaar\",\n  \"components.Settings.Notifications.encryption\": \"Encryptiemethode\",\n  \"components.Settings.webAppUrl\": \"URL van <WebAppLink>Web App</WebAppLink>\",\n  \"components.Settings.webAppUrlTip\": \"Stuur gebruikers optioneel naar de web-app op uw server in plaats van de \\\"gehoste\\\" web-app\",\n  \"components.UserList.localLoginDisabled\": \"De instelling <strong>Lokaal aanmelden inschakelen</strong> is momenteel uitgeschakeld.\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Om web-pushmeldingen te ontvangen, moet Seerr via HTTPS worden weergegeven.\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Aangevraagd\",\n  \"components.RequestCard.failedretry\": \"Er ging opnieuw iets mis tijdens het aanvragen.\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Sta gebruikers toe zich aan te melden met hun e-mailadres en wachtwoord\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Initiële machtigingen toegekend aan nieuwe gebruikers\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {seizoen} other {seizoenen}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {films}}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {dag} other {dagen}}\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Een melding ontvangen wanneer je media-aanvragen goedgekeurd zijn.\",\n  \"components.Settings.Notifications.validationTypes\": \"Je moet ten minste één meldingstype selecteren\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Je moet ten minste één meldingstype selecteren\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Je moet ten minste één meldingstype selecteren\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Je moet ten minste één meldingstype selecteren\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Je moet ten minste één meldingstype selecteren\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Een melding ontvangen wanneer andere gebruikers nieuwe media-aanvragen indienen waarvoor goedkeuring vereist is.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Een melding ontvangen wanneer media-aanvragen niet kunnen worden toegevoegd aan Radarr of Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Een melding ontvangen wanneer je media-aanvragen worden geweigerd.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Een melding ontvangen wanneer je media-aanvragen beschikbaar zijn.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Een melding ontvangen wanneer andere gebruikers nieuwe media-aanvragen indienen die automatisch worden goedgekeurd.\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Weergavetaal\",\n  \"components.MovieDetails.showmore\": \"Meer tonen\",\n  \"components.MovieDetails.showless\": \"Minder tonen\",\n  \"components.TvDetails.streamingproviders\": \"Momenteel te streamen op\",\n  \"components.MovieDetails.streamingproviders\": \"Momenteel te streamen op\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Taak bewerkt!\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Elk(e) {jobScheduleMinutes, plural, one {minuut} other {{jobScheduleMinutes} minuten}}\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Nieuwe frequentie\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Er ging iets mis bij het opslaan van de taak.\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Taak wijzigen\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Elk(e) {jobScheduleHours, plural, one {uur} other {{jobScheduleHours} uur}}\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Je voert de <code>develop</code>versie van Seerr uit, die alleen wordt aanbevolen als je bijdraagt aan de ontwikkeling of de allereerste versies helpt testen.\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Weet je zeker dat je deze opmerking wilt verwijderen?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Opmerking verwijderen\",\n  \"components.IssueDetails.IssueComment.edit\": \"Opmerking bewerken\",\n  \"components.IssueDetails.IssueComment.postedby\": \"{relativeTime} gepost door {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"{relativeTime} ingediend door {username} (bewerkt)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Je moet een bericht invoeren\",\n  \"components.IssueDetails.problemepisode\": \"Getroffen aflevering\",\n  \"components.IssueDetails.problemseason\": \"Getroffen seizoen\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Als beschikbaar in 4K markeren\",\n  \"components.ManageSlideOver.markavailable\": \"Als beschikbaar markeren\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.IssueDetails.comments\": \"Opmerkingen\",\n  \"components.ManageSlideOver.openarr\": \"Openen in {arr}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Gebruikers- of groepssleutel\",\n  \"i18n.open\": \"Onopgelost\",\n  \"i18n.resolved\": \"Opgelost\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Seizoen {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Probleem indienen\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Je moet een beschrijving geven\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Wat is er aan de hand?\",\n  \"components.IssueModal.issueSubtitles\": \"Ondertiteling\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.ManageSlideOver.downloadstatus\": \"Downloads\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Geen aanvragen.\",\n  \"components.IssueDetails.lastupdated\": \"Laatst bijgewerkt\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Probleem verwijderen\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Beschrijving bewerken\",\n  \"components.IssueDetails.allseasons\": \"Alle seizoenen\",\n  \"components.IssueDetails.closeissue\": \"Probleem afsluiten\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Alle afleveringen\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueDetails.nocomments\": \"Geen opmerkingen.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Probleem melden\",\n  \"components.IssueDetails.allepisodes\": \"Alle afleveringen\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Probleembeschrijving bewerkt!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Probleem verwijderd!\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Geef een gedetailleerde uitleg van het probleem dat je bent tegengekomen.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Probleemstatus bijgewerkt!\",\n  \"components.IssueDetails.closeissueandcomment\": \"Afsluiten met opmerking\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Getroffen seizoen\",\n  \"components.IssueDetails.openedby\": \"#{issueId} - {relativeTime} ingediend door {username}\",\n  \"components.IssueDetails.IssueDescription.description\": \"Beschrijving\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Melding sturen wanneer problemen nieuwe opmerkingen krijgen.\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Probleem weergeven\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Er ging iets mis bij het indienen van het probleem.\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Er ging iets mis bij het verwijderen van het probleem.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Er ging iets mis bij het updaten van de probleemstatus.\",\n  \"components.IssueDetails.deleteissue\": \"Probleem verwijderen\",\n  \"components.IssueDetails.episode\": \"Aflevering {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Probleem\",\n  \"components.IssueDetails.issuetype\": \"Type\",\n  \"components.IssueDetails.leavecomment\": \"Opmerking plaatsen\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Weet je zeker dat je dit probleem wilt verwijderen?\",\n  \"components.IssueDetails.unknownissuetype\": \"Onbekend\",\n  \"components.IssueDetails.openinarr\": \"Openen in {arr}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Er ging iets mis bij het bewerken van de beschrijving van het probleem.\",\n  \"components.IssueList.IssueItem.issuetype\": \"Type\",\n  \"components.IssueList.IssueItem.opened\": \"Ingediend\",\n  \"components.IssueDetails.reopenissue\": \"Probleem opnieuw indienen\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Opnieuw indienen met opmerking\",\n  \"components.IssueDetails.season\": \"Seizoen {seasonNumber}\",\n  \"components.IssueList.showallissues\": \"Alle problemen weergeven\",\n  \"components.IssueList.sortModified\": \"Laatst gewijzigd\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Alle seizoenen\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Aflevering {episodeNumber}\",\n  \"components.IssueList.issues\": \"Problemen\",\n  \"components.IssueList.sortAdded\": \"Meest recent\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Status\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} door {user}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Onbekend\",\n  \"components.IssueList.IssueItem.viewissue\": \"Probleem weergeven\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Getroffen aflevering\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Getroffen aflevering\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Probleemmelding voor <strong>{title}</strong> ingediend!\",\n  \"components.PermissionEdit.viewissues\": \"Problemen weergeven\",\n  \"components.IssueModal.issueOther\": \"Anders\",\n  \"components.Layout.Sidebar.issues\": \"Problemen\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Gegevens wissen\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Hiermee worden alle gegevens voor deze {mediaType} onomkeerbaar verwijderd, inclusief eventuele aanvragen. Als dit item in je {mediaServerName}-bibliotheek staat, worden de mediagegevens bij de volgende scan opnieuw aangemaakt.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Aanvragen\",\n  \"components.ManageSlideOver.manageModalTitle\": \"{mediaType} beheren\",\n  \"components.ManageSlideOver.tvshow\": \"serie\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Ontvang een melding wanneer problemen die jij hebt gemeld, opgelost zijn.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Reactie op probleem\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Stuur meldingen wanneer problemen opgelost zijn.\",\n  \"components.ManageSlideOver.openarr4k\": \"Openen in 4K-{arr}\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Ontvang een melding wanneer andere gebruikers reageren op problemen.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Ontvang een melding wanneer er nieuwe reacties komen op problemen die jij hebt gemeld.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Ontvang een melding wanneer andere gebruikers problemen melden.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Probleem gemeld\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Stuur meldingen wanneer problemen worden gemeld.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Probleem opgelost\",\n  \"components.PermissionEdit.createissues\": \"Problemen melden\",\n  \"components.PermissionEdit.createissuesDescription\": \"Toestemming geven om mediaproblemen te melden.\",\n  \"components.PermissionEdit.manageissues\": \"Problemen beheren\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Toestemming geven om mediaproblemen te beheren.\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Toestemming geven om mediaproblemen te bekijken die door andere gebruikers zijn gemeld.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Maak een token aan in je <PushbulletSettingsLink>accountinstellingen</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Toegangstoken\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Instellingen voor Pushbullet-meldingen konden niet opgeslagen worden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Token toepassings-API\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Een toepassing registreren</ApplicationRegistrationLink> om te gebruiken met {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Je <UsersGroupsLink>gebruikers- of groepsidentifier</UsersGroupsLink> van 30 tekens\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Je moet een geldig toepassingstoken opgeven\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Instellingen voor Pushover-meldingen konden niet opgeslagen worden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Instellingen voor Pushover-meldingen opgeslagen!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Je moet een toegangstoken opgeven\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Je moet een geldige gebruikers- of groepssleutel opgeven\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Instellingen voor Pushbullet-meldingen opgeslagen!\",\n  \"components.IssueDetails.playonplex\": \"Afspelen op {mediaServerName}\",\n  \"components.IssueDetails.play4konplex\": \"Afspelen op {mediaServerName} in 4K\",\n  \"components.IssueDetails.openin4karr\": \"Openen in 4K {arr}\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Aflevering} other {Afleveringen}}\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Seizoen} other {Seizoenen}}\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Onopgeloste problemen\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extra's\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Ontvang een melding wanneer problemen worden opgelost door andere gebruikers.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Probleem opnieuw ingediend\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Ontvang een melding wanneer problemen door andere gebruikers opnieuw worden ingediend.\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Stuur meldingen wanneer problemen opnieuw worden ingediend.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Ontvang een bericht wanneer problemen die jij hebt gemeld, opnieuw worden ingediend.\",\n  \"components.RequestModal.requestseasons4k\": \"{seasonCount} {seasonCount, plural, one {seizoen} other {seizoenen}} aanvragen in 4K\",\n  \"components.RequestModal.requestmovies\": \"{count} {count, plural, one {film} other {films}} aanvragen\",\n  \"components.RequestModal.selectmovies\": \"Films selecteren\",\n  \"components.MovieDetails.productioncountries\": \"Productie{countryCount, plural, one {land} other {landen}}\",\n  \"components.RequestModal.requestmovies4k\": \"{count} {count, plural, one {film} other {films}} in 4K aanvragen\",\n  \"components.TvDetails.productioncountries\": \"Productie{countryCount, plural, one {land} other {landen}}\",\n  \"components.IssueDetails.commentplaceholder\": \"Opmerking toevoegen…\",\n  \"components.RequestModal.requestApproved\": \"Aanvraag voor <strong>{title}</strong> goedgekeurd!\",\n  \"components.RequestModal.approve\": \"Aanvraag goedkeuren\",\n  \"components.Settings.RadarrModal.inCinemas\": \"In de bioscoop\",\n  \"components.Settings.RadarrModal.released\": \"Uitgebracht\",\n  \"components.Settings.RadarrModal.announced\": \"Aangekondigd\",\n  \"components.Settings.Notifications.enableMentions\": \"Vermeldingen inschakelen\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Dienst inschakelen\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Instellingen voor meldingen Gotify opgeslagen!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Toepassingstoken\",\n  \"i18n.importing\": \"Importeren…\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Instellingen voor meldingen Gotify niet opgeslagen.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Testmelding Gotify niet verzonden.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Testmelding Gotify verzonden!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Testmelding Gotify verzenden…\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL server\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Je moet een toepassingstoken opgeven\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Je moet ten minste één meldingstype selecteren\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL mag niet eindigen op een schuine streep\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Je moet een geldige URL opgeven\",\n  \"i18n.import\": \"Importeren\",\n  \"components.UserList.newplexsigninenabled\": \"De instelling <strong>Nieuwe Plex-aanmelding inschakelen</strong> is momenteel ingeschakeld. Plex-gebruikers met bibliotheektoegang hoeven niet te worden geïmporteerd om in te loggen.\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Geavanceerd\",\n  \"components.ManageSlideOver.alltime\": \"Altijd\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Alle seizoenen markeren als beschikbaar in 4K\",\n  \"components.ManageSlideOver.opentautulli\": \"Openen in Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Afgelopen {days, number} dagen\",\n  \"components.ManageSlideOver.playedby\": \"Afgespeeld door\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {keer afgespeeld} other {keer afgespeeld}}\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Kanaal-tag\",\n  \"components.Settings.externalUrl\": \"Externe URL\",\n  \"components.Settings.tautulliApiKey\": \"API-sleutel\",\n  \"components.Settings.tautulliSettings\": \"Instellingen Tautulli\",\n  \"components.Settings.tautulliSettingsDescription\": \"Configureer optioneel de instellingen van jouw Tautulli-server. Seerr haalt de kijkgeschiedenis van jouw Plex-media op van Tautulli.\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Er ging iets mis bij het opslaan van de Tautulli-instellingen.\",\n  \"components.Settings.urlBase\": \"URL-basis\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"URL-basis mag niet eindigen op een schuine streep\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL mag niet eindigen op een schuine streep\",\n  \"components.UserProfile.recentlywatched\": \"Recent bekeken\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Alle seizoenen als beschikbaar markeren\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K-media\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Media\",\n  \"components.Settings.validationApiKey\": \"Je moet een API-sleutel opgeven\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Instellingen Tautulli opgeslagen!\",\n  \"components.Settings.validationUrl\": \"Je moet een geldige URL opgeven\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL-basis moet met een schuine streep beginnen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Gebruikers-ID Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Het <FindDiscordIdLink>meercijferige ID-nummer</FindDiscordIdLink> van je Discord-account\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Je moet een geldige gebruikers-ID van Discord opgeven\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Gegevensmap\",\n  \"components.RequestBlock.languageprofile\": \"Taalprofiel\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Huidige frequentie\",\n  \"components.StatusBadge.managemedia\": \"{mediaType} beheren\",\n  \"components.StatusBadge.openinarr\": \"Openen in {arr}\",\n  \"components.StatusBadge.playonplex\": \"Afspelen op {mediaServerName}\",\n  \"components.UserProfile.emptywatchlist\": \"Media die zijn toegevoegd aan je <PlexWatchlistSupportLink>Plex-kijklijst</PlexWatchlistSupportLink> verschijnen hier.\",\n  \"components.MovieDetails.digitalrelease\": \"Digitale uitgave\",\n  \"i18n.restartRequired\": \"Opnieuw opstarten vereist\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Toestemming geven om de lijst met onlangs toegevoegde media weer te geven.\",\n  \"components.PermissionEdit.viewrecent\": \"Onlangs toegevoegd weergeven\",\n  \"components.Settings.deleteServer\": \"{serverType}-server verwijderen\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} bijgewerkt\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB-ID\",\n  \"components.StatusChecker.restartRequired\": \"Server opnieuw opstarten vereist\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Start de server opnieuw op om de bijgewerkte instellingen toe te passen.\",\n  \"components.TitleCard.cleardata\": \"Gegevens wissen\",\n  \"components.TitleCard.mediaerror\": \"{mediatype} niet gevonden\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB-ID\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.declinerequest\": \"Aanvraag weigeren\",\n  \"components.RequestCard.editrequest\": \"Aanvraag aanpassen\",\n  \"components.RequestCard.cancelrequest\": \"Aanvraag annuleren\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Collectie aanvragen in 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Collectie aanvragen\",\n  \"components.RequestModal.requestseries4ktitle\": \"Serie aanvragen in 4K\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Film aanvragen in 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Serie aanvragen\",\n  \"components.RequestModal.requestmovietitle\": \"Film aanvragen\",\n  \"components.TvDetails.tmdbuserscore\": \"Gebruikersscore TMDB\",\n  \"components.TvDetails.rtaudiencescore\": \"Publieksscore Rotten Tomatoes\",\n  \"components.TvDetails.seasonnumber\": \"Seizoen {seasonNumber}\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Er ging iets mis bij het ophalen van de seizoensgegevens.\",\n  \"components.TvDetails.seasonstitle\": \"Seizoenen\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Jouw kijklijst\",\n  \"components.Discover.plexwatchlist\": \"Jouw kijklijst\",\n  \"components.MovieDetails.physicalrelease\": \"Fysieke uitgave\",\n  \"components.PermissionEdit.autorequest\": \"Automatisch aanvragen\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex-kijklijst synchroniseren\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Series automatisch aanvragen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Automatisch series op je <PlexWatchlistSupportLink>Plex-kijklijst</PlexWatchlistSupportLink> aanvragen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Automatisch films op je <PlexWatchlistSupportLink>Plex-kijklijst</PlexWatchlistSupportLink> aanvragen\",\n  \"components.PermissionEdit.autorequestDescription\": \"Toestemming geven om niet-4K media in je Plex-kijklijst automatisch aan te vragen.\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB-ID\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex-kijklijst\",\n  \"components.MovieDetails.theatricalrelease\": \"Bioscoopuitgave\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Aanvraag automatisch ingediend\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Ontvang een melding wanneer er automatisch nieuwe media-aanvragen worden ingediend voor items op je kijklijst.\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Toestemming geven om niet-4K series in je Plex-kijklijst automatisch aan te vragen.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Plex-kijklijsten weergeven\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Toestemming geven om de Plex-kijklijsten van andere gebruikers te bekijken.\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Details bekijken\",\n  \"components.Settings.advancedTooltip\": \"Als deze instelling onjuist wordt geconfigureerd, kan dit de functionaliteit verstoren\",\n  \"components.StatusChecker.reloadApp\": \"{applicationTitle} opnieuw laden\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Klik op de onderstaande knop om de toepassing opnieuw te laden.\",\n  \"components.UserProfile.plexwatchlist\": \"Plex-kijklijst\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Films automatisch aanvragen\",\n  \"components.TvDetails.manageseries\": \"Serie beheren\",\n  \"components.MovieDetails.managemovie\": \"Film beheren\",\n  \"components.MovieDetails.reportissue\": \"Probleem melden\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Toestemming geven om niet-4K films in je Plex-kijklijst automatisch aan te vragen.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Series automatisch aanvragen\",\n  \"components.PermissionEdit.autorequestMovies\": \"Films automatisch aanvragen\",\n  \"components.Settings.experimentalTooltip\": \"Het inschakelen van deze instelling kan leiden tot onverwacht gedrag van de toepassing\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr moet opnieuw worden gestart om wijzigingen in deze instelling door te voeren\",\n  \"components.AirDateBadge.airedrelative\": \"{relativeTime} uitgezonden\",\n  \"components.AirDateBadge.airsrelative\": \"Uitzending {relativeTime}\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Serie-aanvragen\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# aflevering} other {# afleveringen}}\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.MovieDetails.rtaudiencescore\": \"Publieksscore Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatometer Rotten Tomatoes\",\n  \"components.MovieDetails.tmdbuserscore\": \"Gebruikersscore TMDB\",\n  \"components.RequestBlock.approve\": \"Aanvraag goedkeuren\",\n  \"components.TvDetails.reportissue\": \"Probleem melden\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomatometer Rotten Tomatoes\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"We konden geen match vinden voor deze serie.\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Filmaanvragen\",\n  \"components.Layout.UserDropdown.requests\": \"Aanvragen\",\n  \"components.RequestBlock.decline\": \"Aanvraag weigeren\",\n  \"components.Discover.emptywatchlist\": \"Media die zijn toegevoegd aan je <PlexWatchlistSupportLink>Plex-kijklijst</PlexWatchlistSupportLink> verschijnen hier.\",\n  \"components.RequestBlock.delete\": \"Aanvraag verwijderen\",\n  \"components.RequestBlock.edit\": \"Aanvraag aanpassen\",\n  \"components.RequestBlock.lastmodifiedby\": \"Laatst gewijzigd door\",\n  \"components.RequestBlock.requestdate\": \"Aanvraagdatum\",\n  \"components.RequestBlock.requestedby\": \"Aangevraagd door\",\n  \"components.RequestCard.approverequest\": \"Aanvraag goedkeuren\",\n  \"components.TvDetails.Season.noepisodes\": \"Afleveringenlijst niet beschikbaar.\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Afbeeldingcache\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Afbeeldingen in cache\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Totale cachegrootte\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Afbeeldingcache legen\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Wanneer ingeschakeld in de instellingen, zal Seerr afbeeldingen proxyen en cachen van vooraf geconfigureerde externe bronnen. Gecachete afbeeldingen worden opgeslagen in je configuratiemap. Je kan de bestanden vinden in <code>{appDataPath}/cache/images</code>.\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: seizoen {seasonNumber} aflevering {episodeNumber}\",\n  \"components.RequestCard.unknowntitle\": \"Onbekende titel\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Onbekende titel\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Discover.CreateSlider.needresults\": \"Je moet minstens 1 resultaat hebben.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Geef een TMDB Genre ID op\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Geef een TMDB Network ID op\",\n  \"components.Discover.CreateSlider.nooptions\": \"Geen resultaten.\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Geef een TMDB Keyword ID op\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Zichtbaarheid in-/uitschakelen\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Geef een zoekopdracht op\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Genres zoeken…\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Geef een TMDB Studio ID op\",\n  \"components.Discover.moviegenres\": \"Filmgenres\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Trefwoorden zoeken…\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} serie\",\n  \"components.Discover.customizediscover\": \"Ontdekken aanpassen\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Verwijderen\",\n  \"components.Discover.resetfailed\": \"Er is iets fout gegaan bij het resetten van de instellingen van Ontdekken.\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Media die zijn toegevoegd aan je <PlexWatchlistSupportLink>Plex-kijklijst</PlexWatchlistSupportLink> verschijnen hier.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Jouw kijklijst\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Onlangs toegevoegd\",\n  \"components.Discover.networks\": \"Netwerken\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Studio's zoeken…\",\n  \"components.Discover.CreateSlider.starttyping\": \"Begin met typen om te zoeken.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Je moet een gegevenswaarde opgeven.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Je moet een titel opgeven.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} films\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB-filmtrefwoord\",\n  \"components.Discover.tmdbnetwork\": \"TMDB-netwerk\",\n  \"components.Discover.tmdbsearch\": \"TMDB-zoekopdracht\",\n  \"components.Settings.SettingsMain.apikey\": \"API-sleutel\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Externe afbeeldingen cachen (vereist veel schijfruimte)\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Algemene en standaardinstellingen van Seerr configureren.\",\n  \"components.Settings.SettingsMain.general\": \"Algemeen\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Algemene instellingen\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Beschikbare media verbergen\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Instellingen opgeslagen!\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Slider succesvol verwijderd.\",\n  \"components.Discover.createnewslider\": \"Nieuwe slider maken\",\n  \"components.Discover.resetwarning\": \"Zet alle sliders terug naar standaard. Dit zal ook alle aangepaste sliders verwijderen!\",\n  \"components.Discover.stopediting\": \"Stop met bewerken\",\n  \"components.Discover.studios\": \"Studio's\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB-filmgenre\",\n  \"components.Discover.tmdbstudio\": \"TMDB-studio\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB-genre serie\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB-trefwoord serie\",\n  \"components.Discover.updatesuccess\": \"Instellingen Ontdekken bijgewerkt.\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Populariteit oplopend\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Populariteit aflopend\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Verschijningsdatum oplopend\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Titel oplopend (A-Z)\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Titel aflopend (Z-A)\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB-beoordeling oplopend\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB-beoordeling aflopend\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Slider verwijderen mislukt.\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# filter actief} other {# filters actief}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Series\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Eerste uitzenddatum oplopend\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Populariteit aflopend\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Titel oplopend (A-Z)\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Titel aflopend (Z-A)\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# filter actief} other {# filters actief}}\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Actieve filters wissen\",\n  \"components.Discover.FilterSlideover.filters\": \"Filters\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Eerste uitzenddatum\",\n  \"components.Discover.FilterSlideover.from\": \"Van\",\n  \"components.Discover.FilterSlideover.genres\": \"Genres\",\n  \"components.Discover.FilterSlideover.keywords\": \"Trefwoorden\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Oorspronkelijke taal\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Beoordelingen tussen {minValue} en {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Verschijningsdatum\",\n  \"components.Discover.FilterSlideover.runtime\": \"Speelduur\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minuten looptijd\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB-gebruikersscore\",\n  \"components.Discover.FilterSlideover.to\": \"Tot\",\n  \"components.Discover.resetsuccess\": \"Instellingen Ontdekken succesvol teruggezet.\",\n  \"components.Discover.resettodefault\": \"Terugzetten naar standaard\",\n  \"components.Discover.tvgenres\": \"Seriegenre\",\n  \"components.Discover.updatefailed\": \"Er is iets fout gegaan bij het bijwerken van de instellingen van Ontdekken.\",\n  \"components.Layout.Sidebar.browsemovies\": \"Films\",\n  \"components.Selector.nooptions\": \"Geen resultaten.\",\n  \"components.Selector.searchStudios\": \"Studio's zoeken…\",\n  \"components.Selector.starttyping\": \"Begin met typen om te zoeken.\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Toepassingstitel\",\n  \"components.Settings.SettingsMain.locale\": \"Weergavetaal\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Taal voor Ontdekken\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Inhoud filteren op oorspronkelijke taal\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Gedeeltelijke serie-aanvragen toestaan\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Er ging iets mis bij het genereren van een nieuwe API-sleutel.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Nieuwe API-sleutel gegenereerd!\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Je moet een toepassingstitel opgeven\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL mag niet eindigen op een schuine streep\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# filter actief} other {# filters actief}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Films\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB-beoordeling aflopend\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Verschijningsdatum aflopend\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Populariteit oplopend\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB-beoordeling oplopend\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Eerste uitzenddatum aflopend\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Toepassings-URL\",\n  \"components.Layout.Sidebar.browsetv\": \"Series\",\n  \"components.Selector.searchGenres\": \"Genres selecteren…\",\n  \"components.Selector.searchKeywords\": \"Trefwoorden zoeken…\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Afbeeldingscaching inschakelen\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Je moet een geldige URL opgeven\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Er ging iets mis bij het opslaan van de instellingen.\",\n  \"components.Discover.CreateSlider.addSlider\": \"Slider toevoegen\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Aangepaste slider maken\",\n  \"components.Discover.CreateSlider.addfail\": \"Nieuwe slider maken mislukt.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Nieuwe slider aangemaakt en instellingen Ontdekken opgeslagen.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Slider bewerken\",\n  \"components.Discover.CreateSlider.editfail\": \"Slider bewerken mislukt.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Slider bewerkt en instellingen Ontdekken opgeslagen.\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Naam slider\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streamingdiensten\",\n  \"components.Selector.showless\": \"Minder tonen\",\n  \"components.Selector.showmore\": \"Meer tonen\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Elke {jobScheduleSeconds, plural, one {seconde} other {{jobScheduleSeconds} seconden}}\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Synchronisatie van mediabeschikbaarheid\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Streamingdiensten voor films TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Streamingdiensten voor series TMDB\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName}-URL vereist\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"E-mailadres is ongeldig.\",\n  \"components.Login.description\": \"Aangezien dit de eerste keer is dat je je aanmeldt bij {applicationName}, dien je een geldig e-mailadres op te geven.\",\n  \"components.Login.saving\": \"Toevoegen…\",\n  \"components.ManageSlideOver.removearr\": \"Verwijderen van {arr}\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Aanvragen taggen\",\n  \"components.MovieDetails.openradarr4k\": \"Film openen in 4K-Radarr\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Automatisch een extra label toevoegen met de gebruikers-id en weergavenaam van de aanvrager\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Serietype anime\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Automatisch een extra label toevoegen met de gebruikers-id en weergavenaam van de aanvrager\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName}-instellingen\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"De {mediaServerName}-bibliotheken die op titels worden gescand. Klik op onderstaande knop als er geen bibliotheken in de lijst staan.\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normaliter wordt dit eenmaal per 24 uur uitgevoerd. Seerr zal de lijst met onlangs toegevoegde media op je {mediaServerName}-server vaker controleren. Als dit de eerste keer is dat je Seerr instelt, wordt aanbevolen eenmalig een handmatige, volledige bibliotheekscan uit te voeren!\",\n  \"components.Settings.save\": \"Wijzigingen opslaan\",\n  \"components.Settings.syncJellyfin\": \"Bibliotheken synchoniseren\",\n  \"components.TvDetails.play\": \"Afspelen op {mediaServerName}\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Aantal gebruikersstemmen TMDB\",\n  \"components.Login.save\": \"Toevoegen\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Hiermee wordt deze {mediaType} onomkeerbaar verwijderd van {arr}, inclusief alle bestanden.\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Apparaatstandaard\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Gebruikerse-mail vereisen\",\n  \"components.Settings.SonarrModal.seriesType\": \"Serietype\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName}-instellingen\",\n  \"components.Setup.configuremediaserver\": \"Mediaserver instellen\",\n  \"components.TvDetails.play4k\": \"Afspelen op {mediaServerName} in 4K\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName}-gebruiker\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Er zijn geen {mediaServerName}-gebruikers om te importeren.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Apparaatstandaard\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Meldingsgeluid\",\n  \"components.Login.signinwithjellyfin\": \"{mediaServerName}-account gebruiken\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Aantal stemmen tussen {minValue} en {maxValue}\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Een e-mailadres is vereist.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Een wachtwoord is vereist.\",\n  \"components.Login.credentialerror\": \"Gebruikersnaam of wachtwoord is onjuist.\",\n  \"components.Login.emailtooltip\": \"Het adres hoeft niet gelieerd te zijn aan je {mediaServerName}-instantie.\",\n  \"components.Login.initialsignin\": \"Verbinden\",\n  \"components.Login.initialsigningin\": \"Verbinden…\",\n  \"components.Login.title\": \"E-mail toevoegen\",\n  \"components.Login.username\": \"Gebruikersnaam\",\n  \"components.Login.validationEmailRequired\": \"Je moet een e-mailadres opgeven\",\n  \"components.Login.validationEmailFormat\": \"Ongeldig e-mailadres\",\n  \"components.Login.validationemailformat\": \"Geldig e-mailadres vereist\",\n  \"components.Login.validationhostformat\": \"Geldige URL vereist\",\n  \"components.Login.validationusernamerequired\": \"Gebruikersnaam vereist\",\n  \"components.ManageSlideOver.removearr4k\": \"Verwijderen van 4K-{arr}\",\n  \"components.MovieDetails.downloadstatus\": \"Downloadstatus\",\n  \"components.MovieDetails.imdbuserscore\": \"Gebruikersbeoordeling IMDB – stemmen: {formattedCount}\",\n  \"components.MovieDetails.openradarr\": \"Film openen in Radarr\",\n  \"components.MovieDetails.play\": \"Afspelen op {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Afspelen op {mediaServerName} in 4K\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Meldingsgeluid\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Aanvragen taggen\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Er is iets misgegaan bij het opslaan van de {mediaServerName}-instellingen.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName}-instellingen opgeslagen!\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName}-bibliotheken\",\n  \"components.Settings.manualscanJellyfin\": \"Handmatige bibliotheekscan\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.saving\": \"Opslaan…\",\n  \"components.Settings.syncing\": \"Synchroniseren\",\n  \"components.Settings.timeout\": \"Time-out\",\n  \"components.Setup.signin\": \"Aanmelden\",\n  \"components.Setup.signinWithJellyfin\": \"Vul de Jellyfin gegevens in\",\n  \"components.TitleCard.addToWatchList\": \"Toevoegen aan kijklijst\",\n  \"components.TitleCard.watchlistError\": \"Er is iets misgegaan. Probeer het opnieuw.\",\n  \"components.UserList.importfromJellyfin\": \"{mediaServerName}-gebruikers importeren\",\n  \"components.UserList.importfromJellyfinerror\": \"Er is iets misgegaan bij het importeren van {mediaServerName}-gebruikers.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName}-gebruiker\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Wijzigingen opslaan\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Opslaan…\",\n  \"i18n.collection\": \"Collectie\",\n  \"components.UserProfile.localWatchlist\": \"Kijklijst van {username}\",\n  \"components.Setup.signinWithPlex\": \"Vul de Plex gegevens in\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Configureer optioneel de interne en externe eindpunten voor je {mediaServerName}-server. Meestal verschilt de externe URL van de interne URL. Als je wilt doorverwijzen naar een andere pagina voor wachtwoordherstel, kun je een aangepaste URL voor wachtwoordherstel instellen voor het aanmelden met {mediaServerName}. Je kunt ook de API-sleutel voor Jellyfin wijzigen, die eerder automatisch is gegenereerd.\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Configureer de instellingen voor je {mediaServerName}-server. {mediaServerName} scant je {mediaServerName}-bibliotheken om te zien welke inhoud beschikbaar is.\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> is verwijderd van de kijklijst!\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> is toegevoegd aan de kijklijst!\",\n  \"components.TitleCard.watchlistCancel\": \"kijklijst voor <strong>{title}</strong> is geannuleerd.\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName}-{userCount, plural, one {gebruiker} other {gebruikers}} geïmporteerd!\",\n  \"components.UserList.newJellyfinsigninenabled\": \"De instelling <strong>Nieuwe {mediaServerName}-aanmelding gebruiken</strong> is momenteel ingeschakeld. {mediaServerName}-gebruikers met toegang tot de bibliotheek hoeven niet geïmporteerd te worden om zich te kunnen aanmelden.\",\n  \"components.Login.back\": \"Ga terug\",\n  \"components.Login.invalidurlerror\": \"Kan geen verbinding maken met de {mediaServerName} server.\",\n  \"components.TvDetails.addtowatchlist\": \"Toevoegen aan kijklijst\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"URL basis mag niet eindigen met een schuine streep\",\n  \"components.Selector.returningSeries\": \"Terugkerende serie\",\n  \"components.MovieDetails.addtowatchlist\": \"Toevoegen aan kijklijst\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> is verwijderd van je kijklijst!\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> is toegevoegd aan je kijklijst!\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> is verwijderd van de kijklijst!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Geldig e-mailadres vereist\",\n  \"components.Login.adminerror\": \"Je moet een beheerdersaccount gebruiken om je aan te melden.\",\n  \"components.Selector.inProduction\": \"In productie\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.port\": \"Poort\",\n  \"components.Login.servertype\": \"Servertype\",\n  \"components.Login.validationPortRequired\": \"Je moet een geldig poortnummer opgeven\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"URL-basis moet beginnen met een schuine streep\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL mag niet eindigen met een schuine streep\",\n  \"components.Login.validationservertyperequired\": \"Kies een servertype\",\n  \"components.MovieDetails.removefromwatchlist\": \"Verwijderen van kijklijst\",\n  \"components.MovieDetails.watchlistError\": \"Er is iets misgegaan. Probeer het opnieuw.\",\n  \"components.RequestList.RequestItem.profileName\": \"Profiel\",\n  \"components.Selector.canceled\": \"Geannuleerd\",\n  \"components.Selector.ended\": \"Afgelopen\",\n  \"components.Selector.pilot\": \"Pilot\",\n  \"components.Selector.planned\": \"Gepland\",\n  \"components.Selector.searchStatus\": \"Selecteer status...\",\n  \"components.Settings.invalidurlerror\": \"Kan niet verbinden met de {mediaServerName} server.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"URL bij vergeten wachtwoord\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Er is iets misgegaan bij het synchroniseren van bibliotheken\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Geen bibliotheken gevonden\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Aangepaste authenticatie met automatische bibliotheekgroepering wordt niet ondersteund\",\n  \"components.Setup.back\": \"Ga terug\",\n  \"components.Setup.configemby\": \"Configureer Emby\",\n  \"components.Setup.configjellyfin\": \"Configureer Jellyfin\",\n  \"components.Setup.configplex\": \"Configureer Plex\",\n  \"components.Setup.servertype\": \"Kies servertype\",\n  \"components.Setup.signinWithEmby\": \"Vul de Emby gegevens in\",\n  \"components.Setup.subtitle\": \"Begin met het kiezen van je mediaserver\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.TvDetails.removefromwatchlist\": \"Verwijderen uit kijklijst\",\n  \"components.TvDetails.watchlistError\": \"Er is iets misgegaan. Probeer het opnieuw.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> is toegevoegd aan de kijklijst!\",\n  \"components.UserList.username\": \"Gebruikersnaam\",\n  \"components.UserList.validationUsername\": \"Je moet een gebruikersnaam opgeven\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"E-mailadres vereist\",\n  \"components.Login.enablessl\": \"Gebruik SSL\",\n  \"components.Login.urlBase\": \"URL basis\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Streamingdiensten tonen op regionale beschikbaarheid\",\n  \"components.Settings.scanbackground\": \"Het scannen gebeurt op de achtergrond. In de tussentijd kun je verdergaan met het instelproces.\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Streamingdiensten tonen op regionale beschikbaarheid\",\n  \"components.RequestList.RequestItem.removearr\": \"Verwijderen van {arr}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Regio voor Ontdekken\",\n  \"components.Settings.apiKey\": \"API-sleutel\",\n  \"components.RequestList.sortDirection\": \"Sorteerrichting wisselen\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Je moet een geldige Discord Role ID opgeven\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Role-id melding\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"De role-id die in het webhook-bericht vermeld moet worden. Laat leeg om vermeldingen uit te zetten\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Gebruikersavatars\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Regio voor Ontdekken\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Inhoud filteren op regionale beschikbaarheid\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Regio voor streamen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Inhoud filteren op regionale beschikbaarheid\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Regio voor streamen\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Deze e-mail is bezet!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Een andere gebruiker heeft deze gebruikersnaam al. Je moet een e-mail instellen\",\n  \"i18n.specials\": \"Specials\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex-verversingstoken\",\n  \"components.Settings.tip\": \"Tip\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Gebruik de netwerkparameters van je container/systeem in plaats van deze instellingen. Zie de {docs} voor meer informatie.\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Aankomende series\",\n  \"components.Settings.OverrideRuleModal.create\": \"Regel aanmaken\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Als je groepschat topics heeft, kun je hier een thread-/topic-ID opgeven\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Sleutelwoorden\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Aanvragen voor speciale afleveringen toestaan\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"Schakel deze instelling NIET in tenzij je begrijpt wat je doet!\",\n  \"components.Settings.SettingsNetwork.network\": \"Netwerk\",\n  \"components.Login.loginwithapp\": \"Meld je aan met {appName}\",\n  \"components.Settings.Notifications.messageThreadId\": \"Thread-/topic-ID\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Specificeert welke instellingen worden aangepast als aan bovenstaande voorwaarden wordt voldaan.\",\n  \"components.Settings.addrule\": \"Nieuwe uitzonderingsregel\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Het is niet gelukt om met je gegevens met {mediaServerName} te verbinden\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Als je groepschat topics heeft, kun je hier een thread-/topic-ID opgeven\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Specificeert voorwaarden voor het toepassen van parameterveranderingen. Ieder veld moet gevalideerd worden om de regel toe te passen (EN-operatie). Een veld is geldig als een van de eigenschappen overeenkomen (OF-operatie).\",\n  \"components.Selector.searchUsers\": \"Gebruikers selecteren…\",\n  \"components.Settings.overrideRulesDescription\": \"Uitzonderingsregels laten je eigenschappen selecteren die worden vervangen als een aanvraag met de regel overeenkomt.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Verbinden met Plex met je gegevens mislukt\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Voer je {mediaServerName}-gegevens in om je account aan {applicationName} te koppelen.\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"De thread-/topic-ID moet een positief geheel getal zijn\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Gebruik ',' als scheidingsteken en '*.' als joker voor subdomeinen\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Aanmelden met {mediaServerName} inschakelen\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Gekoppelde accounts\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Kwaliteitsprofiel selecteren\",\n  \"components.Settings.OverrideRuleTile.users\": \"Gebruikers\",\n  \"components.Setup.librarieserror\": \"Validatie mislukt. Schakel de bibliotheken opnieuw in en uit om verder te gaan.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Je hebt geen toestemming om de gekoppelde accounts van deze gebruiker aan te passen.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Thread-/topic-ID\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Dit account is al gekoppeld aan een {applicationName}-gebruiker\",\n  \"components.Login.noadminerror\": \"Geen administratorgebruiker gevonden op de server.\",\n  \"components.Login.orsigninwith\": \"Of meld je aan met\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Labels\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Voorwaarden\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Nieuwe uitzonderingsregel\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Uitzonderingsregel bewerken\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Genres\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Talen\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Geen labels.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Kwaliteitsprofiel\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Hoofdmap\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Uitzonderingsregel aangemaakt!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Uitzonderingsregel bijgewerkt!\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Hoofdmap selecteren\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Dienst selecteren\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Labels selecteren\",\n  \"components.Settings.OverrideRuleModal.service\": \"Dienst\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Deze regel op de geselecteerde dienst toepassen.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Instellingen\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Labels\",\n  \"components.Settings.OverrideRuleModal.users\": \"Gebruikers\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Voorwaarden\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Genre\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Sleutelwoorden\",\n  \"components.Settings.OverrideRuleTile.language\": \"Taal\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Kwaliteitsprofiel\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Hoofdmap\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Instellingen\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"CSRF-bescherming inschakelen\",\n  \"components.Settings.SettingsNetwork.docs\": \"documentatie\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Stel externe API-toegang in op alleen-lezen (HTTPS vereist)\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Dwing Seerr om eerst IPv4-addressen te herleiden, in plaats van IPv6\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Eerst IPv4 herleiden forceren\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Netwerkinstellingen\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S)-proxy\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Er is iets misgegaan bij het opslaan van de instellingen.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Instellingen opgeslagen!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Proxy-ondersteuning inschakelen\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Je dient een geldige poort op te geven\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Aanmeldmethodes\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Configureer aanmeldmethodes voor gebruikers.\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Sta gebruikers toe zich aan te melden met hun {mediaServerName}-account\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Configureer de netwerkinstellingen van je Seerr-instantie.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Adressen genegeerd door proxy\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Proxy omzeilen voor lokale adressen\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Proxy-hostnaam\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Proxy-wachtwoord\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Proxy-poort\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"SSL gebruiken voor proxy\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Proxy-gebruikersnaam\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Stelt Seerr in staat om IP-adressen van clënten achter een proxy juist te registreren\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Er dient ten minste één authenticatiemethode te worden geselecteerd.\",\n  \"components.Settings.menuNetwork\": \"Netwerk\",\n  \"components.Settings.overrideRules\": \"Uitzonderingsregels\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Er is een onbekende fout opgetreden\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Wachtwoord\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Je dient een wachtwoord op te geven\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Koppelen\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Toevoegen…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"{mediaServerName}-account koppelen\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Gebruikersnaam\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Je dient een gebruikersnaam op te geven\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Gekoppeld account verwijderen mislukt.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Er is een onbekende fout opgetreden\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Deze externe accounts zijn gekoppeld aan je {applicationName}-account.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Er zijn geen externe accounts aan je account gekoppeld.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Dit account is al gekoppeld aan een Plex-gebruiker\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Gekoppelde accounts\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"Het thread-/topic-ID dient een positief geheel getal te zijn\",\n  \"components.Settings.no\": \"Nee\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Onbekend\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Je dient een geldige URL op te geven\",\n  \"components.Discover.FilterSlideover.certification\": \"Kijkwijzer\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Sleutelwoorden uitsluiten\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Probleembeschrijving\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Selecteer een metadataprovider\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Geen opties beschikbaar\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Selecteer een land\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Begin met typen om te zoeken.\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Prioriteit\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Wachtwoord\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Testmelding Ntfy niet verzonden.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Testmelding Ntfy verzenden…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Testmelding Ntfy verzonden!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Je moet minstens één meldingstype selecteren\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Actief adres\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Leeftijd\",\n  \"components.Settings.SettingsJobsCache.size\": \"Grootte\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"API-sleutel gekopieerd naar klembord.\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Beschikbare media weglaten uit de ontdekpagina's maar niet uit zoekresultaten\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube-URL\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNS-cache\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Alle gekozen metadataproviders zijn werkend\",\n  \"components.Settings.connectionTestFailed\": \"Verbindingstest mislukt\",\n  \"components.Settings.failed\": \"Werkt niet\",\n  \"components.Settings.general\": \"Algemeen\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} is geen TMDB-sleutelwoord.\",\n  \"components.Settings.menuMetadataProviders\": \"Metadataproviders\",\n  \"components.Settings.metadataProviderSelection\": \"Selectie metadataproviders\",\n  \"components.Settings.metadataProviderSettings\": \"Metadataproviders\",\n  \"components.Settings.metadataSettings\": \"Instellingen voor metadataprovider\",\n  \"components.Settings.metadataSettingsSaved\": \"Instellingen voor metadataprovider opgeslagen\",\n  \"components.Settings.nooptions\": \"Geen resultaten.\",\n  \"components.Settings.notTested\": \"Niet getest\",\n  \"components.Settings.operational\": \"Operationeel\",\n  \"components.Settings.providerStatus\": \"Status metadataprovider\",\n  \"components.Settings.searchKeywords\": \"Sleutelwoorden zoeken…\",\n  \"components.Settings.seriesMetadataProvider\": \"Metadataprovider series\",\n  \"components.Settings.settings\": \"Instellingen\",\n  \"components.Settings.starttyping\": \"Begin met typen om te zoeken.\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"De provider TMDB werkt niet; selecteer een andere\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"De provider TVDB werkt niet; selecteer een andere\",\n  \"components.Settings.valueRequired\": \"Je dient een waarde op te geven.\",\n  \"components.Settings.yes\": \"Ja\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Browser\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Aangemaakt\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Abonnement verwijderen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Apparaat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Apparaten beheren\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Besturingssysteem\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Abonnement verwijderd.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Er is iets misgegaan bij het verwijderen van het abonnement.\",\n  \"i18n.completed\": \"Voltooid\",\n  \"i18n.deleted\": \"Verwijderd\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Selecteer een certificatie\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Je moet een prioriteitsgetal instellen\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Agent inschakelen\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Poster insluiten\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Server root URL\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Poster insluiten\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Poster insluiten\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"URL-variabelen ondersteunen\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Beschikbare variabelen worden beschreven in de sectie voor webhook-sjabloonvariabelen\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"De URL voor de meldingstest wordt ingesteld op {testUrl} in plaats van de werkelijke webhook-URL.\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Poster insluiten\",\n  \"components.Settings.Notifications.embedPoster\": \"Poster insluiten\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNS-cache\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr cachet DNS-lookups om prestaties te optimaliseren en onnodige API-calls te voorkomen.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Globale statistieken DNS-cache\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"These statistieken zijn verzameld over alle DNS cacheentries.\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"{hostname} DNS-cache geleegd.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Treffers\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Missers\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Hostnaam\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Elke {jobScheduleDays, plural, one {dag} other {{jobScheduleDays} dagen}}\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Fouten\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"DNS-cache leegmaken\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Trefferpercentage\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Treffers\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4-fallbacks\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Missers\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URL mag niet eindigen met een schuine streep\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"Basis-URL voor YouTube-video's als een zelfgehoste YouTube-instantie wordt gebruikt.\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"Maximale TTL DNS-cache\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"Minimale TTL DNS-cache\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"Schakel dit NIET in als je problemen ondervindt met DNS-lookups\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Schakel het cachen van DNS-zoekopdrachten in om de prestaties te optimaliseren en onnodige API-verzoeken te voorkomen\",\n  \"components.Settings.animeMetadataProvider\": \"Metadataprovider anime\",\n  \"components.Settings.chooseProvider\": \"Kies metadataproviders voor verschillende typen inhoud\",\n  \"components.Settings.clickTest\": \"Druk op de knop \\\"Testen\\\" om de verbinding met metadataproviders te controleren\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Opslaan instellingen metadataproviders mislukt\",\n  \"components.Settings.noSpecialCharacters\": \"De configuratie moet een door komma's gescheiden lijst van TMDB-trefwoord-ID's zijn en mag niet met een komma beginnen of eindigen.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Web-push uitschakelen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Er is iets misgegaan bij het uitschakelen van web-push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Web-push inschakelen\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Er is iets misgegaan bij het inschakelen van web-push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Engine\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Er zijn geen webpush-abonnementen om weer te geven.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"type\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Web-push is uitgschakeld.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Web-push is ingeschakeld.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Opslaan instellingen web-pushmeldingen mislukt.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Opslaan instellingen web-pushmeldingen gelukt!\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Kon certificaten niet laden\",\n  \"components.Selector.CertificationSelector.minRating\": \"Minimum beoordeling\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Tokenauthenticatie\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Gebruikersnaam + Wachtwoord authenticatie\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Maximum beoordeling\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Ntfy notificatie-instellingen konden niet worden opgeslagen.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Ntfy notificatie-instellingen succesvol opgeslagen!\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Onderwerp\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Gebruikersnaam\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Je moet een onderwerp invullen\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Je moet een geldige URL invullen\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Over Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Een bijdrage doen\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Seerr ondersteunen\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"U moet een geldige maximale TTL-waarde opgeven\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"U moet een geldige minimale TTL-waarde opgeven\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Actief abonnement\",\n  \"component.BlocklistBlock.blocklistdate\": \"Datum geblokkeerd\",\n  \"component.BlocklistBlock.blocklistedby\": \"Geblokkeerd door\",\n  \"component.BlocklistModal.blocklisting\": \"Blokkeren\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> staat niet op de blokkeerlijst.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Geblokkeerde media beheren.\",\n  \"components.Blocklist.blocklistdate\": \"datum\",\n  \"components.Blocklist.blocklistedby\": \"{date} door {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Instellingen blokkeerlijst\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Geblokkeerde labels\",\n  \"components.Blocklist.filterManual\": \"Handmatig\",\n  \"components.Blocklist.mediaName\": \"Naam\",\n  \"components.Blocklist.mediaTmdbId\": \"TMDB-id\",\n  \"components.Blocklist.mediaType\": \"Type\",\n  \"components.Blocklist.showAllBlocklisted\": \"Alle geblokkeerde media tonen\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Verbinden met {services} is niet mogelijk. Mogelijk is niet alle informatie beschikbaar.\",\n  \"components.Layout.Sidebar.blocklist\": \"Blokkeerlijst\",\n  \"components.PermissionEdit.blocklistedItems\": \"Media blokkeren.\",\n  \"components.PermissionEdit.manageblocklist\": \"Blokkeerlijst beheren\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Geblokkeerde media weergeven\",\n  \"components.RequestList.unableToConnect\": \"Verbinden met {services} is niet mogelijk. Mogelijk is niet alle informatie beschikbaar.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Er zijn nog geen DNS-lookup gecachet.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Geblokkeerde labels verwerken\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Geblokkeerde items verbergen\",\n  \"components.Settings.blocklistedTagsText\": \"Geblokkeerde labels\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Weet je zeker dat je de geblokkeerde labels wilt wissen?\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Niets om te kopiëren\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Configuratie voor geblokkeerde labels kopiëren\",\n  \"i18n.addToBlocklist\": \"Aan blokkeerlijst toevoegen\",\n  \"i18n.blocklist\": \"Blokkeren\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> staat al op de blokkeerlijst.\",\n  \"i18n.blocklistError\": \"Er is iets misgegaan. Probeer het opnieuw.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> is succesvol geblokkeerd.\",\n  \"i18n.blocklisted\": \"Geblokkeerd\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> is succesvol verwijderd van de blokkeerlijst.\",\n  \"i18n.removefromBlocklist\": \"Verwijderen van blokkeerlijst\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Toestemming geven om geblokkeerde media te beheren.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Toestemming geven om media te blokkeren.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Toestemming geven om geblokkeerde media te bekijken.\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Inhoud met labels blokkeren\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Limiteer geblokkeerde inhoud per tag\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"De \\\"Verwerk geblokkeerde tags\\\" taak zal maximaal dit aantal pagina's per sortering blokkeren. Grotere aantallen zorgen voor een nauwkeurigere blokkeerlijst, maar nemen meer ruimte in beslag.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Automatisch content met tags toevoegen aan de blokkeerlijst met behulp van de \\\"Geblokkeerde tags verwerken\\\" taak\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Verberg geblokkeerde items op de ontdekkingspagina's voor alle gebruikers met de 'Blokkeerlijst beheren' machtiging\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"API-verzoek time-out\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Maximale wachttijd (in seconden) voor reacties van externe services zoals Radarr/Sonarr. Stel in op 0 voor geen time-out.\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Stuur ALLE uitgaande HTTP/HTTPS-verzoeken via een proxyserver (host/poort). Schakelt GEEN HTTPS-, SSL- of certificaatconfiguratie in.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"U moet een geldige time-outwaarde opgeven\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Plak hieronder de configuratie van de blokkeerlijsttag.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Importeer Configuratie van Geblokkeerde Tags\",\n  \"components.Settings.copyBlocklistedTags\": \"Geblokkeerde tags gekopieerd.\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Importeer Geblokkeerde Tags Configuratie\"\n}\n"
  },
  {
    "path": "src/i18n/locale/pl.json",
    "content": "{\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Montowanie woluminu <code>{appDataPath}</code> nie zostało poprawnie skonfigurowane. Wszystkie dane zostaną wyczyszczone po zatrzymaniu lub ponownym uruchomieniu kontenera.\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Filmy {genre}\",\n  \"components.Discover.popularmovies\": \"Popularne filmy\",\n  \"components.LanguageSelector.languageServerDefault\": \"Domyślny ({language})\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr wersja deweloperska\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr wersja stabilna\",\n  \"components.Login.email\": \"Adres e-mail\",\n  \"components.Login.forgotpassword\": \"Zapomniane hasło?\",\n  \"components.Login.password\": \"Hasło\",\n  \"components.Login.loginerror\": \"Coś poszło nie tak przy próbie logowania.\",\n  \"components.Login.signin\": \"Zaloguj\",\n  \"components.Login.signingin\": \"Logowanie…\",\n  \"components.Login.signinheader\": \"Zaloguj się aby kontynuować\",\n  \"components.Login.signinwithoverseerr\": \"Użyj swojego konta {applicationTitle}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Czy na pewno chcesz usunąć ten komentarz?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Usuń komentarz\",\n  \"components.IssueDetails.IssueComment.edit\": \"Edytuj komentarz\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Musisz wpisać wiadomość\",\n  \"components.IssueDetails.openedby\": \"#{issueId} otwarty przez {username} {relativeTime}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Prześlij problem\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Raport o problemie dla <strong>{title}</strong> przesłany pomyślnie!\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Coś poszło nie tak podczas zgłaszania problemu.\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Usuń problem\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Edytuj opis\",\n  \"components.IssueDetails.allepisodes\": \"Wszystkie odcinki\",\n  \"components.IssueDetails.allseasons\": \"Wszystkie sezony\",\n  \"components.IssueDetails.closeissue\": \"Zamknij problem\",\n  \"components.IssueDetails.closeissueandcomment\": \"Zamknij z komentarzem\",\n  \"components.IssueDetails.comments\": \"Komentarze\",\n  \"components.IssueDetails.episode\": \"Odcinek {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Problem\",\n  \"components.IssueDetails.lastupdated\": \"Ostatnio zaktualizowane\",\n  \"components.IssueDetails.leavecomment\": \"Komentarz\",\n  \"components.IssueDetails.openinarr\": \"Otwórz w {arr}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Coś poszło nie tak podczas edytowania opisu problemu.\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Podczas usuwania problemu coś poszło nie tak.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Coś poszło nie tak podczas aktualizowania stanu problemu.\",\n  \"components.IssueDetails.unknownissuetype\": \"Nieznany\",\n  \"components.ManageSlideOver.openarr\": \"Otwórz w {arr}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Dodatki\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Dotknięty odcinek\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Dotknięty sezon\",\n  \"components.IssueList.sortAdded\": \"Najnowsze\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Wyświetl problem\",\n  \"components.IssueModal.issueSubtitles\": \"Napisy\",\n  \"components.IssueModal.issueVideo\": \"Wideo\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Otwarte problemy\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Prośby\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Prośba o oczekuje na zatwierdzenie\",\n  \"components.PermissionEdit.admin\": \"Admin\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Automatyczne zatwierdzanie filmów 4K\",\n  \"components.IssueDetails.openin4karr\": \"Otwórz w 4K {arr}\",\n  \"components.IssueDetails.issuetype\": \"Typ\",\n  \"components.IssueDetails.nocomments\": \"Brak komentarzy.\",\n  \"components.IssueDetails.problemepisode\": \"Odcinek, którego dotyczy problem\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Status\",\n  \"components.IssueList.IssueItem.issuetype\": \"Typ\",\n  \"components.IssueList.IssueItem.opened\": \"Otwarty\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} przez {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Odcinek, którego dotyczy problem\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Nieznany\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Odcinek {episodeNumber}\",\n  \"components.IssueList.IssueItem.viewissue\": \"Zobacz problem\",\n  \"components.IssueList.issues\": \"Problemy\",\n  \"components.IssueList.showallissues\": \"Pokaż wszystkie problemy\",\n  \"components.IssueList.sortModified\": \"Ostatnio zmodyfikowane\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Wszystkie odcinki\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Wszystkie sezony\",\n  \"components.Login.signinwithplex\": \"Użyj swojego konta Plex\",\n  \"components.Login.validationemailrequired\": \"Musisz podać prawidłowy adres e-mail\",\n  \"components.Login.validationpasswordrequired\": \"Musisz podać hasło\",\n  \"components.ManageSlideOver.downloadstatus\": \"Pobierane\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Wszystkie języki\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Język wyświetlania\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Szukaj filmów i seriali\",\n  \"components.Layout.Sidebar.dashboard\": \"Odkryj\",\n  \"components.Layout.Sidebar.issues\": \"Problemy\",\n  \"components.Layout.Sidebar.requests\": \"Prośby\",\n  \"components.Layout.Sidebar.settings\": \"Ustawienia\",\n  \"components.Layout.Sidebar.users\": \"Użytkownicy\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Layout.UserDropdown.settings\": \"Ustawienia\",\n  \"components.Layout.UserDropdown.signout\": \"Wyloguj się\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commity}} za\",\n  \"components.Layout.VersionStatus.outofdate\": \"Nieaktualny\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Wyczyść dane\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Brak próśb.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Komentarz do problemu\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Wysyłaj powiadomienia, gdy problemy otrzymają nowe komentarze.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Zgłoszono problem\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Wysyłaj powiadomienia, gdy zostaną zgłoszone problemy.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problem rozwiązany\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Wysyłaj powiadomienia, gdy problemy zostaną rozwiązane.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Prośba o automatyczne zatwierdzenie\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Wysyłaj powiadomienia, gdy użytkownicy składają nowe prośby o media, które są automatycznie zatwierdzane.\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Wysyłaj powiadomienia, gdy prośby o multimedia zostaną ręcznie zatwierdzone.\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Wysyłaj powiadomienia, gdy prośby o multimedia staną się dostępne.\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Wysyłaj powiadomienia, gdy prośby o multimedia zostaną odrzucone.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Przetwarzanie żądania nie powiodło się\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Przyznaj automatyczne zatwierdzanie próśb o filmy inne niż 4K.\",\n  \"components.PermissionEdit.createissues\": \"Zgłoś problemy\",\n  \"components.PermissionEdit.manageissues\": \"Zarządzaj problemami\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Udziel uprawnień do zarządzania problemami z multimediami.\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Spowoduje to nieodwracalne usunięcie wszystkich danych dla {mediaType}, w tym wszelkie prośby. Jeśli ten element istnieje w Twojej bibliotece {mediaServerName}, informacje o multimediach zostaną odtworzone podczas następnego skanowania.\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Podaj szczegółowe wyjaśnienie napotkanego problemu.\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Co jest nie tak?\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Gatunki filmowe\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Gatunki seriali\",\n  \"components.Discover.recentrequests\": \"Ostatnie prośby\",\n  \"components.Discover.upcomingmovies\": \"Nadchodzące filmy\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Zgłoś problem\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Sezon {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Musisz podać opis\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Otwórz ponownie z komentarzem\",\n  \"components.IssueModal.issueOther\": \"Inny\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Filmy\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Gatunki filmowe\",\n  \"components.Discover.upcoming\": \"Nadchodzące filmy\",\n  \"components.IssueDetails.problemseason\": \"Sezon, którego dotyczy problem\",\n  \"components.IssueDetails.season\": \"Sezon {seasonNumber}\",\n  \"components.IssueDetails.toastissuedeleted\": \"Pomyślnie usunięto problem!\",\n  \"components.CollectionDetails.overview\": \"Podsumowanie\",\n  \"components.Discover.StudioSlider.studios\": \"Studia\",\n  \"components.Discover.discover\": \"Odkryj\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Gatunki seriali\",\n  \"components.Discover.recentlyAdded\": \"Niedawno dodane\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Pomyślnie edytowano opis problemu!\",\n  \"components.IssueDetails.IssueDescription.description\": \"Opis\",\n  \"components.IssueDetails.toaststatusupdated\": \"Pomyślnie zaktualizowano status problemu!\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Czy na pewno chcesz usunąć ten problem?\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Otrzymuj powiadomienia, gdy problemy zgłoszone przez ciebie otrzymają nowe komentarze.\",\n  \"components.MovieDetails.overview\": \"Przegląd\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Otrzymuj powiadomienia, gdy Twoje prośby o multimedia staną się dostępne.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Przyznaj automatyczne zatwierdzanie próśb o seriale 4K.\",\n  \"components.IssueDetails.deleteissue\": \"Usuń problem\",\n  \"components.MovieDetails.budget\": \"Budżet\",\n  \"components.MovieDetails.mark4kavailable\": \"Oznacz jako dostępne w 4K\",\n  \"components.IssueDetails.play4konplex\": \"Odtwarzanie w 4K na platformie {mediaServerName}\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.IssueDetails.reopenissue\": \"Otwórz ponownie problem\",\n  \"components.MovieDetails.recommendations\": \"Rekomendacje\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Przyznaj automatyczne zatwierdzanie wszystkich próśb o media 4K.\",\n  \"components.MovieDetails.watchtrailer\": \"Obejrzyj zwiastun\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Otrzymuj powiadomienia, gdy inni użytkownicy skomentują problem.\",\n  \"components.MovieDetails.showless\": \"Pokaż mniej\",\n  \"components.MovieDetails.similar\": \"Podobne tytuły\",\n  \"components.ManageSlideOver.markavailable\": \"Oznacz jako dostępne\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Zobacz więcej\",\n  \"components.PermissionEdit.adminDescription\": \"Pełny dostęp administratora. Omija wszystkie inne kontrole uprawnień.\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Zarządzaj {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Oznacz jako dostępne w 4K\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Otrzymuj powiadomienia, gdy inni użytkownicy zgłaszają problemy.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Otrzymuj powiadomienia, gdy zgłoszone przez ciebie problemy zostaną rozwiązane.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Otrzymuj powiadomienia, gdy Twoje prośby o multimedia zostaną odrzucone.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Automatycznie zatwierdzaj 4K\",\n  \"components.ManageSlideOver.openarr4k\": \"Otwórz w 4K {arr}\",\n  \"components.ManageSlideOver.tvshow\": \"seria\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Pełna obsada\",\n  \"components.MovieDetails.cast\": \"Obsada\",\n  \"components.MovieDetails.markavailable\": \"Oznacz jako dostępne\",\n  \"components.MovieDetails.revenue\": \"Dochody\",\n  \"components.MovieDetails.originallanguage\": \"Język oryginału\",\n  \"components.MovieDetails.originaltitle\": \"Tytuł oryginalny\",\n  \"components.MovieDetails.overviewunavailable\": \"Przegląd niedostępny.\",\n  \"components.MovieDetails.showmore\": \"Pokaż więcej\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Typy powiadomień\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Otrzymuj powiadomienia, gdy Twoje prośby o multimedia zostaną zatwierdzone.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Otrzymuj powiadomienia, gdy inni użytkownicy prześlą nowe prośby o multimedia, które wymagają zatwierdzenia.\",\n  \"components.PermissionEdit.autoapprove\": \"Automatycznie zatwierdzaj\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Automatyczne zatwierdzanie filmów\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Przyznaj automatyczne zatwierdzanie próśb o filmy inne niż 4K.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Udziel pozwolenia na przesyłanie próśb o seriale inne niż 4K.\",\n  \"components.PersonDetails.appearsin\": \"Wystąpienia\",\n  \"components.PersonDetails.alsoknownas\": \"Znany również jako: {names}\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Przyznaj uprawnienia do przeglądania problemów z multimediami zgłoszonych przez innych użytkowników.\",\n  \"components.QuotaSelector.unlimited\": \"Bez ograniczeń\",\n  \"components.RegionSelector.regionDefault\": \"Wszystkie regiony\",\n  \"components.RegionSelector.regionServerDefault\": \"Domyślny ({region})\",\n  \"components.RequestBlock.profilechanged\": \"Profil jakości\",\n  \"components.RequestBlock.server\": \"Serwer docelowy\",\n  \"components.RequestBlock.requestoverrides\": \"Zastąpienia żądań\",\n  \"components.RequestBlock.rootfolder\": \"Folder główny\",\n  \"components.RequestButton.approverequest\": \"Zatwierdź prośbę\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} - {deathdate}\",\n  \"components.RequestButton.requestmore\": \"Poproś o więcej\",\n  \"components.RequestCard.deleterequest\": \"Usuń prośbę\",\n  \"components.RequestButton.declinerequest\": \"Odrzuć prośbę\",\n  \"components.RequestButton.viewrequest\": \"Zobacz prośbę\",\n  \"components.RequestButton.requestmore4k\": \"Poproś o więcej w 4K\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Brak tagów.\",\n  \"components.RequestList.sortModified\": \"Ostatnio zmodyfikowany\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Zaawansowane\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Domyślnie)\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Profil językowy\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Przyznaj uprawnienia do zarządzania prośbami o multimedia. Wszystkie prośby złożone przez użytkownika z tym uprawnieniem zostaną automatycznie zatwierdzone.\",\n  \"components.PermissionEdit.request4k\": \"Poproś o 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Udziel zgody na przesyłanie próśb o multimedia 4K.\",\n  \"components.PermissionEdit.request4kMovies\": \"Poproś o filmy 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Udziel zgody na przesyłanie próśb o filmy 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Udziel zgody na przesyłanie próśb o seriale 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Poproś o filmy\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Udziel pozwolenia na przesyłanie próśb o filmy inne niż 4K.\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Anuluj prośbę\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Usuń prośbę\",\n  \"components.RequestList.RequestItem.editrequest\": \"Edytuj prośbę\",\n  \"components.RequestList.RequestItem.modified\": \"Zmodyfikowano\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} przez {user}\",\n  \"components.RequestList.RequestItem.requested\": \"Prośba zgłoszona\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Prośba zgłoszona\",\n  \"components.RequestList.showallrequests\": \"Pokaż wszystkie prośby\",\n  \"components.RequestList.sortAdded\": \"Najnowsze\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Serwer docelowy\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Profil jakości\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Folder główny\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Wybierz tagi\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Tagi\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.PermissionEdit.viewrequests\": \"Wyświetl prośby\",\n  \"components.PermissionEdit.users\": \"Zarządzanie użytkownikami\",\n  \"components.PermissionEdit.viewissues\": \"Wyświetl problemy\",\n  \"components.PersonDetails.birthdate\": \"Urodzony {birthdate}\",\n  \"components.PermissionEdit.usersDescription\": \"Udziel uprawnień do zarządzania użytkownikami. Użytkownicy z tym uprawnieniem nie mogą modyfikować użytkowników z uprawnieniami administratora ani ich udzielać.\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Filmy po {language}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Seriale z {network}\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Filmy studia {studio}\",\n  \"components.Discover.NetworkSlider.networks\": \"Platformy\",\n  \"components.Discover.populartv\": \"Popularne seriale\",\n  \"components.Discover.trending\": \"Popularne\",\n  \"components.Discover.upcomingtv\": \"Nadchodzące seriale\",\n  \"components.DownloadBlock.estimatedtime\": \"Szacowany czas {time}\",\n  \"components.RequestModal.seasonnumber\": \"Sezon {number}\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON payload zresetowany pomyślnie!\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Template Variable Help\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Wysłano powiadomienie testowe webhook!\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Zawsze używaj STARTTLS\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Klucz prywatny PGP\",\n  \"components.Settings.Notifications.sendSilently\": \"Wysyłaj po cichu\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Wysyłaj powiadomienia bez dźwięku\",\n  \"components.Settings.Notifications.senderName\": \"Nazwa nadawcy\",\n  \"components.Settings.Notifications.smtpHost\": \"Host SMTP\",\n  \"components.Settings.Notifications.smtpPort\": \"Port SMTP\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Nie udało się zapisać ustawień powiadomień Telegram.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Ustawienia powiadomień Telegram zostały zapisane pomyślnie!\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Nie udało się wysłać powiadomienia testowego Discord.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Wysłanie powiadomienia testowego Discord…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Powiadomienie testowe Discord wysłane!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Nie udało się wysłać testowego powiadomienia e-mail.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Wysyłanie powiadomienia testowego e-mail…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Wysłano powiadomienie testowe e-mail!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Nie udało się wysłać powiadomienia testowego Telegram.\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Wysłano powiadomienie testowe Telegram!\",\n  \"components.Settings.RadarrModal.hostname\": \"Nazwa hosta lub adres IP\",\n  \"components.Settings.RadarrModal.servername\": \"Nazwa serwera\",\n  \"components.Settings.RadarrModal.ssl\": \"Użyj SSL\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Musisz dostarczyć poprawny payload JSON\",\n  \"components.Settings.RadarrModal.add\": \"Dodaj serwer\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Brak tagów.\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Musisz podać poprawny adres URL\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Ładowanie tagów…\",\n  \"components.PersonDetails.crewmember\": \"Ekipa\",\n  \"components.RequestButton.approverequest4k\": \"Zatwierdź prośbę 4K\",\n  \"components.RequestButton.declinerequest4k\": \"Odrzuć prośbę o 4K\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.requestseasons\": \"Poproś o {seasonCount} {seasonCount, plural, one {sezon} other {sezony}}\",\n  \"components.RequestModal.selectseason\": \"Wybierz sezon(y)\",\n  \"components.ResetPassword.gobacklogin\": \"Wróć do strony logowania\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Link do resetowania hasła zostanie wysłany na podany adres e-mail, jeśli jest on powiązany z użytkownikiem.\",\n  \"components.ResetPassword.resetpassword\": \"Zresetuj swoje hasło\",\n  \"components.ResetPassword.validationemailrequired\": \"Musisz podać prawidłowy adres e-mail\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Hasła muszą być zgodne\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Hasło jest zbyt krótkie; powinno mieć co najmniej 8 znaków\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Musisz podać hasło\",\n  \"components.Search.search\": \"Szukaj\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Token dostępu (Access Token)\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink> Zarejestruj aplikację</ApplicationRegistrationLink> do użytku z Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Nie udało się zapisać ustawień powiadomień Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Ustawienia powiadomień Pushover zapisane pomyślnie!\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Klucz użytkownika lub grupy\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Nie udało się wysłać powiadomienia testowego Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Wysyłanie powiadomienia testowego Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Wysłano powiadomienie testowe Slack!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Musisz wybrać co najmniej jeden typ powiadomienia\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Musisz podać prawidłowy adres URL\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL Webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Utwórz integrację <WebhookLink>Incoming Webhook</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Włącz agenta\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Aby otrzymywać powiadomienia web push, Seerr musi być udostępniany za pośrednictwem HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Nie udało się wysłać powiadomienia testowego Web push.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Wysyłanie powiadomia testowego web push…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Powiadomienie testowe web push wysłane!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Nie udało się zapisać ustawień powiadomień Web Push.\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Nagłówek autoryzacji\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Musisz wybrać co najmniej jeden typ powiadomienia\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Musisz podać poprawny adres URL\",\n  \"components.Settings.Notifications.authUser\": \"Nazwa użytkownika SMTP\",\n  \"components.Settings.Notifications.botAPI\": \"Token autoryzacji bota\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Stwórz bota</CreateBotLink> do użycia z Seerr\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Adres URL awatara bota\",\n  \"components.Settings.Notifications.botUsername\": \"Nazwa użytkownika bota\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Musisz podać hasło PGP\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Należy podać prawidłowy klucz prywatny PGP\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Musisz podać prawidłową nazwę hosta lub adres IP\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL Webhook\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Utwórz <DiscordWebhookLink>integrację webhook</DiscordWebhookLink> na swoim serwerze\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Payload JSON\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Baza URL\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Wybierz minimalną dostępność\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Wybierz profil jakości\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Musisz wybrać minimalną dostępność\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Musisz podać nazwę serwera\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Musisz podać prawidłowy numer portu\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Musisz wybrać folder główny\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Aktualny\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Najnowszy\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Dane o wydaniu są obecnie niedostępne.\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Wydania\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Lista zmian\",\n  \"components.RequestModal.QuotaDisplay.season\": \"sezon\",\n  \"components.RequestModal.requestcancelled\": \"Prośba o <strong>{title}</strong> została anulowana.\",\n  \"components.RequestModal.requestSuccess\": \"Prośba o <strong>{title}</strong> wysłana pomyślnie!\",\n  \"components.RequestModal.season\": \"sezon\",\n  \"components.ResetPassword.emailresetlink\": \"Link do odzyskiwania przez adres e-mail\",\n  \"components.RequestModal.requestadmin\": \"Ta prośba zostanie zatwierdzona automatycznie.\",\n  \"components.ResetPassword.passwordreset\": \"Resetowanie hasła\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Powiadomienie testowe Pushbullet wysłane!\",\n  \"components.ResetPassword.confirmpassword\": \"Potwierdź hasło\",\n  \"components.ResetPassword.email\": \"Adres e-mail\",\n  \"components.ResetPassword.password\": \"Hasło\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Hasło zostało zresetowane pomyślnie!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Musisz podać token dostępu\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Musisz wybrać co najmniej jeden typ powiadomienia\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Ustawienia powiadomień pushbullet zostały pomyślnie zapisane!\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Włącz agenta\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Powiadomienie testowe Pushover wysłane!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Nie udało się zapisać ustawień powiadomień Slack.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Musisz wybrać co najmniej jeden typ powiadomienia\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Ustawienia powiadomień web push zostały pomyślnie zapisane!\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Serial\",\n  \"components.MovieDetails.runtime\": \"{minutes} minuty\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Opublikowane przez {username} {relativeTime}\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Nie udało się wysłać powiadomienia testowego Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Musisz podać prawidłowy token aplikacji\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Należy podać prawidłowy klucz użytkownika lub grupy\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Wysyłanie powiadomienia testowego Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Twój 30-znakowy <UsersGroupsLink>identyfikator użytkownika lub grupy</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Włącz agenta\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Ustawienia powiadomień Slack zapisane pomyślnie!\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Seriale {genre}\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Wysyłanie powiadomienia testowego webhook…\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Pozwól użytkownikom również rozpocząć czat z botem i skonfigurować własne powiadomienia\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Podpisuj zaszyfrowane wiadomości e-mail za pomocą <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Włącz agenta\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Przywróć ustawienia domyślne\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Nie udało się wysłać powiadomienia testowego Webhook.\",\n  \"components.Settings.Notifications.encryptionTip\": \"W większości przypadków niejawny TLS używa portu 465, a STARTTLS używa portu 587\",\n  \"components.Settings.Notifications.pgpPassword\": \"Hasło PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Podpisuj zaszyfrowane wiadomości e-mail za pomocą <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Opublikowane przez {username} {relativeTime} (edytowano)\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Pełna obsada\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studia}}\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Wysyłaj powiadomienia, gdy inni użytkownicy składają nowe prośby o multimedia, które są automatycznie zatwierdzane.\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Edytuj serwer 4K Radarr\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Ładowanie profili jakości…\",\n  \"components.CollectionDetails.requestcollection4k\": \"Poproś o kolekcję w 4K\",\n  \"components.MovieDetails.streamingproviders\": \"Obecnie dostępne na\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Data wydania} other {Daty wydania}}\",\n  \"components.MovieDetails.viewfullcrew\": \"Zobacz pełną obsadę\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Przyznaj automatyczne zatwierdzanie wszystkich próśb o multimedia inne niż 4K.\",\n  \"components.RequestButton.approve4krequests\": \"Zatwierdź {requestCount, plural, one {Prośba} other {{requestCount} Prośby}} 4K\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimalna dostępność\",\n  \"components.RequestButton.decline4krequests\": \"Odrzuć {requestCount, plural, one {prośby 4K} other {{requestCount} próśb 4K}}\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Otrzymuj powiadomienia, gdy prośby o multimedia nie zostaną dodane do Radarr lub Sonarr.\",\n  \"components.PermissionEdit.advancedrequest\": \"Zaawansowane prośby\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Przyznaj uprawnienia do modyfikowania zaawansowanych opcji próśb multimedia.\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Przyznaj automatyczne zatwierdzanie próśb o filmy 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Automatyczne zatwierdzanie seriali 4K\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Automatyczne zatwierdzanie seriali\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {sezon} other {sezony}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} na{quotaDays} {days}</quotaUnits>\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {sezon} other {sezony}}\",\n  \"components.RequestButton.viewrequest4k\": \"Wyświetl prośbę 4K\",\n  \"components.RequestCard.failedretry\": \"Coś poszło nie tak podczas ponawiania prośby.\",\n  \"components.RequestButton.approverequests\": \"Zatwierdź {requestCount, plural, one {prośba} other {{requestCount} próśb}}\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Wysyłaj powiadomienia, gdy użytkownicy składają nowe prośby dotyczące multimediów, które wymagają zatwierdzenia.\",\n  \"components.PermissionEdit.requestDescription\": \"Udzielenie zgody na składanie próśb na multimedia inne niż 4K.\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Przyznaj uprawnienia do przeglądania próśb o multimedia przesłanych przez innych użytkowników.\",\n  \"components.PersonDetails.ascharacter\": \"jako {character}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {dzień} other {dni}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} na {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {filmy}}\",\n  \"components.RequestButton.declinerequests\": \"Odrzuć {requestCount, plural, one {prośbę} other {{requestCount} prośby}}\",\n  \"components.RequestCard.mediaerror\": \"Tytuł skojarzony z tą prośbą nie jest już dostępny.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Możesz wyświetlić podsumowanie limitów próśb tego użytkownika na jego <ProfileLink>stronie profilu</ProfileLink>.\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Musisz podać prawidłowy numer portu\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Dodaj nowy serwer 4K Radarr\",\n  \"components.Settings.RadarrModal.createradarr\": \"Dodaj nowy serwer Radarr\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Możesz wyświetlić podsumowanie limitów próśb na swojej <ProfileLink>stronie profilu</ProfileLink>.\",\n  \"components.Settings.Notifications.validationTypes\": \"Musisz wybrać co najmniej jeden typ powiadomienia\",\n  \"components.Settings.Notifications.validationUrl\": \"Musisz podać prawidłowy adres URL\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Domyślny serwer 4K\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Ładowanie folderów głównych…\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Domyślny serwer\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Musisz wybrać profil jakości\",\n  \"components.IssueDetails.playonplex\": \"Odtwórz na {mediaServerName}\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Odcinek} other {Odcinki}}\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {sezon} other {sezony}}\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Prośba zatwierdzona\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Dostępne\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Prośba odrzucona\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Wysyłaj powiadomienia, gdy prośby o multimedia nie zostaną dodane do Radarr lub Sonarr.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Udzielanie zgody na zgłaszanie problemów z multimediami.\",\n  \"components.PermissionEdit.managerequests\": \"Zarządzaj prośbami\",\n  \"components.PermissionEdit.request\": \"Prośba\",\n  \"components.PermissionEdit.request4kTv\": \"Poproś o serial w 4K\",\n  \"components.PermissionEdit.requestTv\": \"Poproś o serial\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Sezon} other {Sezony}}\",\n  \"components.RequestList.RequestItem.failedretry\": \"Coś poszło nie tak podczas ponawiania prośby.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"Tytuł powiązany z tą prośbą nie jest już dostępny.\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {sezon} other {sezony}}\",\n  \"components.RequestList.requests\": \"Prośby\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Ta seria to anime.\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Poproś jako\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Brak} other {<strong>#</strong>}} {type} {remaining, plural, one {żądanie} other {żądań}} pozostało\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Aby przesłać prośbę o ten serial, musisz mieć co najmniej <strong>{seasons}</strong> {seasons, plural, one {prośbę} other {prośby}}.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Możesz przesyłać<strong>{limit}</strong> próśb {type} co <strong>{days}</strong> dni.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Ten użytkownik może przeysłać <strong>{limit}</strong> próśb {type} co <strong>{days}</strong> dni.\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {filmy}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Brak wystarczającej liczby próśb o sezon\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Aby przesłać prośbę o ten serial, ten użytkownik musi mieć co najmniej <strong>{seasons}</strong> {seasons, plural, one {prośbę} other {prośby}}.\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {sezon} other {sezony}}\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Nie mogliśmy automatycznie spełnić Twojej prośby. Wybierz odpowiednie dopasowanie z poniższej listy.\",\n  \"components.RequestModal.alreadyrequested\": \"Już poproszono\",\n  \"components.RequestModal.autoapproval\": \"Automatyczne zatwierdzenie\",\n  \"components.RequestModal.edit\": \"Edytuj prośbę\",\n  \"components.RequestModal.errorediting\": \"Coś poszło nie tak podczas edytowania prośby.\",\n  \"components.RequestModal.numberofepisodes\": \"Liczba odcinków\",\n  \"components.RequestModal.pending4krequest\": \"Oczekująca prośba o 4K\",\n  \"components.RequestModal.pendingapproval\": \"Twoja prośba oczekuje na zatwierdzenie.\",\n  \"components.RequestModal.pendingrequest\": \"Oczekująca prośba\",\n  \"components.RequestModal.requestCancel\": \"Prośba o <strong>{title}</strong> została anulowana.\",\n  \"components.RequestModal.requestedited\": \"Prośba o <strong>{title}</strong> została pomyślnie edytowana!\",\n  \"components.RequestModal.requesterror\": \"Coś poszło nie tak podczas przesyłania prośby.\",\n  \"components.RequestModal.requestfrom\": \"Prośba użytkownika {username} oczekuje na zatwierdzenie.\",\n  \"components.RequestModal.cancel\": \"Anuluj prośbę\",\n  \"components.Search.searchresults\": \"Wyniki wyszukiwania\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Utwórz token z poziomu <PushbulletSettingsLink>Ustawień konta</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Nie udało się wysłać powiadomienia testowego Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Wysyłanie powiadomienia testowego Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Włącz agenta\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Nie udało się zapisać ustawień powiadomień Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token API aplikacji\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL Webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Nie udało się zapisać ustawień powiadomień webhook.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Ustawienia powiadomień webhook zostały pomyślnie zapisane!\",\n  \"components.Settings.Notifications.agentenabled\": \"Włącz agenta\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Zezwalaj na certyfikaty z podpisem własnym\",\n  \"components.Settings.Notifications.authPass\": \"Hasło SMTP\",\n  \"components.Settings.Notifications.encryptionNone\": \"Brak\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Wysyłanie powiadomia testowego Telegram…\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Musisz podać token autoryzacji bota\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Musisz podać poprawny identyfikator czatu\",\n  \"components.Settings.Notifications.validationEmail\": \"Musisz podać poprawny adres e-mail\",\n  \"components.Settings.Notifications.chatId\": \"Identyfikator czatu (Chat ID)\",\n  \"components.Settings.Notifications.chatIdTip\": \"Rozpocznij czat ze swoim botem, dodaj <GetIdBotLink>@get_id_bot</GetIdBotLink> i wydaj polecenie <code>/my_id</code>\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Nie udało się zapisać ustawień powiadomień Discord.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Ustawienia powiadomień Discorda zapisane pomyślnie!\",\n  \"components.Settings.Notifications.emailsender\": \"Adres nadawcy\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Nie udało się zapisać ustawień powiadomień e-mail.\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Ustawienia powiadomień e-mail zostały zapisane pomyślnie!\",\n  \"components.Settings.Notifications.encryption\": \"Metoda szyfrowania\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Użyj STARTTLS, jeśli jest dostępny\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Używanie niejawnego protokołu TLS\",\n  \"components.Settings.RadarrModal.apiKey\": \"Klucz API\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Profil jakości\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Folder główny\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Wybierz folder główny\",\n  \"components.Settings.RadarrModal.selecttags\": \"Wybierz tagi\",\n  \"components.Settings.RadarrModal.server4k\": \"Serwer 4K\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Połączenie testowe w celu załadowania profili jakości\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Połączenie testowe w celu załadowania folderów głównych\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Połączenie testowe, aby wczytać tagi\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Nie udało się połączyć z Radarr.\",\n  \"components.Settings.RadarrModal.editradarr\": \"Edytuj serwer Radarr\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Włącz automatyczne wyszukiwanie\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Zewnętrzny adres URL\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Włącz skanowanie\",\n  \"components.Settings.RadarrModal.tags\": \"Tagi\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Połączenie z Radarr nawiązane pomyślnie!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Musisz podać klucz API\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"Adres URL nie może kończyć się ukośnikiem\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Bazowy adres URL musi zaczynać się ukośnikiem\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Bazowy URL nie może być zakończony ukośnikiem\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Musisz podać prawidłową nazwę hosta lub adres IP\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Zmodyfikuj zadanie\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Częstotliwość\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Co{jobScheduleHours, plural, one {godzinę} other {{jobScheduleHours} godzin}}\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Opróżnij pamięć podręczną\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Co {jobScheduleMinutes, plural, one {minutę} other {{jobScheduleMinutes} minut}}\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Zadania\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} rozpoczęte.\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Skanowanie ostatnio dodanych na Plex\",\n  \"components.Settings.SettingsJobsCache.process\": \"Proces\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Skan Radarr\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Skanowanie Sonarr\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Uruchom teraz\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Nieznane zadanie\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Skopiowano komunikat dziennika do schowka.\",\n  \"components.Settings.SettingsLogs.extraData\": \"Dodatkowe dane\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Debug\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Informacje\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Ostrzeżenie\",\n  \"components.Settings.SettingsLogs.level\": \"Powaga\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Szczegóły dziennika\",\n  \"components.Settings.SettingsLogs.label\": \"Etykieta\",\n  \"components.Settings.SettingsLogs.logs\": \"Logi\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pauza\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Wznów\",\n  \"components.Settings.SettingsLogs.showall\": \"Pokaż wszystkie logi\",\n  \"components.Settings.SettingsLogs.time\": \"Sygnatura czasowa\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Domyślne uprawnienia\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Włącz lokalne logowanie\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Zezwalaj użytkownikom na logowanie się przy użyciu adresu e-mail i hasła, a nie Plex OAuth\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Globalny limit próśb o filmy\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Łączna liczba próśb\",\n  \"components.Settings.SettingsAbout.version\": \"Wersja\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Pamięć podręczna\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Zobacz dziennik zmian\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Zobacz na GitHub\",\n  \"components.Settings.SettingsAbout.about\": \"O\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentacja\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Uzyskiwanie pomocy technicznej\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Dyskusje na GitHubie\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Nieaktualne\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Korzystasz z gałęzi <code>deweloperskiej</code> Seerr, która jest zalecana tylko dla osób przyczyniających się do rozwoju lub pomagających w testach.\",\n  \"components.Settings.SettingsAbout.timezone\": \"Strefa czasowa\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Multimedia ogółem\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Aktualne\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr buforuje żądania do zewnętrznych punktów końcowych API, aby zoptymalizować wydajność i uniknąć wykonywania niepotrzebnych wywołań API.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Pamięć podręczna {cachename} została opróżniona.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Trafienia\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Klucze ogółem\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Anuluj zadanie\",\n  \"components.Settings.SettingsJobsCache.command\": \"Polecenie\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Synchronizuj pobierania\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Zresetuj synchronizację pobierania\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Coś poszło nie tak podczas zapisywania zadania.\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr wykonuje pewne zadania konserwacyjne jako cyklicznie zaplanowane zadania, ale mogą być one również ręcznie uruchamiane poniżej. Ręczne uruchomienie zadania nie spowoduje zmiany jego harmonogramu.\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Następne wykonanie\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Możesz również zobaczyć te logi bezpośrednio przez <code>stdout</code>, lub w <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Nazwa zadania\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Zadanie edytowane pomyślnie!\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} anulowane.\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Zadania i pamięć podręczna\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Typ\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Skopiuj do schowka\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Włącz funkcję New Plex Sign-In\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Ustawienia użytkownika zostały zapisane pomyślnie!\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Rozmiar klucza\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Chybienia\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Nazwa pamięci podręcznej\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Rozmiar wartości\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Pełne skanowanie biblioteki Plex\",\n  \"components.Settings.SettingsLogs.filterError\": \"Błąd\",\n  \"components.Settings.SettingsLogs.message\": \"Wiadomość\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Początkowe uprawnienia nadawane nowym użytkownikom\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Zezwalaj użytkownikom Plex na logowanie się bez wcześniejszego importowania\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Coś poszło nie tak podczas zapisywania ustawień.\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Globalny limit żądań serii\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Ustawienia użytkownika\",\n  \"components.Settings.SettingsUsers.users\": \"Użytkownicy\",\n  \"components.Settings.SonarrModal.animeTags\": \"Tagi anime\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Profil języka anime\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Profil jakości anime\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Baza URL\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Dodaj nowy serwer 4K Sonarr\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Dodaj nowy serwer Sonarr\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Edytuj serwer 4K Sonarr\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Edytuj serwer Sonarr\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Ładowanie profili jakości…\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Brak tagów.\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Foldery sezonów\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Przetestuj połączenie, aby załadować profile jakości\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Połączenie testowe w celu załadowania folderów głównych\",\n  \"components.Settings.SonarrModal.tags\": \"Tagi\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Przetestuj połączenie, aby załadować tagi\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Nie udało się połączyć z Sonarrem.\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Przetestuj połączenie, aby załadować profile językowe\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Musisz podać poprawny adres URL\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Podstawowy adres URL musi mieć wiodący ukośnik\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Musisz wybrać profil językowy\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Bazowy adres URL nie może być zakończony ukośnikiem\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Musisz podać prawidłową nazwę hosta lub adres IP\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Musisz podać prawidłowy numer portu\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Musisz wybrać profil jakości\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Musisz podać nazwę serwera\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Musisz wybrać folder główny\",\n  \"components.Settings.activeProfile\": \"Aktywny profil\",\n  \"components.Settings.default\": \"Domyślny\",\n  \"components.Settings.default4k\": \"Domyślne 4K\",\n  \"components.Settings.deleteserverconfirm\": \"Czy na pewno chcesz usunąć ten serwer?\",\n  \"components.Settings.email\": \"E-mail\",\n  \"components.Settings.enablessl\": \"Użyj SSL\",\n  \"components.Settings.librariesRemaining\": \"Pozostałe biblioteki: {count}\",\n  \"components.Settings.hostname\": \"Nazwa hosta lub adres IP\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.manualscan\": \"Ręczne skanowanie biblioteki\",\n  \"components.Settings.manualscanDescription\": \"Zwykle będzie to uruchamiane tylko raz na 24 godziny. Seerr sprawdzi ostatnio dodane serwery Plex bardziej agresywnie. Jeśli konfigurujesz Plex po raz pierwszy, zalecane jest jednorazowe pełne ręczne skanowanie biblioteki!\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.mediaTypeSeries\": \"serial\",\n  \"components.Settings.menuAbout\": \"O\",\n  \"components.Settings.menuGeneralSettings\": \"Ogólne\",\n  \"components.Settings.menuJobs\": \"Zadania i pamięć podręczna\",\n  \"components.Settings.noDefault4kServer\": \"Serwer 4K {serverType} musi być oznaczony jako domyślny, aby umożliwić użytkownikom składanie żądań 4K {mediaType}.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Jeśli masz tylko jeden serwer {serverType} dla zawartości nie 4K i 4K (lub jeśli tylko pobierasz zawartość 4K), Twój serwer {serverType} powinien być <strong>NIE</strong> oznaczony jako serwer 4K.\",\n  \"components.Settings.noDefaultServer\": \"Co najmniej jeden serwer {serverType} musi być oznaczony jako domyślny, aby żądania {mediaType} były przetwarzane.\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Skonfiguruj i włącz agentów powiadomień.\",\n  \"components.Settings.notifications\": \"Powiadomienia\",\n  \"components.Settings.notificationsettings\": \"Ustawienia powiadomień\",\n  \"components.Settings.notrunning\": \"Nie działa\",\n  \"components.Settings.plexlibraries\": \"Biblioteki Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"Biblioteki, które Seerr skanuje w poszukiwaniu tytułów. Skonfiguruj i zapisz ustawienia połączenia Plex, a następnie kliknij przycisk poniżej, jeśli na liście nie ma żadnych bibliotek.\",\n  \"components.Settings.plexsettings\": \"Ustawienia Plex\",\n  \"components.Settings.radarrsettings\": \"Ustawienia Radarr\",\n  \"components.Settings.scanning\": \"Synchronizacja…\",\n  \"components.Settings.serverLocal\": \"lokalny\",\n  \"components.Settings.serverRemote\": \"zdalny\",\n  \"components.Settings.serverSecure\": \"bezpieczne\",\n  \"components.Settings.serverpreset\": \"Serwer\",\n  \"components.Settings.serverpresetLoad\": \"Naciśnij przycisk, aby załadować dostępne serwery\",\n  \"components.Settings.serverpresetManualMessage\": \"Ręczna konfiguracja\",\n  \"components.Settings.serverpresetRefreshing\": \"Pobieranie serwerów…\",\n  \"components.Settings.services\": \"Usługi\",\n  \"components.Settings.settingUpPlexDescription\": \"Aby skonfigurować aplikację Plex, możesz wprowadzić szczegóły ręcznie lub wybrać serwer pobrany z witryny <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Naciśnij przycisk znajdujący się po prawej stronie listy rozwijanej, aby wyświetlić listę dostępnych serwerów.\",\n  \"components.Settings.toastPlexRefresh\": \"Pobieranie listy serwerów z Plex…\",\n  \"components.Settings.validationHostnameRequired\": \"Musisz podać prawidłową nazwę hosta lub adres IP\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink> Adres URL aplikacji internetowej</WebAppLink>\",\n  \"components.Setup.finishing\": \"Kończenie…\",\n  \"components.Setup.signinMessage\": \"Zacznij logując się na swoje konto Plex\",\n  \"components.Setup.welcome\": \"Witamy w Seerr\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.nextAirDate\": \"Następna data emisji\",\n  \"components.UserList.bulkedit\": \"Masowa edycja\",\n  \"components.UserList.create\": \"Utwórz\",\n  \"components.UserList.created\": \"Dołączył\",\n  \"components.UserList.edituser\": \"Edytuj uprawnienia użytkownika\",\n  \"components.UserList.email\": \"Adres e-mail\",\n  \"components.UserList.usercreatedsuccess\": \"Pomyślnie utworzono użytkownika!\",\n  \"components.UserList.userdeleted\": \"Użytkownik został pomyślnie usunięty!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Wyświetlana nazwa\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Zastąp globalny limit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Użytkownik lokalny\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Domyślny ({language})\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Ustawienia powiadomień Discord zostały pomyślnie zapisane!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Wysyłaj powiadomienia bez dźwięku\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Identyfikator czatu\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Potwierdź hasło\",\n  \"i18n.noresults\": \"Brak wyników.\",\n  \"i18n.notrequested\": \"Brak próśb\",\n  \"i18n.partiallyavailable\": \"Częściowo dostępne\",\n  \"i18n.retry\": \"Ponów próbę\",\n  \"i18n.view\": \"Zobacz\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"Wewnętrzny błąd serwera\",\n  \"pages.oops\": \"Ups\",\n  \"pages.pagenotfound\": \"Nie znaleziono strony\",\n  \"components.CollectionDetails.requestcollection\": \"Poproś o kolekcję\",\n  \"components.Setup.setup\": \"Konfiguracja\",\n  \"i18n.close\": \"Zamknij\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.UserList.accounttype\": \"Typ\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtruj zawartość według języka oryginału\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Rozpocznij czat</TelegramBotLink> ze swoim botem, dodaj <GetIdBotLink>@get_id_bot</GetIdBotLink> i wydaj polecenie <code>/my_id</code>\",\n  \"i18n.usersettings\": \"Ustawienia użytkownika\",\n  \"pages.returnHome\": \"Powrót do domu\",\n  \"pages.serviceunavailable\": \"Usługa niedostępna\",\n  \"components.TvDetails.overview\": \"Podsumowanie\",\n  \"components.UserList.admin\": \"Administrator\",\n  \"components.UserList.userdeleteerror\": \"Coś poszło nie tak podczas usuwania użytkownika.\",\n  \"components.UserList.userfail\": \"Coś poszło nie tak podczas zapisywania uprawnień użytkownika.\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Zobacz profil\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Edytuj ustawienia\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Limit próśb o serial\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Ustawienia zostały zapisane pomyślnie!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Powiadomienia\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Ustawienia powiadomień Telegram zostały zapisane pomyślnie!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Musisz podać prawidłowy identyfikator użytkownika\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Musisz podać prawidłowy klucz publiczny PGP\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Uprawnienia zostały pomyślnie zapisane!\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Hasło\",\n  \"components.UserProfile.movierequests\": \"Prośby o filmy\",\n  \"i18n.canceling\": \"Anulowanie…\",\n  \"i18n.resolved\": \"Rozwiązane\",\n  \"i18n.resultsperpage\": \"Wyświetlaj {pageSize} wyników na stronę\",\n  \"i18n.retrying\": \"Ponawianie…\",\n  \"i18n.status\": \"Stan\",\n  \"components.Settings.SonarrModal.hostname\": \"Nazwa hosta lub adres IP\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Profil języka\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Ładowanie tagów…\",\n  \"components.Settings.addsonarr\": \"Dodaj serwer Sonarr\",\n  \"components.Settings.plexsettingsDescription\": \"Skonfiguruj ustawienia serwera Plex. Seerr skanuje biblioteki Plex, aby określić dostępność treści.\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.scan\": \"Synchronizuj biblioteki\",\n  \"components.Settings.toastPlexConnecting\": \"Próba połączenia z Plex…\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Nie udało się połączyć z Plex.\",\n  \"components.Settings.validationPortRequired\": \"Musisz podać prawidłowy numer portu\",\n  \"components.Settings.webhook\": \"Webhooki\",\n  \"components.Setup.configureservices\": \"Skonfiguruj usługi\",\n  \"components.Setup.continue\": \"Kontynuuj\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Pełna obsada serialu\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Pełna ekipa serialu\",\n  \"components.TvDetails.episodeRuntime\": \"Czas trwania odcinka\",\n  \"components.TvDetails.originallanguage\": \"Język oryginalny\",\n  \"components.TvDetails.originaltitle\": \"Tytuł oryginalny\",\n  \"components.TvDetails.overviewunavailable\": \"Podsumowanie niedostępne.\",\n  \"components.TvDetails.recommendations\": \"Rekomendacje\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Sezon} other {# Sezony}}\",\n  \"components.TvDetails.showtype\": \"Typ serialu\",\n  \"components.TvDetails.similar\": \"Podobne seriale\",\n  \"components.TvDetails.streamingproviders\": \"Obecnie dostępne na\",\n  \"components.UserList.autogeneratepassword\": \"Automatycznie generuj hasło\",\n  \"components.UserList.autogeneratepasswordTip\": \"Wyślij do użytkownika wiadomość e-mail z hasłem wygenerowanym przez serwer\",\n  \"components.UserList.createlocaluser\": \"Utwórz użytkownika lokalnego\",\n  \"components.UserList.creating\": \"Tworzenie…\",\n  \"components.UserList.deleteuser\": \"Usuń użytkownika\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> {userCount, plural, one {użytkownik Plex został zaimportowany} other {użytkowników Plex zostało zaimportowanych}} pomyślnie!\",\n  \"components.UserList.localLoginDisabled\": \"Ustawienie <strong>Włącz Lokalne Logowanie</strong> jest obecnie wyłączone.\",\n  \"components.UserList.localuser\": \"Użytkownik lokalny\",\n  \"components.UserList.nouserstoimport\": \"Brak nowych użytkowników Plex do zaimportowania.\",\n  \"components.UserList.owner\": \"Właściciel\",\n  \"components.UserList.password\": \"Hasło\",\n  \"components.UserList.passwordinfodescription\": \"Skonfiguruj adres URL aplikacji i włącz powiadomienia e-mail, aby umożliwić automatyczne generowanie hasła.\",\n  \"components.UserList.plexuser\": \"Użytkownik Plex\",\n  \"components.UserList.role\": \"Rola\",\n  \"components.UserList.sortRequests\": \"Liczba próśb\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Musisz podać token dostępu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Musisz podać prawidłowy token aplikacji\",\n  \"components.UserProfile.recentrequests\": \"Ostatnie prośby\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Włącz automatyczne wyszukiwanie\",\n  \"components.Settings.menuLogs\": \"Logi\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Zewnętrzny adres URL\",\n  \"components.Settings.menuNotifications\": \"Powiadomienia\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.UserList.users\": \"Użytkownicy\",\n  \"components.UserList.user\": \"Użytkownik\",\n  \"components.UserList.usercreatedfailed\": \"Coś poszło nie tak podczas tworzenia użytkownika.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Podany adres e-mail jest już używany przez innego użytkownika.\",\n  \"components.UserList.userlist\": \"Lista użytkowników\",\n  \"components.UserList.userssaved\": \"Uprawnienia użytkownika zostały pomyślnie zapisane!\",\n  \"components.UserList.validationEmail\": \"Adres e-mail jest wymagany\",\n  \"components.UserList.validationpasswordminchars\": \"Hasło jest zbyt krótkie; powinno mieć co najmniej 8 znaków\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Dołączył {joindate}\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID użytkownika: {userid}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Limit próśb o filmy\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Właściciel\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Użytkownik Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Odkryj region\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Odkryj język\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtruj zawartość według dostępności regionalnej\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rola\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Nie udało się zapisać ustawień powiadomień Discord.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Nie udało się zapisać ustawień powiadomień e-mail.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Ustawienia powiadomień e-mail zostały zapisane pomyślnie!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Ustawienia powiadomień\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Klucz publiczny PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Szyfruj wiadomości e-mail za pomocą <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Token dostępowy\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Utwórz token z poziomu <PushbulletSettingsLink>ustawień konta</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Nie udało się zapisać ustawień powiadomień Pushbullet.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Ustawienia powiadomień pushbullet zostały pomyślnie zapisane!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Token interfejsu API aplikacji\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Zarejestruj aplikację</ApplicationRegistrationLink> do użycia z {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Klucz użytkownika lub grupy\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Twój 30-znakowy <UsersGroupsLink>identyfikator użytkownika lub grupy</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Nie udało się zapisać ustawień powiadomień Pushover.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Ustawienia powiadomień pushover zostały pomyślnie zapisane!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Musisz podać prawidłowy klucz użytkownika lub grupy\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Musisz podać prawidłowy identyfikator czatu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Aktualne hasło\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nowe hasło\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Hasło zostało zapisane pomyślnie!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Musisz potwierdzić nowe hasło\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Hasła muszą być zgodne\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Musisz podać swoje aktualne hasło\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Musisz podać nowe hasło\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Hasło jest zbyt krótkie; powinno mieć co najmniej 8 znaków\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Coś poszło nie tak podczas zapisywania ustawień.\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Nie możesz modyfikować własnych uprawnień.\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Ogólne\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Powiadomienia\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Uprawnienia\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Nie masz uprawnień do modyfikowania ustawień tego użytkownika.\",\n  \"components.UserProfile.limit\": \"{remaining} z {limit}\",\n  \"components.UserProfile.pastdays\": \"{type} (ostatnie {days} dni)\",\n  \"components.UserProfile.requestsperdays\": \"Pozostało {limit}\",\n  \"components.UserProfile.seriesrequest\": \"Prośby o seriale\",\n  \"components.UserProfile.unlimited\": \"Bez ograniczeń\",\n  \"i18n.advanced\": \"Zaawansowane\",\n  \"i18n.all\": \"Wszystkie\",\n  \"i18n.approve\": \"Zatwierdź\",\n  \"i18n.areyousure\": \"Czy na pewno?\",\n  \"i18n.back\": \"Powrót\",\n  \"i18n.decline\": \"Odrzuć\",\n  \"i18n.declined\": \"Odrzucony\",\n  \"i18n.delete\": \"Usuń\",\n  \"i18n.deleting\": \"Usuwanie…\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.edit\": \"Edytuj\",\n  \"i18n.experimental\": \"Eksperymentalne\",\n  \"i18n.failed\": \"Nieudane\",\n  \"i18n.loading\": \"Ładowanie…\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.movies\": \"Filmy\",\n  \"i18n.next\": \"Następny\",\n  \"i18n.open\": \"Otwarte\",\n  \"i18n.pending\": \"Oczekujący\",\n  \"i18n.previous\": \"Poprzedni\",\n  \"i18n.processing\": \"Przetwarzanie\",\n  \"i18n.request\": \"Poproś\",\n  \"i18n.request4k\": \"Poproś o 4K\",\n  \"i18n.requested\": \"Prośba zgłoszona\",\n  \"i18n.requesting\": \"Prośba…\",\n  \"i18n.save\": \"Zapisz zmiany\",\n  \"i18n.saving\": \"Zapisywanie…\",\n  \"i18n.settings\": \"Ustawienia\",\n  \"i18n.showingresults\": \"Wyświetlanie wyników od<strong>{from}</strong> do <strong>{to}</strong> z <strong>{total}</strong>\",\n  \"i18n.test\": \"Test\",\n  \"i18n.testing\": \"Testowanie…\",\n  \"i18n.tvshow\": \"Serial\",\n  \"i18n.tvshows\": \"Seriale\",\n  \"i18n.unavailable\": \"Niedostępny\",\n  \"pages.somethingwentwrong\": \"Coś poszło nie tak\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Domyślny serwer\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Wybierz folder główny\",\n  \"components.Settings.SonarrModal.add\": \"Dodaj serwer\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Ładowanie folderów głównych…\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Profil jakości\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Folder główny\",\n  \"components.Settings.address\": \"Adres\",\n  \"components.Settings.SonarrModal.ssl\": \"Użyj SSL\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"Adres URL nie może kończyć się ukośnikiem\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Konfiguruje globalne i domyślne ustawienia użytkowników.\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Folder główny anime\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Wybierz profil jakości\",\n  \"components.Settings.SonarrModal.selecttags\": \"Wybierz tagi\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Nie udało się pobrać listy serwerów Plex.\",\n  \"components.Settings.SonarrModal.apiKey\": \"Klucz API\",\n  \"components.Settings.cancelscan\": \"Anuluj skanowanie\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Domyślny serwer 4K\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Ładowanie profili językowych…\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Wybierz profil językowy\",\n  \"components.Settings.SonarrModal.server4k\": \"Serwer 4K\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Połączenie z Sonarr nawiązane pomyślnie!\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Musisz podać klucz API\",\n  \"components.Settings.addradarr\": \"Dodaj serwer Radarr\",\n  \"components.Settings.SonarrModal.servername\": \"Nazwa serwera\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Włącz skanowanie\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuUsers\": \"Użytkownicy\",\n  \"components.Settings.currentlibrary\": \"Bieżąca biblioteka: {name}\",\n  \"components.Settings.menuServices\": \"Usługi\",\n  \"components.Settings.sonarrsettings\": \"Ustawienia Sonarr\",\n  \"components.Settings.ssl\": \"Protokół SSL\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Połączenie Plex nawiązane pomyślnie!\",\n  \"components.Settings.serviceSettingsDescription\": \"Skonfiguruj poniżej swój serwer(y) {serverType}. Możesz podłączyć wiele serwerów {serverType}, ale tylko dwa z nich mogą być oznaczone jako domyślne (jeden nie-4K i jeden 4K). Administratorzy mogą zmienić serwer używany do przetwarzania nowych żądań przed zatwierdzeniem.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Lista serwerów Plex została pobrana pomyślnie!\",\n  \"components.Settings.startscan\": \"Rozpocznij skanowanie\",\n  \"components.Setup.finish\": \"Zakończ konfigurację\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Sieć} other {Sieci}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Użytkownik\",\n  \"components.Settings.webAppUrlTip\": \"Opcjonalnie kieruj użytkowników do aplikacji internetowej na Twoim serwerze zamiast do \\\"hostowanej\\\" aplikacji internetowej\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minut\",\n  \"components.TvDetails.viewfullcrew\": \"Zobacz pełną ekipę\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Ogólne\",\n  \"components.TvDetails.firstAirDate\": \"Pierwsza data emisji\",\n  \"components.UserList.deleteconfirm\": \"Czy na pewno chcesz usunąć tego użytkownika? Wszystkie jego dane zostaną trwale usunięte.\",\n  \"components.TvDetails.cast\": \"Obsada\",\n  \"components.TvDetails.watchtrailer\": \"Obejrzyj zwiastun\",\n  \"components.UserList.sortCreated\": \"Data dołączenia\",\n  \"components.UserList.importfromplexerror\": \"Coś poszło nie tak podczas importowania użytkowników Plex.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Coś poszło nie tak podczas zapisywania ustawień.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Identyfikator użytkownika\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Wyślij po cichu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Nie udało się zapisać ustawień powiadomień telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"<FindDiscordIdLink>Wielocyfrowy numer ID</FindDiscordIdLink> powiązany z Twoim kontem użytkownika\",\n  \"components.UserList.importfromplex\": \"Importuj użytkowników Plex\",\n  \"i18n.available\": \"Dostępny\",\n  \"components.UserList.sortDisplayName\": \"Wyświetlana nazwa\",\n  \"components.UserList.totalrequests\": \"Prośby\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrator\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Język wyświetlania\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Ustawienia ogólne\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Typ konta\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Uprawnienia\",\n  \"components.UserProfile.totalrequests\": \"Łączna liczba próśb\",\n  \"i18n.cancel\": \"Anuluj\",\n  \"i18n.approved\": \"Zatwierdzone\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"To konto użytkownika nie ma obecnie ustawionego hasła. Skonfiguruj hasło poniżej, aby umożliwić temu kontu logowanie się jako \\\"użytkownik lokalny\\\"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Twoje konto nie ma obecnie ustawionego hasła. Skonfiguruj hasło poniżej, aby umożliwić zalogowanie się jako \\\"użytkownik lokalny\\\" przy użyciu Twojego adresu e-mail.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Nie masz uprawnień do zmiany hasła tego użytkownika.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Hasło\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Coś poszło nie tak podczas zapisywania hasła.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Coś poszło nie tak podczas zapisywania hasła. Czy aktualne hasło zostało wpisane poprawnie?\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Otrzymuj powiadomienia, gdy problemy zostaną rozwiązane przez innych użytkowników.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problem ponownie otwarty\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Otrzymuj powiadomienia o ponownym otwarciu zgłoszonych problemów.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Otrzymuj powiadomienia, gdy problemy zostaną ponownie otwarte przez innych użytkowników.\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Wysyłaj powiadomienia, gdy problemy zostaną ponownie otwarte.\",\n  \"components.RequestModal.requestmovies4k\": \"Prośba o {count} {count, plural, one {film} other {filmów}} w 4k\",\n  \"components.RequestModal.selectmovies\": \"Wybierz film(y)\",\n  \"components.RequestModal.requestmovies\": \"Prośba o {count} {count, plural, one {film} other {filmów}}\",\n  \"components.IssueDetails.commentplaceholder\": \"Dodaj komentarz…\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {Kraj} other {Kraje}} produkcji\",\n  \"components.RequestModal.requestseasons4k\": \"Prośba o {seasonCount} {seasonCount, plural, one {sezon} other {sezony}} w 4K\",\n  \"components.TvDetails.productioncountries\": \"Produkcja {countryCount, plural, one {kraj} other {kraje}}\",\n  \"components.RequestModal.approve\": \"Zatwierdź prośbę\",\n  \"components.RequestModal.requestApproved\": \"Prośba o <strong>{title}</strong> zatwierdzona!\",\n  \"components.Settings.RadarrModal.announced\": \"Zapowiedziany\",\n  \"components.Settings.RadarrModal.inCinemas\": \"W kinach\",\n  \"components.Settings.RadarrModal.released\": \"Wydany\",\n  \"components.Settings.Notifications.enableMentions\": \"Włącz wzmianki\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Nie udało się zapisać ustawień powiadomień Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Ustawienia powiadomień Gotify zostały pomyślnie zapisane!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Wysyłanie powiadomienia o testowego Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Wysłano powiadomienie testowe Gotify!\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Adres URL serwera\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Musisz wybrać co najmniej jeden typ powiadomienia\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Musisz podać prawidłowy adres URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"Adres URL nie może kończyć się ukośnikiem\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Włącz agenta\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Nie udało się wysłać powiadomienia testowego Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token aplikacji\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Musisz podać token aplikacji\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Coś poszło nie tak podczas zapisywania ustawień Tautulli.\",\n  \"components.ManageSlideOver.pastdays\": \"Ostatnie {days, number} dni\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Oznacz wszystkie sezony jako Dostępne w 4K\",\n  \"components.Settings.validationUrlTrailingSlash\": \"Adres URL nie może kończyć się ukośnikiem\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {odtworzenie} other {odtworzenia}}\",\n  \"components.UserList.newplexsigninenabled\": \"Ustawienie <strong>Włącz logowanie Plex</strong> jest obecnie włączone. Użytkownicy Plex, którzy mają dostęp do biblioteki nie muszą być importowani by się zalogować.\",\n  \"components.ManageSlideOver.alltime\": \"Cały czas\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Zaawansowane\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Multimedia\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Multimedia w 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Oznacz wszystkie sezony jako Dostępne\",\n  \"components.ManageSlideOver.opentautulli\": \"Otwórz w Tautulli\",\n  \"components.ManageSlideOver.playedby\": \"Odgrywane przez\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Tag kanału\",\n  \"components.Settings.externalUrl\": \"Zewnętrzny adres URL\",\n  \"components.Settings.tautulliApiKey\": \"Klucz API\",\n  \"components.Settings.tautulliSettings\": \"Ustawienia Taultulli\",\n  \"components.Settings.tautulliSettingsDescription\": \"Opcjonalnie skonfiguruj ustawienia serwera Tautulli. Seerr pobiera dane historii oglądania dla multimediów Plex z Tautulli.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Ustawienia Tautulli zostały pomyślnie zapisane!\",\n  \"components.Settings.urlBase\": \"Baza URL\",\n  \"components.Settings.validationApiKey\": \"Musisz podać klucz API\",\n  \"components.Settings.validationUrl\": \"Musisz podać prawidłowy adres URL\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Baza adresu URL musi mieć ukośnik\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"Baza adresu URL nie może kończyć się ukośnikiem\",\n  \"components.UserProfile.recentlywatched\": \"Ostatnio oglądane\",\n  \"i18n.import\": \"Importuj\",\n  \"i18n.importing\": \"Importowanie…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID użytkownika Discorda\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"<FindDiscordIdLink>Wielocyfrowy numer ID</FindDiscordIdLink> powiązany z Twoim kontem użytkownika Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Musisz podać poprawne ID użytkownika Discord\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Katalog danych\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Uruchom ponownie serwer, aby zastosować zaktualizowane ustawienia.\",\n  \"components.StatusChecker.appUpdated\": \"Zaktualizowano {applicationTitle}\",\n  \"components.Settings.deleteServer\": \"Usuń serwer {serverType}\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Kliknij przycisk poniżej, aby ponownie załadować aplikację.\",\n  \"components.StatusChecker.reloadApp\": \"Odśwież {applicationTitle}\",\n  \"i18n.restartRequired\": \"Wymagane jest ponowne uruchomienie\",\n  \"components.RequestBlock.languageprofile\": \"Profil językowy\",\n  \"components.StatusChecker.restartRequired\": \"Wymagane ponowne uruchomienie serwera\",\n  \"components.MovieDetails.digitalrelease\": \"Wydanie cyfrowe\",\n  \"components.MovieDetails.physicalrelease\": \"Wydanie fizyczne\",\n  \"components.MovieDetails.theatricalrelease\": \"Wydanie kinowe\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Twoja lista obserwowanych\",\n  \"components.Discover.plexwatchlist\": \"Twoja lista obserwowanych\",\n  \"components.PermissionEdit.autorequest\": \"Automatyczna prośba\",\n  \"components.PermissionEdit.autorequestDescription\": \"Udziel zgody na automatyczne przesyłanie próśb dotyczących multimediów innych niż 4K za pośrednictwem listy obserwowanych Plex.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Prośba przesłana automatycznie\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Otrzymuj powiadomienia o automatycznym składaniu nowych próśb o multimedia dla pozycji znajdujących się na liście obserwowanych.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Filmy z próśb automatycznych\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Lista obserwowanych\",\n  \"components.MovieDetails.managemovie\": \"Zarządzaj filmem\",\n  \"components.MovieDetails.reportissue\": \"Zgłoś problem\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Udziel zgody na automatyczne przesyłanie próśb dotyczących multimediów innych niż 4K za pośrednictwem listy obserwowanych Plex.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Automatyczna prośba o serial\",\n  \"components.AirDateBadge.airedrelative\": \"Wyemitowany {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Data emisji {relativeTime}\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Prośby o filmy\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Prośby o seriale\",\n  \"components.Layout.UserDropdown.requests\": \"Prośby\",\n  \"components.MovieDetails.rtaudiencescore\": \"Ocena publiczności Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatometer Rotten Tomatoes\",\n  \"components.MovieDetails.tmdbuserscore\": \"Ocena użytkowników TMDB\",\n  \"components.Discover.CreateSlider.addSlider\": \"Dodaj suwak\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Utwórz niestandardowy suwak\",\n  \"components.Discover.CreateSlider.addfail\": \"Nie udało się utworzyć nowego suwaka.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Stworzony nowy suwak i zapisano dostosowywania odkrywania.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Edytuj suwak\",\n  \"components.Discover.CreateSlider.editfail\": \"Nie udało się edytować suwaka.\",\n  \"components.Discover.CreateSlider.needresults\": \"Musisz mieć przynajmniej 1 wynik.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Brak wyników.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Podaj ID gatunku TMDB\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Podaj ID stacji TMDB\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Podaj zapytanie wyszukiwania\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Podaj ID studia TMDB\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Szukaj gatunków…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Wyszukaj studia…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Nazwa suwaka\",\n  \"components.Discover.CreateSlider.starttyping\": \"Zacznij pisać aby wyszukać.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Należy wprowadzić wartość danych.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Należy podać tytuł.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"Filmy: {keywordTitle}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmy\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularność rosnąco\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularność malejąco\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Data wydania malejąco\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Tytuł (A-Z) rosnąco\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Tytuł (Z-A) malejąco\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Ocena TMDB rosnąco\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Ocena TMDB malejąco\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Nie udało się usunąć suwaka.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Pomyślnie usunięto suwak.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Przełącz widoczność\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Usuń\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Data premiery rosnąco\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Data premiery malejąco\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularność rosnąco\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularność malejąco\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Tytuł (A-Z) rosnąco\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Tytuł (Z-A) malejąco\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Ocena TMDB malejąco\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Wyczyść aktywne filtry\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtry\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Data pierwszego wyemitowania\",\n  \"components.Discover.FilterSlideover.from\": \"Od\",\n  \"components.Discover.FilterSlideover.genres\": \"Gatunki\",\n  \"components.Discover.FilterSlideover.keywords\": \"Słowa kluczowe\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Oceny między {minValue} a {maxValue}\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Podaj ID słowa kluczowego TMDB\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Wyszukaj słowa kluczowe…\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Data wydania rosnąco\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Seriale\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Ocena TMDB rosnąco\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"Seriale: {keywordTitle}\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Oryginalny język\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Data wydania\",\n  \"components.Discover.FilterSlideover.runtime\": \"Długość\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minut trwania\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Serwisy streamingowe\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Liczba głosów użytkowników TMDB\",\n  \"components.Discover.FilterSlideover.to\": \"Do\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Liczba głosów między {minValue} a {maxValue}\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Twoja lista obserwowanych\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Niedawno dodane\",\n  \"components.Discover.createnewslider\": \"Dodaj nowy suwak\",\n  \"components.Discover.customizediscover\": \"Dostosuj Odkryj\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Media dodane do twojej <PlexWatchlistSupportLink>listy obserwowanych Plex</PlexWatchlistSupportLink> zostaną wyświetlone tutaj.\",\n  \"components.Discover.emptywatchlist\": \"Media dodane do twojej <PlexWatchlistSupportLink>listy obserwowanych Plex</PlexWatchlistSupportLink> zostaną wyświetlone tutaj.\",\n  \"components.Discover.tmdbstudio\": \"Studio TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Słowo kluczowe serialu TMDB\",\n  \"components.Discover.tmdbtvgenre\": \"Gatunek serialu TMDB\",\n  \"components.Discover.tmdbsearch\": \"Wyszukiwanie TMDB\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Ocena użytkowników TMDB\",\n  \"components.Discover.moviegenres\": \"Gatunki filmu\",\n  \"components.Discover.networks\": \"Kanały\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Edytowano suwak i zapisano ustawienia personalizacji.\",\n  \"components.Discover.stopediting\": \"Zakończ edytowanie\",\n  \"components.Discover.studios\": \"Studia\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Sezon {seasonNumber} Odcinek {episodeNumber}\",\n  \"components.Discover.tvgenres\": \"Gatunki seriali\",\n  \"components.Discover.updatefailed\": \"Coś poszło nie tak podczas aktualizacji ustawień personalizacji wykrywania.\",\n  \"components.Discover.updatesuccess\": \"Zaktualizowano ustawienia personalizacji wykrywania.\",\n  \"components.Discover.resettodefault\": \"Przywróć domyślne\",\n  \"components.Discover.resetfailed\": \"Coś poszło nie tak podczas resetowania ustawień personalizacji wykrywania.\",\n  \"components.Discover.resetsuccess\": \"Pomyślnie zresetowano ustawienia wykrywania.\",\n  \"components.Discover.tmdbmoviegenre\": \"Gatunek filmu TMDB\",\n  \"components.Layout.Sidebar.browsetv\": \"Seriale\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Adres e-mail jest nieprawidłowy.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Wymagane jest podanie hasła.\",\n  \"components.Login.credentialerror\": \"Nazwa użytkownika lub hasło są nieprawidłowe.\",\n  \"components.Login.emailtooltip\": \"Adres nie musi być powiązany z instancją {mediaServerName}.\",\n  \"components.Login.initialsignin\": \"Połącz\",\n  \"components.Login.initialsigningin\": \"Łączenie…\",\n  \"components.Login.save\": \"Reklama\",\n  \"components.Login.saving\": \"Dodaję…\",\n  \"components.Login.signinwithjellyfin\": \"Użyj swojego konta {mediaServerName}\",\n  \"components.Login.title\": \"Dodaj e-mail\",\n  \"components.Login.username\": \"Nazwa użytkownika\",\n  \"components.Login.validationEmailRequired\": \"Musisz podać adres e-mail\",\n  \"components.Login.validationemailformat\": \"Wymagany poprawny adres e-mail\",\n  \"components.Login.validationhostformat\": \"Wymagany poprawny adres URL\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL wymagany\",\n  \"components.Login.validationusernamerequired\": \"Wymagana nazwa użytkownika\",\n  \"components.ManageSlideOver.removearr4k\": \"Usuń z 4k {arr}\",\n  \"components.MovieDetails.downloadstatus\": \"Status pobierania\",\n  \"components.MovieDetails.openradarr4k\": \"Otwórz film 4k w Radarr\",\n  \"components.MovieDetails.play\": \"Odtwórz na {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Odtwórz w 4K na {mediaServerName}\",\n  \"components.PermissionEdit.viewrecent\": \"Wyświetl ostatnio dodane\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Zezwolenie na wyświetlanie listy ostatnio dodanych multimediów.\",\n  \"components.RequestBlock.approve\": \"Zatwierdź żądanie\",\n  \"components.RequestBlock.decline\": \"Odrzuć żądanie\",\n  \"components.RequestBlock.delete\": \"Usuń żądanie\",\n  \"components.RequestBlock.lastmodifiedby\": \"Ostatnio modyfikowany przez\",\n  \"components.RequestBlock.requestdate\": \"Data żądania\",\n  \"components.RequestBlock.requestedby\": \"Żądany przez\",\n  \"components.RequestCard.cancelrequest\": \"Anuluj prośbę\",\n  \"components.RequestCard.declinerequest\": \"Odrzuć prośbę\",\n  \"components.RequestCard.editrequest\": \"Edytuj prośbę\",\n  \"components.RequestCard.unknowntitle\": \"Nieznany tytuł\",\n  \"components.RequestModal.requestcollectiontitle\": \"Poproś o kolekcję\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Poproś o film w 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Poproś o film\",\n  \"components.RequestModal.requestseries4ktitle\": \"Poproś o serial w 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Poproś o serial\",\n  \"components.Selector.searchGenres\": \"Wybierz gatunki…\",\n  \"components.Selector.searchKeywords\": \"Wyszukaj słowa kluczowe…\",\n  \"components.Selector.searchStudios\": \"Szukaj studiów…\",\n  \"components.Selector.showless\": \"Pokaż mniej\",\n  \"components.Selector.starttyping\": \"Rozpocznij wpisywanie, aby wyszukać.\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Ostatnio dodane skanowanie Jellyfin\",\n  \"components.Settings.SettingsMain.apikey\": \"Klucz API\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Nazwa aplikacji\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL aplikacji\",\n  \"components.Settings.SettingsMain.general\": \"Ogólne\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Ustawienia ogólne\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Konfiguracja globalnych i domyślnych ustawień Seerr.\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Ukryj dostępne media\",\n  \"components.Settings.SettingsMain.locale\": \"Wyświetlany język\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Zezwalaj na częściowe żądania seriali\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Coś poszło nie tak podczas zapisywania ustawień.\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName} Ustawienia\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Coś poszło nie tak podczas zapisywania ustawień {mediaServerName}.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"Ustawienia {mediaServerName} zostały pomyślnie zapisane!\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"Biblioteki {mediaServerName} skanują w poszukiwaniu tytułów. Kliknij poniższy przycisk, jeśli na liście nie ma żadnych bibliotek.\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName} ustawienia\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Konfiguracja ustawień serwera {mediaServerName}. {mediaServerName} skanuje biblioteki {mediaServerName}, aby sprawdzić, jaka zawartość jest dostępna.\",\n  \"components.Settings.manualscanJellyfin\": \"Ręczne skanowanie biblioteki\",\n  \"components.Settings.saving\": \"Zapisywanie…\",\n  \"components.Settings.syncing\": \"Synchronizowanie\",\n  \"components.Setup.signinWithPlex\": \"Wprowadź swoje dane Plex\",\n  \"components.StatusBadge.openinarr\": \"Otwórz w {arr}\",\n  \"components.StatusBadge.playonplex\": \"Odtwórz na {mediaServerName}\",\n  \"components.TitleCard.watchlistError\": \"Coś poszło nie tak, spróbuj ponownie.\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Coś poszło nie tak podczas pobierania danych sezonu.\",\n  \"components.TvDetails.seasonnumber\": \"Sezon {seasonNumber}\",\n  \"components.TvDetails.seasonstitle\": \"Sezony\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Automatyczne żądania filmów\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Zapisz zmiany\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Zapisywanie…\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmy\",\n  \"components.Login.validationEmailFormat\": \"Nieprawidłowy adres e-mail\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Nie udało nam się znaleźć odpowiednika dla tego serialu.\",\n  \"components.Selector.showmore\": \"Pokaż więcej\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Pamięć podręczna obrazów pochodzących z zewnątrz (wymaga znacznej ilości miejsca na dysku)\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrowanie zawartości według oryginalnego języka\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Ustawienia zapisane pomyślnie!\",\n  \"components.Settings.experimentalTooltip\": \"Włączenie tego ustawienia może spowodować nieoczekiwane zachowanie aplikacji\",\n  \"components.UserList.mediaServerUser\": \"Użytkownik {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"Email\",\n  \"components.Discover.resetwarning\": \"Przywróć domyślne ustawienia wszystkich suwaków. Spowoduje to również usunięcie wszystkich niestandardowych suwaków!\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Wymagany jest adres e-mail.\",\n  \"components.MovieDetails.openradarr\": \"Otwórz film w Radarr\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Poproś o kolekcję w 4K\",\n  \"components.Setup.signinWithJellyfin\": \"Wprowadź swoje dane Jellyfin\",\n  \"components.Login.description\": \"Ponieważ logujesz się do {applicationName} po raz pierwszy, musisz dodać prawidłowy adres e-mail.\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Spowoduje to nieodwracalne usunięcie tego {mediaType} z {arr}, w tym wszystkich plików.\",\n  \"components.ManageSlideOver.removearr\": \"Usuń z {arr}\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Zezwolenie na automatyczne przesyłanie żądań dotyczących seriali innych niż 4K za pośrednictwem listy obserwowanych Plex.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Wyświetl {mediaServerName} watchlistę\",\n  \"components.RequestCard.approverequest\": \"Zaakceptuj prośbę\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Automatycznie dodawaj dodatkowy znacznik z identyfikatorem użytkownika i wyświetlaną nazwą użytkownika\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Pełne skanowanie bibliotek Jellyfin\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Zobacz szczegóły\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Opcjonalnie skonfiguruj wewnętrzne i zewnętrzne punkty końcowe dla serwera {mediaServerName}. W większości przypadków zewnętrzny adres URL różni się od wewnętrznego adresu URL. Niestandardowy adres URL resetowania hasła można również ustawić dla logowania {mediaServerName}, na wypadek gdybyś chciał przekierować na inną stronę resetowania hasła. Możesz również zmienić klucz API Jellyfin, który został uprzednio wygenerowany automatycznie.\",\n  \"components.Settings.save\": \"Zapisz zmiany\",\n  \"components.Settings.syncJellyfin\": \"Synchronizuj biblioteki\",\n  \"components.TvDetails.Season.noepisodes\": \"Lista odcinków jest niedostępna.\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Dźwięk powiadomień\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Żądania tagów\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Aktualna częstotliwość\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Musisz podać tytuł aplikacji\",\n  \"components.Settings.SonarrModal.seriesType\": \"Typ seriali\",\n  \"components.Settings.advancedTooltip\": \"Nieprawidłowe skonfigurowanie tego ustawienia może spowodować nieprawidłowe działanie\",\n  \"components.TvDetails.reportissue\": \"Zgłoś problem\",\n  \"components.RequestBlock.edit\": \"Edytuj żądanie\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Nieznany tytuł\",\n  \"components.Selector.nooptions\": \"Brak wyników.\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Domyślne urządzenie\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Wymagaj adresu e-mail użytkownika\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Zwykle będzie to uruchamiane tylko raz na 24 godziny. Seerr będzie bardziej agresywnie sprawdzać ostatnio dodane biblioteki serwera {mediaServerName}. Jeśli po raz pierwszy konfigurujesz Seerr, zalecane jest jednorazowe pełne ręczne skanowanie biblioteki!\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Aktywny filtr} other {# Aktywne filtry}}\",\n  \"components.Login.back\": \"Wróć\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> został z powodzeniem usunięty z listy Do obejrzenia!\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> został z powodzeniem dodany do listy Do obejrzenia!\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Co {jobScheduleSeconds, plural, one {sekundę} other {{jobScheduleSeconds} sekundy}}\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Czyszczenie pamięci podręcznej obrazów\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Pamięć podręczna obrazów\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# aktywny filtr} few {# aktywne filtry} other {# aktywnych filtrów}}\",\n  \"components.Login.enablessl\": \"Użyj SSL\",\n  \"components.Login.invalidurlerror\": \"Niepowodzenie połączenia z serwerem {mediaServerName}.\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.servertype\": \"Typ serwera\",\n  \"components.Login.urlBase\": \"Bazowy URL\",\n  \"components.Login.validationPortRequired\": \"Musisz wprowadzić prawidłowy numer portu\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"Bazowy URL musi rozpoczynać się ukośnikiem\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"Bazowy URL nie może kończyć się ukośnikiem\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL nie może kończyć się ukośnikiem\",\n  \"components.Login.validationservertyperequired\": \"Proszę wybrać typ serwera\",\n  \"components.MovieDetails.addtowatchlist\": \"Dodaj do listy Do obejrzenia\",\n  \"components.MovieDetails.removefromwatchlist\": \"Usuń z listy Do obejrzenia\",\n  \"components.MovieDetails.watchlistError\": \"Coś poszło nie tak, spróbuj ponownie.\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.Discover.tmdbmoviekeyword\": \"Słowo kluczowe TMDB\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Rodzaj serialu Anime\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.TitleCard.watchlistDeleted\": \"Z powodzeniem usunięto <strong>{title}</strong> z listy Do obejrzenia!\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Udziel zgody na wyświetlanie list Do obejrzenia {mediaServerName} innych użytkowników.\",\n  \"components.Selector.canceled\": \"Anulowane\",\n  \"components.Selector.returningSeries\": \"Powracający serial\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Po włączeniu w ustawieniach, Seerr będzie buforował obrazy z skonfigurowanych źródeł zewnętrznych i pośredniczył w ich wyświetlaniu. Buforowane obrazy są zapisywane w folderze danych aplikacji. Pliki można znaleźć w <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Synchronizacja listy Do obejrzenia Plex\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Automatycznie dodawaj dodatkowy znacznik z identyfikatorem użytkownika i wyświetlaną nazwą użytkownika\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.TvDetails.addtowatchlist\": \"Dodaj do listy Do obejrzenia\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Brak użytkowników {mediaServerName} do zaimportowania.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Automatycznie składaj prośby o filmy z twojej listy <PlexWatchlistSupportLink>Do obejrzenia Plex</PlexWatchlistSupportLink>\",\n  \"components.TitleCard.watchlistSuccess\": \"Z powodzeniem dodano <strong>{title}</strong> do listy Do obejrzenia!\",\n  \"components.TvDetails.play4k\": \"Odtwórz w 4K na {mediaServerName}\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> został z powodzeniem dodany do listy Do obejrzenia!\",\n  \"components.UserList.importedfromJellyfin\": \"Z powodzeniem zaimportowano <strong>{userCount}</strong> {userCount, plural, one {użytkownika} other {użytkowników}} {mediaServerName}!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Dźwięk powiadomień\",\n  \"components.UserList.newJellyfinsigninenabled\": \"Ustawienie <strong>Włącz nowe logowanie {mediaServerName}</strong> jest aktualnie aktywne. Użytkownicy {mediaServerName} z dostępem do biblioteki nie muszą być zaimportowani aby się zalogować.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Wymagany poprawny adres e-mail\",\n  \"components.UserProfile.emptywatchlist\": \"Media dodane do twojej listy <PlexWatchlistSupportLink>Do obejrzenia Plex</PlexWatchlistSupportLink> zostaną wyświetlone tutaj.\",\n  \"components.Login.adminerror\": \"Do zalogowania musisz użyć konta administratora.\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Synchronizacja dostępności mediów\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Zbuforowane obrazy\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Niestandardowa autentykacja nie jest obsługiwana w połączeniu z Automatycznym grupowaniem bibliotek\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Coś poszło nie tak w trakcie synchronizacji bibliotek\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Nie znaleziono żadnych bibliotek\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Aktywny filtr} other {# Aktywne filtry}}\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.MovieDetails.imdbuserscore\": \"Ocena użytkowników IMDB\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.profileName\": \"Profil\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.Selector.ended\": \"Zakończone\",\n  \"components.Selector.inProduction\": \"W produkcji\",\n  \"components.Selector.pilot\": \"Pilot\",\n  \"components.Selector.planned\": \"Planowany\",\n  \"components.Selector.searchStatus\": \"Wybierz status...\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Całkowity rozmiar pamięci podręcznej\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Włącz Buforowanie obrazów\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Język funkcji Odkryj\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Coś poszło nie tak w trakcie generowania nowego klucza API.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Nowy klucz API został pomyślnie wygenerowany!\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Musisz podać poprawny adres URL\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"Adres URL nie może kończyć się ukośnikiem\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Żądania tagów\",\n  \"components.Settings.invalidurlerror\": \"Niepowodzenie połączenia z serwerem {mediaServerName}.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Adres URL odzyskiwania hasła\",\n  \"components.Settings.jellyfinlibraries\": \"Biblioteki {mediaServerName}\",\n  \"components.Settings.restartrequiredTooltip\": \"Aby zmiana tego ustawienia została zastosowana, należy ponownie uruchomić Seerr\",\n  \"components.Settings.timeout\": \"Limit czasu\",\n  \"components.Setup.back\": \"Wróć\",\n  \"components.Setup.configemby\": \"Skonfiguruj Emby\",\n  \"components.Setup.configjellyfin\": \"Skonfiguruj Jellyfin\",\n  \"components.Setup.configplex\": \"Skonfiguruj Plex\",\n  \"components.Setup.configuremediaserver\": \"Skonfiguruj serwer multimediów\",\n  \"components.Setup.servertype\": \"Wybierz rodzaj serwera\",\n  \"components.Setup.signin\": \"Zaloguj się\",\n  \"components.Setup.signinWithEmby\": \"Wprowadź swoje dane Emby\",\n  \"components.Setup.subtitle\": \"Zacznij od wybrania serwera multimediów\",\n  \"components.StatusBadge.managemedia\": \"Zarządzaj {mediaType}\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.TitleCard.addToWatchList\": \"Dodaj do listy Do obejrzenia\",\n  \"components.TitleCard.cleardata\": \"Wyczyść dane\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} nie odnaleziony\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.TitleCard.watchlistCancel\": \"lista obserwowanych dla <strong>{title}</strong> została anulowana.\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# odcinek} other {# odcinki}}\",\n  \"components.TvDetails.manageseries\": \"Zarządzaj serialem\",\n  \"components.TvDetails.play\": \"Odtwórz na {mediaServerName}\",\n  \"components.TvDetails.removefromwatchlist\": \"Usuń z listy Do obejrzenia\",\n  \"components.TvDetails.rtaudiencescore\": \"Ocena publiczności Rotten Tomatoes\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomatometer Rotten Tomatoes\",\n  \"components.TvDetails.tmdbuserscore\": \"Ocena użytkowników TMDB\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> został z powodzeniem usunięty z listy Do obejrzenia!\",\n  \"components.TvDetails.watchlistError\": \"Coś poszło nie tak, spróbuj ponownie.\",\n  \"components.UserList.importfromJellyfin\": \"Importuj użytkowników {mediaServerName}\",\n  \"components.UserList.importfrommediaserver\": \"Importuj użytkowników {mediaServerName}\",\n  \"components.UserList.importfromJellyfinerror\": \"Coś poszło nie tak w trakcie importowania użytkowników {mediaServerName}.\",\n  \"components.UserList.username\": \"Nazwa użytkownika\",\n  \"components.UserList.validationUsername\": \"Musisz podać nazwę użytkownika\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Użytkownik {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Automatyczna prośba o serial\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Automatycznie składaj prośby o seriale z twojej listy <PlexWatchlistSupportLink>Do obejrzenia Plex</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Adres e-mail jest wymagany\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Domyślne urządzenie\",\n  \"components.UserProfile.localWatchlist\": \"Do obejrzenia {username}\",\n  \"components.UserProfile.plexwatchlist\": \"Do obejrzenia Plex\",\n  \"i18n.collection\": \"Kolekcja\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Usługi strumieniowe TMDB\",\n  \"components.Discover.tmdbnetwork\": \"Sieć TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Telewizyjne usługi strumieniowe TMDB\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"Identyfikator roli do wskazania w wiadomości webhook. Pozostaw puste, aby wyłączyć wzmianki\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Awatary użytkowników\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filtrowanie zawartości według dostępności regionalnej\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Odkryj region\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Musisz podać prawidłowy Discord Role ID\",\n  \"components.RequestList.RequestItem.removearr\": \"Usuń z {arr}\",\n  \"components.RequestList.sortDirection\": \"Zmień kierunek sortowania\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Powiadomienie Role ID\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/pt_BR.json",
    "content": "{\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.PersonDetails.ascharacter\": \"como {character}\",\n  \"components.PersonDetails.appearsin\": \"Aparece em\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Estúdio} other {Estúdios}}\",\n  \"components.MovieDetails.similar\": \"Títulos Semelhantes\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutos\",\n  \"components.MovieDetails.revenue\": \"Receita\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Lançamento} other {Lançamentos}}\",\n  \"components.MovieDetails.recommendations\": \"Recomendações\",\n  \"components.MovieDetails.overviewunavailable\": \"Sinopse indisponível.\",\n  \"components.MovieDetails.overview\": \"Sinopse\",\n  \"components.MovieDetails.originallanguage\": \"Língua Original\",\n  \"components.MovieDetails.cast\": \"Elenco\",\n  \"components.MovieDetails.budget\": \"Orçamento\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Elenco Completo\",\n  \"components.Layout.UserDropdown.signout\": \"Sair\",\n  \"components.Layout.Sidebar.users\": \"Usuários\",\n  \"components.Layout.Sidebar.settings\": \"Configurações\",\n  \"components.Layout.Sidebar.requests\": \"Solicitações\",\n  \"components.Layout.Sidebar.dashboard\": \"Explorar\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Pesquisar Filmes & Séries\",\n  \"components.Discover.upcomingmovies\": \"Filmes em Breve\",\n  \"components.Discover.upcoming\": \"Filmes em Breve\",\n  \"components.Discover.trending\": \"Em Alta\",\n  \"components.Discover.recentrequests\": \"Solicitações Recentes\",\n  \"components.Discover.recentlyAdded\": \"Adicionado Recentemente\",\n  \"components.Discover.populartv\": \"Séries Populares\",\n  \"components.Discover.popularmovies\": \"Filmes Populares\",\n  \"components.Settings.plexlibraries\": \"Bibliotecas do Plex\",\n  \"components.Settings.notrunning\": \"Parado\",\n  \"components.RequestModal.season\": \"Temporada\",\n  \"components.Settings.notificationsettings\": \"Configurações de Notificação\",\n  \"components.Settings.menuServices\": \"Serviços\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Notificações\",\n  \"components.Settings.menuLogs\": \"Logs\",\n  \"components.Settings.menuJobs\": \"Tarefas & Cache\",\n  \"components.Settings.menuGeneralSettings\": \"Geral\",\n  \"components.Settings.menuAbout\": \"Sobre\",\n  \"components.Settings.manualscanDescription\": \"Normalmente, isso só será executado uma vez a cada 24 horas. Seerr irá checar em detalhes items recentemente adicionados ao seu servidor Plex. Se essa é a primeira vez que você configura um servidor Plex, é recomendado a varredura completa de sua biblioteca!\",\n  \"components.Settings.manualscan\": \"Varredura Manual da Biblioteca\",\n  \"components.Settings.librariesRemaining\": \"Bibliotecas Restantes: {count}\",\n  \"components.Settings.hostname\": \"Nome ou IP do Servidor\",\n  \"components.Settings.deleteserverconfirm\": \"Tem certeza que deseja apagar esse servidor?\",\n  \"i18n.deleting\": \"Apagando…\",\n  \"i18n.delete\": \"Apagar\",\n  \"components.Settings.default4k\": \"Padrão 4K\",\n  \"components.Settings.default\": \"Padrão\",\n  \"components.Settings.currentlibrary\": \"Biblioteca Atual: {name}\",\n  \"components.Settings.cancelscan\": \"Cancelar Escaneamento\",\n  \"components.Settings.addsonarr\": \"Adicionar Servidor Sonarr\",\n  \"components.Settings.address\": \"Endereço\",\n  \"components.Settings.addradarr\": \"Adicionar Servidor Radarr\",\n  \"components.Settings.activeProfile\": \"Perfil Ativo\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Você deve selecionar uma pasta raíz\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Você deve selecionar um perfil de qualidade\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Você deve prover uma porta válida\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Você deve prover o nome do servidor\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Você deve prover o nome ou IP do servidor\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Você deve prover uma chave de API\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Teste conexão para carregar as pastas raízes\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Teste conexão para carregar perfis de qualidade\",\n  \"components.Settings.SonarrModal.ssl\": \"Usar SSL\",\n  \"components.Settings.SonarrModal.servername\": \"Nome do Servidor\",\n  \"components.Settings.SonarrModal.server4k\": \"Servidor 4K\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Selecione a pasta raíz\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Selecione o perfil de qualidade\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Temporadas Em Pastas\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Pasta Raíz\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Perfil de Qualidade\",\n  \"components.Settings.SonarrModal.port\": \"Porta\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Carregando pastas raízes…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Carregando Perfis de Qualidade…\",\n  \"components.Settings.SonarrModal.hostname\": \"Nome ou IP do Servidor\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Editar Servidor Sonarr\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Servidor Padrão\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Adicionar Um Novo Servidor Sonarr\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL Base\",\n  \"components.Settings.SonarrModal.apiKey\": \"Chave de API\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Pasta Raíz de Animes\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Perfil de Qualidade Para Animes\",\n  \"components.Settings.SonarrModal.add\": \"Adicionar Servidor\",\n  \"components.Settings.SettingsAbout.version\": \"Versão\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Total de Solicitações\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Total de Títulos\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Discussões no GitHub\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Obtenha Suporte\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Você deve selecionar uma pasta raíz\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Você deve selecionar um perfil de qualidade\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Você deve prover uma porta válida\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Você deve prover o nome do servidor\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Você deve selecionar a disponibilidade mínima\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Você deve prover o nome ou IP do servidor\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Você deve prover uma chave de API\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Conexão com Radarr estabelecida com sucesso!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Falha ao conectar-se ao Radarr.\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Teste conexão para carregar as pastas raízes\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Teste conexão para carregar perfis de qualidade\",\n  \"components.Settings.RadarrModal.ssl\": \"Usar SSL\",\n  \"components.Settings.RadarrModal.servername\": \"Nome do Servidor\",\n  \"components.Settings.RadarrModal.server4k\": \"Servidor 4K\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Selecione a pasta raíz\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Selecione o perfil de qualidade\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Selecione disponibilidade mínima\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Pasta Raíz\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Perfil de Qualidade\",\n  \"components.Settings.RadarrModal.port\": \"Porta\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Disponibilidade Mínima\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Carregando Pastas Raízes…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Carregando Perfis de Qualidade…\",\n  \"components.Settings.RadarrModal.hostname\": \"Nome ou IP do Servidor\",\n  \"components.Settings.RadarrModal.editradarr\": \"Editar Servidor Radarr\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Servidor Padrão\",\n  \"components.Settings.RadarrModal.createradarr\": \"Adicionar Novo Servidor Radarr\",\n  \"components.Settings.RadarrModal.baseUrl\": \"URL Base\",\n  \"components.Settings.RadarrModal.apiKey\": \"Chave de API\",\n  \"components.Settings.RadarrModal.add\": \"Adicionar Servidor\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Você deve prover uma porta válida\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Você deve prover um nome válido ou IP de servidor\",\n  \"components.Settings.Notifications.smtpPort\": \"Porta SMTP\",\n  \"components.Settings.Notifications.smtpHost\": \"Servidor SMTP\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Configurações de notificação via e-mail salvas com sucesso!\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Falha ao salvar configurações de notificação via e-mail.\",\n  \"components.Settings.Notifications.emailsender\": \"Email do Remetente\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Configurações de notificação via Discord salvas com sucesso!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Falha ao salvar configurações de notificação via Discord.\",\n  \"components.Settings.Notifications.authUser\": \"Usuário SMTP\",\n  \"components.Settings.Notifications.authPass\": \"Senha SMTP\",\n  \"components.Settings.Notifications.agentenabled\": \"Habilitar Agente\",\n  \"components.Search.searchresults\": \"Resultados da Pesquisa\",\n  \"components.RequestModal.selectseason\": \"Selecione Temporada(s)\",\n  \"components.RequestModal.seasonnumber\": \"Temporada {number}\",\n  \"components.RequestModal.requestfrom\": \"Existe uma solicitação pendente de {username}.\",\n  \"components.RequestModal.requestadmin\": \"Essa solicitação será aprovada automaticamente.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> solicitado com sucesso!\",\n  \"components.RequestModal.requestCancel\": \"Solicitação para <strong>{title}</strong> cancelada.\",\n  \"components.RequestModal.pendingrequest\": \"Solicitação Pendente\",\n  \"components.RequestModal.numberofepisodes\": \"# de Episódeos\",\n  \"components.RequestModal.cancel\": \"Cancelar Solicitação\",\n  \"components.RequestList.requests\": \"Solicitações\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.Setup.continue\": \"Continuar\",\n  \"components.Setup.configureservices\": \"Configurar Serviços\",\n  \"components.Settings.validationPortRequired\": \"Você deve prover uma porta válida\",\n  \"components.Settings.validationHostnameRequired\": \"Você deve prover o Nome ou IP do Servidor\",\n  \"components.Settings.startscan\": \"Iniciar Varredura\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.sonarrsettings\": \"Configurações do Sonarr\",\n  \"components.Settings.radarrsettings\": \"Configurações do Radarr\",\n  \"components.Settings.port\": \"Porta\",\n  \"components.Settings.plexsettingsDescription\": \"Configure os dados de conexão com servidor Plex. Seerr escanea suas bibliotecas do Plex em busca de novo conteúdo disponível.\",\n  \"components.Settings.plexsettings\": \"Configurações do Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"Bibliotecas que Seerr irá buscar por títulos. Configure e salve as informações de conexão com Plex e clique no botão abaixo se nenhuma biblioteca for listada.\",\n  \"components.Settings.SettingsAbout.timezone\": \"Fuso Horário\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Ver no GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Ver Mudanças\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Mudanças em {version}\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Versões\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Informações de versão indisponíveis.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Última Versão\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Atual\",\n  \"components.TvDetails.recommendations\": \"Recomendações\",\n  \"components.TvDetails.overviewunavailable\": \"Sinopse indisponível.\",\n  \"components.TvDetails.overview\": \"Sinopse\",\n  \"components.TvDetails.originallanguage\": \"Língua Original\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Emissora} other {Emissoras}}\",\n  \"components.TvDetails.cast\": \"Elenco\",\n  \"components.TvDetails.anime\": \"Animes\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Elenco Completo da Série\",\n  \"components.Setup.welcome\": \"Bem-Vindo ao Seerr\",\n  \"components.Setup.signinMessage\": \"Comece entrando com sua conta Plex\",\n  \"components.Setup.finishing\": \"Finalizando…\",\n  \"components.Setup.finish\": \"Finalizar Configurações\",\n  \"pages.returnHome\": \"Voltar Para Página Inicial\",\n  \"pages.oops\": \"Opa\",\n  \"i18n.unavailable\": \"Indisponível\",\n  \"i18n.tvshows\": \"Séries\",\n  \"i18n.processing\": \"Processando\",\n  \"i18n.pending\": \"Pendente\",\n  \"i18n.partiallyavailable\": \"Parcialmente Disponível\",\n  \"i18n.movies\": \"Filmes\",\n  \"i18n.declined\": \"Rejeitado\",\n  \"i18n.decline\": \"Rejeitar\",\n  \"i18n.close\": \"Fechar\",\n  \"i18n.cancel\": \"Cancelar\",\n  \"i18n.available\": \"Disponível\",\n  \"i18n.approved\": \"Aprovada\",\n  \"i18n.approve\": \"Aprovar\",\n  \"components.UserList.userlist\": \"Lista de Usuários\",\n  \"components.UserList.userdeleteerror\": \"Algo deu errado ao remover usuário.\",\n  \"components.UserList.userdeleted\": \"Usuário removido com sucesso!\",\n  \"components.UserList.user\": \"Usuário\",\n  \"components.UserList.totalrequests\": \"Solicitações\",\n  \"components.UserList.role\": \"Privilégio\",\n  \"components.UserList.plexuser\": \"Usuário Plex\",\n  \"components.UserList.deleteuser\": \"Deletar Usuário\",\n  \"components.UserList.deleteconfirm\": \"Tem certeza que deseja apagar esse usuário? Todas informações de solicitações feitas por esse usuário serão permanentemente removidas.\",\n  \"components.UserList.created\": \"Criado\",\n  \"components.UserList.admin\": \"Administrador\",\n  \"components.TvDetails.similar\": \"Séries Semelhantes\",\n  \"components.TvDetails.showtype\": \"Tipo de Série\",\n  \"components.RequestModal.requestseasons\": \"Solicitar {seasonCount} {seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.TvDetails.viewfullcrew\": \"Ver Toda Equipe Técnica\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Equipe Técnica Completa da Série\",\n  \"components.PersonDetails.crewmember\": \"Membros\",\n  \"components.MovieDetails.viewfullcrew\": \"Ver Equipe Técnica Completa\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Equipe Técnica Completa\",\n  \"components.UserList.importfromplexerror\": \"Algo deu errado ao importar usuários do Plex.\",\n  \"components.UserList.importfromplex\": \"Importar Usuários do Plex\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> {userCount, plural, one {usuário Plex importado} other {usuários Plex importados}} com sucesso!\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Habilitar Agente\",\n  \"components.RequestList.RequestItem.failedretry\": \"Algo deu errado ao retentar fazer a solicitação.\",\n  \"components.MovieDetails.watchtrailer\": \"Assistir Trailer\",\n  \"components.CollectionDetails.requestcollection\": \"Solicitar Coleção\",\n  \"components.CollectionDetails.overview\": \"Sinopse\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Filmes\",\n  \"i18n.requested\": \"Solicitado\",\n  \"i18n.retry\": \"Tentar Novamente\",\n  \"i18n.failed\": \"Falhou\",\n  \"components.TvDetails.watchtrailer\": \"Assisitir Trailer\",\n  \"components.TvDetails.firstAirDate\": \"Primeira Exibição\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Você deve prover um ID de Chat válido\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Você deve prover uma chave de autorização do Bot\",\n  \"components.Settings.Notifications.senderName\": \"Nome do Remetente\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Configurações de notificação via Telegram salvas com sucesso!\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Falha ao salvar configurações de notificação via Telegram.\",\n  \"components.Settings.Notifications.chatId\": \"ID de Chat\",\n  \"components.Settings.Notifications.botAPI\": \"Token de Autorização do Bot\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Permitir certificados auto-assinados\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Configurações de notificação via Slack salvas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Falha ao salvar configurações de notificação via Slack.\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentação\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Envia notificações quando outros usuários solicitarem novas mídias que requerem aprovação.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Solicitação Disponível\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Solicitação Aprovada\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Solicitação com Aprovação Pendente\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Envia notificaões quando solicitações de mídia falharem ao serem adicionadas ao Radarr ou Sonarr.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Falha ao Processar Solicitação\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Envia notificações quando mídias solicitadas estiverem disponíveis.\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Enviar notificações quando solicitações de mídia são aprovadas manualmente.\",\n  \"i18n.request\": \"Solicitar\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Você deve prover uma chave válida de usúario ou grupo\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Você deve prover uma chave válida de acesso\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Chave do Usuário ou Grupo\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Configurações de notificação via Pushover salvas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Falha ao salvar configurações de notificação via Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Habilitar Agente\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token de Acesso\",\n  \"components.RequestList.sortModified\": \"Última Mudança\",\n  \"components.RequestList.sortAdded\": \"Mais Recente\",\n  \"components.RequestList.showallrequests\": \"Exibir Todas Solicitações\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.RequestModal.pending4krequest\": \"Solicitação em 4K Pendente\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Configurações de notificação via Webhook salvas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Falha ao salvar configurações de notificação via Webhook.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Você deve prover um conteúdo JSON válido\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Ajuda Com Modelos de Variáveis\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON restaurado para conteúdo padrão!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Restaurar Padrão\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Conteúdo JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Cabeçalho de Autorização\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Habilitar Agente\",\n  \"components.RequestButton.viewrequest4k\": \"Ver Solicitação 4K\",\n  \"components.RequestButton.viewrequest\": \"Ver Solicitação\",\n  \"components.RequestButton.requestmore4k\": \"Solicitar Mais em 4K\",\n  \"components.RequestButton.requestmore\": \"Solicitar Mais\",\n  \"components.RequestButton.declinerequests\": \"Rejeitar {requestCount, plural, one {Solicitação} other {{requestCount} Solicitações}}\",\n  \"components.RequestButton.declinerequest4k\": \"Rejeitar Solicitação 4K\",\n  \"components.RequestButton.declinerequest\": \"Rejeitar Solicitação\",\n  \"components.RequestButton.decline4krequests\": \"Rejeitar {requestCount, plural, one {Solicitação} other {{requestCount} Solicitações}} em 4K\",\n  \"components.RequestButton.approverequests\": \"Aprovar {requestCount, plural, one {Solicitação} other {{requestCount} Solicitações}}\",\n  \"components.RequestButton.approverequest4k\": \"Aprovar Solicitação 4K\",\n  \"components.RequestButton.approverequest\": \"Aprovar Solicitação\",\n  \"components.RequestButton.approve4krequests\": \"Aprovar {requestCount, plural, one {Solicitação 4K} other {{requestCount} Solicitações 4K}}\",\n  \"components.UserList.validationpasswordminchars\": \"Senha muito curta; necessário ter no mínimo 8 caracteres\",\n  \"components.UserList.usercreatedsuccess\": \"Usuário criado com sucesso!\",\n  \"components.UserList.usercreatedfailed\": \"Algo deu errado ao criar usuário.\",\n  \"components.UserList.passwordinfodescription\": \"Configure a URL da aplicação e habilite notificações via e-mail para permitir a geração automática de senha.\",\n  \"components.UserList.password\": \"Senha\",\n  \"components.UserList.localuser\": \"Usuário Local\",\n  \"components.UserList.email\": \"Endereço de E-mail\",\n  \"components.UserList.creating\": \"Criando…\",\n  \"components.UserList.createlocaluser\": \"Criar Usuário Local\",\n  \"components.UserList.create\": \"Criar\",\n  \"components.UserList.autogeneratepassword\": \"Gerar Senha Automaticamente\",\n  \"components.Login.validationpasswordrequired\": \"Você deve prover uma senha\",\n  \"components.Login.validationemailrequired\": \"Você deve prover um e-mail válido\",\n  \"components.Login.signinwithoverseerr\": \"Entrar com sua conta {applicationTitle}\",\n  \"components.Login.password\": \"Senha\",\n  \"components.Login.loginerror\": \"Algo deu errado ao tentar se autenticar.\",\n  \"components.Login.email\": \"Endereço de E-mail\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Envia notificações quando solicitações de mídia são recusadas.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Solicitação Recusada\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Ver Mais\",\n  \"components.RequestModal.requestedited\": \"Solicitação de <strong>{title}</strong> alterada com sucesso!\",\n  \"components.RequestModal.requestcancelled\": \"Solicitação de <strong>{title}</strong> foi cancelada.\",\n  \"components.RequestModal.errorediting\": \"Algo deu errado ao modificar a solicitação.\",\n  \"components.RequestModal.autoapproval\": \"Aprovação Automática\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Pasta Raiz\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Perfil de Qualidade\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Servidor de Destino\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Padrão)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Esta série é um anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avançado\",\n  \"components.RequestBlock.server\": \"Servidor de Destino\",\n  \"components.RequestBlock.rootfolder\": \"Pasta Raiz\",\n  \"components.RequestBlock.requestoverrides\": \"Mudanças na solicitação\",\n  \"components.RequestBlock.profilechanged\": \"Perfil de Qualidade\",\n  \"i18n.edit\": \"Editar\",\n  \"i18n.experimental\": \"Experimental\",\n  \"components.RequestModal.requesterror\": \"Algo deu errado ao solicitar mídia.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Não conseguimos correlacionar sua solicitação automaticamente. Por favor selecione a correspondência correta na lista abaixo.\",\n  \"components.Login.signin\": \"Entrar\",\n  \"components.UserList.userssaved\": \"Permissões de usuário salvas com sucesso!\",\n  \"components.UserList.bulkedit\": \"Edição Em Massa\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Lista de servidores do Plex obtida com sucesso!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Falha ao obter a lista de servidores do Plex.\",\n  \"components.Settings.toastPlexRefresh\": \"Obtendo lista de servidores do Plex…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Conexão com Plex estabelecida com sucesso!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Falha ao se conectar ao Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"Tentando se conectar ao Plex…\",\n  \"components.Settings.settingUpPlexDescription\": \"Para configurar o Plex, você pode entrar com as configurações manualmente ou escolher um dos servidores disponívies obtivos de <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Clique no botão próximo à lista para obter os servidores disponíveis.\",\n  \"components.Settings.serverpresetRefreshing\": \"Obtendo servidores…\",\n  \"components.Settings.serverpresetManualMessage\": \"Configurar manualmente\",\n  \"components.Settings.serverpresetLoad\": \"Clique para carregar servidores disponíveis\",\n  \"components.Settings.serverpreset\": \"Servidor\",\n  \"components.Settings.serverRemote\": \"remoto\",\n  \"components.Settings.serverLocal\": \"local\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Configure e habilite agentes de notificação.\",\n  \"components.Login.signingin\": \"Autenticando…\",\n  \"components.PermissionEdit.usersDescription\": \"Concede permissão para gerenciar usuários. Usuários com essa permissão não podem modificar usuários com acesso Administrativo, ou condecer tal permissão.\",\n  \"components.PermissionEdit.users\": \"Gerenciar Usuários\",\n  \"components.PermissionEdit.requestDescription\": \"Concede permissão para solicitar mídia não 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Concede permissão para solicitar séries em 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"Solicitar Séries em 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Concede permissão para solicitar filmes em 4K.\",\n  \"components.PermissionEdit.request4kMovies\": \"Solicitar Filmes em 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Concede permissão para solicitar mídia em 4K.\",\n  \"components.PermissionEdit.request4k\": \"Solicitar 4K\",\n  \"components.PermissionEdit.request\": \"Solicitar\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Concede permissão para gerenciar solicitações de mídia. Todas solicitações feitas por um usuário com esse perfil serão automaticamente aprovadas.\",\n  \"components.PermissionEdit.managerequests\": \"Gerenciar Solicitações\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Concede aprovação automática para solicitações de séries não 4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Aprovar Séries Automaticamente\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Concede aprovação automática para solicitações de filmes não 4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Aprovar Filmes Automaticamente\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Concede aprovação automática para todas solicitações de mídia não 4K.\",\n  \"components.PermissionEdit.autoapprove\": \"Aprovar Automaticamente\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Concede permissão para alterar solicitações avançadas de mídia.\",\n  \"components.PermissionEdit.advancedrequest\": \"Solicitações Avançadas\",\n  \"components.PermissionEdit.adminDescription\": \"Acesso administrativo completo. Ignora todas outras checagens de privilégios.\",\n  \"components.PermissionEdit.admin\": \"Administrador\",\n  \"components.Login.signinwithplex\": \"Entrar com sua conta Plex\",\n  \"components.Login.signinheader\": \"Autentique para continuar\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Conexão com Sonarr estabelecida com sucesso!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Falha ao conectar-se ao Sonarr.\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Habilitar Escaneamento\",\n  \"components.Settings.SonarrModal.externalUrl\": \"URL Externa\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Habilitar Escaneamento\",\n  \"components.Settings.RadarrModal.externalUrl\": \"URL Externa\",\n  \"components.MovieDetails.markavailable\": \"Marcar como Disponível\",\n  \"components.MovieDetails.mark4kavailable\": \"Marcar como Disponível em 4K\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Cache {cachename} limpo.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Tamanho do Valor\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Não Encontrado\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Tamanho da Chave\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Total de Chaves\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Encontrado\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Nome do Cache\",\n  \"i18n.advanced\": \"Avançado\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Executar Agora\",\n  \"components.Settings.SettingsJobsCache.process\": \"Processo\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Próxima Execução\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tipo\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} iniciado(a).\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr executa tarefas regularares de manutenção de forma automática, mas elas podem também serem iniciadas manualmente abaixo. Tarefas executadas manualmente não irão afetar o agendamento da próxima execução.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Tarefas\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Nome da Tarefa\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} cancelado(a).\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Limpar Cache\",\n  \"components.Settings.SettingsJobsCache.command\": \"Comando\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Cancelar Tarefa\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr armazena temporariamente as solicitações à APIs externas para otimizar performance e evitar novas chamadas desnecessárias.\",\n  \"components.UserList.users\": \"Usuários\",\n  \"components.Setup.setup\": \"Configurar\",\n  \"components.Search.search\": \"Pesquisar\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Solicitar Como\",\n  \"components.Discover.discover\": \"Explorar\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"O ponto de montagem<code>{appDataPath}</code> não foi corretamente configurado. Todos dados serão perdidos quando o container parar ou reiniciar.\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"A URL não pode terminar com uma barra\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Você deve prover uma URL válida\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"A URL não pode terminar com uma barra\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Você deve prover uma URL válida\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Concede permissão para visualizar solicitações de mídia feita por outros usuários.\",\n  \"components.PermissionEdit.viewrequests\": \"Visualizar Solicitações\",\n  \"components.UserList.validationEmail\": \"Você deve prover um e-mail válido\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"URL Base não deve terminar com uma barra\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"URL Base deve ter iniciar com uma barra\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL Base não deve terminar com uma barra\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL Base deve iniciar com uma barra\",\n  \"components.Settings.Notifications.validationEmail\": \"Você deve prover um e-mail válido\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Você deve prover uma URL válida\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Você deve prover uma URL válida\",\n  \"components.TvDetails.nextAirDate\": \"Próxima Transmissão\",\n  \"components.ResetPassword.email\": \"Endereço de E-mail\",\n  \"components.ResetPassword.resetpassword\": \"Alterar sua Senha\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Você deve prover uma senha\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Senha muito curta. Ela deve ter minimo 8 caracteres\",\n  \"components.ResetPassword.validationpasswordmatch\": \"As senhas devem coincidir\",\n  \"components.ResetPassword.validationemailrequired\": \"Você deve prover um e-mail válido\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Um link para alteração de senha será enviado ao endereço de e-mail informado caso o mesmo esteja associado a um usuário válido.\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Senha redefinida com sucesso!\",\n  \"components.ResetPassword.password\": \"Senha\",\n  \"components.ResetPassword.gobacklogin\": \"Voltar para Página de Autenticação\",\n  \"components.ResetPassword.emailresetlink\": \"Envie um Link de Recuperação\",\n  \"components.ResetPassword.confirmpassword\": \"Confirme a Senha\",\n  \"components.Login.forgotpassword\": \"Esqueceu a Senha?\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Você deve selecionar um perfil de idioma\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Teste conexão para carregar perfis de idioma\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Selecione um perfil de Idioma\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Carregando perfis de Idioma…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Perfil de Idioma\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Perfil de Idioma de Animes\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Perfil de Idioma\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Envia notificações sem som\",\n  \"components.Settings.Notifications.sendSilently\": \"Enviar Silenciosamente\",\n  \"components.UserList.sortRequests\": \"Número de Solicitações\",\n  \"components.UserList.sortDisplayName\": \"Nome de Exibição\",\n  \"components.UserList.sortCreated\": \"Data de Criação\",\n  \"components.PermissionEdit.autoapprove4k\": \"Aprovar 4K Automaticamente\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Concede aprovação automática para solicitações de séries em 4K.\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Concede aprovação automática para solicitações de filmes em 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Aprovar Automaticamente Séries em 4K\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Aprovar Automaticamente Filmes em 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Concede aprovação automática para todas solicitações de mídia em 4K.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Você deve prover um token de acesso\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Configurações de notificação via Pushbullet salvas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Falha ao salvar configurações de notificação via Pushover.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Você deve prover uma nova senha\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Você deve prover sua senha atual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Você deve confirmar a nova senha\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Ver Perfil\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Usuário Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Usuário Local\",\n  \"components.UserProfile.recentrequests\": \"Solicitações Recentes\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Senha Atual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Senha salva com sucesso!\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Senha\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Senha\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Permissões\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Permissões\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nova Senha\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notificações\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Nome de Exibição\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID do Usuário\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Editar Configurações\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Confirme a Senha\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Permissões salvas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Configurações salvas com sucesso!\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Geral\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Configurações Gerais\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Configurações de Notificação\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"As senhas devem coincidir\",\n  \"components.UserList.userfail\": \"Algo deu errado ao salvar permissões de usuário.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Algo deu errado ao salvar configurações.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Algo deu errado ao salvar configurações.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Algo deu errado ao salvar senha.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"A senha é muito curta; Ela deve ter no mínimo 8 caractéres\",\n  \"components.UserList.edituser\": \"Editar Permissões de Usuário\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Habilitar Agente\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Token de Acesso\",\n  \"components.Layout.UserDropdown.settings\": \"Configurações\",\n  \"components.Layout.UserDropdown.myprofile\": \"Perfil\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Você deve prover um ID válido de usuário\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"O <FindDiscordIdLink>número de identificação</FindDiscordIdLink> correspondente ao seu usuário\",\n  \"components.CollectionDetails.requestcollection4k\": \"Solicitar Coleção em 4K\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Região de Exploração\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Idioma de Exploração\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.email\": \"E-mail\",\n  \"components.RegionSelector.regionDefault\": \"Todas Regiões\",\n  \"components.Discover.upcomingtv\": \"Séries em Breve\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtra conteúdo por disponibilidade na região\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtra conteúdo pela língua original\",\n  \"components.RegionSelector.regionServerDefault\": \"Padrão ({region})\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Você não tem permissão para modificar a senha desse usuário.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Usuário\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Privilégio\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Dono\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrador\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Tipo de Conta\",\n  \"components.UserList.owner\": \"Dono\",\n  \"components.UserList.accounttype\": \"Tipo\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Sincronizar Downloads\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Limpar Sincronização de Download\",\n  \"i18n.loading\": \"Carregando…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Você deve prover um ID válido de chat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Inicie uma conversa</TelegramBotLink>, adicione <GetIdBotLink>@get_id_bot</GetIdBotLink>, e envie o comando <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID de Chat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Envia notificações sem som\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Enviar Silenciosamente\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Temporada} other {# Temporadas}}\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Tarefa Desconhecida\",\n  \"components.Settings.Notifications.botUsername\": \"Usuário do Bot\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Séries de {genre}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Séries por {network}\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Filmes por {studio}\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Filmes de {genre}\",\n  \"components.Settings.Notifications.validationUrl\": \"Você deve prover uma URL válida\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL de Avatar do Bot\",\n  \"components.RequestList.RequestItem.requested\": \"Solicitado\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} por {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Modificada\",\n  \"components.Discover.StudioSlider.studios\": \"Estúdios\",\n  \"components.Discover.NetworkSlider.networks\": \"Emissora\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Séries em {language}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Filmes em {language}\",\n  \"components.Settings.scanning\": \"Sincronizando…\",\n  \"components.Settings.scan\": \"Sincronizar Bibliotecas\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Escaneamento do Sonarr\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Escanemento do Radarr\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Recentemente Adicionado ao Plex\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Escaneamento de Todas Bibliotecas do Plex\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Você não tem permissão para modificar as configurações desse usuários.\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Você não pode modificar suas próprias permissões.\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID de Usuário: {userid}\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Criado em {joindate}\",\n  \"components.Settings.menuUsers\": \"Usuários\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Define configurações globais e padrões de usuário.\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Configurações de Usuário\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Configurações do usuário salvas com sucesso!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Algo deu errado ao salvar configurações.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Habilitar Autenticação Local\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Permissões Padrão\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Assina mensagens encriptadas de e-mail usando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Chave PGP privada\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Assina mensagens encriptadas de e-mail usando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPassword\": \"Senha PGP\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Envia notificações quando usuários solicitarem mídias que são aprovadas automaticamente.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Solicitação Aprovada Automaticamente\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutos\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.TvDetails.episodeRuntime\": \"Duração do Episódio\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Gêneros de Séries\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Gêneros de Séries\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Gêneros de Filmes\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Gêneros de Filmes\",\n  \"components.RequestModal.alreadyrequested\": \"Já Solicitado\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"components.ResetPassword.passwordreset\": \"Redefinir Senha\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Detalhes do Log\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Algo deu errado ao salvar sua senha. Sua senha foi digitada corretamente?\",\n  \"pages.somethingwentwrong\": \"Algo deu errado\",\n  \"pages.serviceunavailable\": \"Serviço Indisponível\",\n  \"pages.pagenotfound\": \"Página Não Encontrada\",\n  \"pages.internalservererror\": \"Erro Interno no Servidor\",\n  \"i18n.usersettings\": \"Configurações de Usuário\",\n  \"i18n.settings\": \"Configurações\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notificações\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Geral\",\n  \"components.Settings.services\": \"Serviços\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Notificações\",\n  \"components.Settings.enablessl\": \"Usar SSL\",\n  \"components.Settings.SettingsUsers.users\": \"Usuários\",\n  \"components.Settings.SettingsLogs.time\": \"Data e Hora\",\n  \"components.Settings.SettingsLogs.showall\": \"Exibir Todas Mensagens\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Resumir\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pausar\",\n  \"components.Settings.SettingsLogs.message\": \"Mensagem\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Você pode ver esses logs diretamente via <code>stdout</code>, ou em <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.logs\": \"Logs\",\n  \"components.Settings.SettingsLogs.level\": \"Severidade\",\n  \"components.Settings.SettingsLogs.label\": \"Rótulo\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Alerta\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Informacional\",\n  \"components.Settings.SettingsLogs.filterError\": \"Erros\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Debug\",\n  \"components.Settings.SettingsLogs.extraData\": \"Informações Adicionais\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Copiar\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Mensagem copiada para área de transferência.\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Tarefas & Cache\",\n  \"components.Settings.SettingsAbout.about\": \"Sobre\",\n  \"components.UserList.nouserstoimport\": \"Nenhum novo usuário Plex para importar.\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Nascimento {birthdate}\",\n  \"components.PersonDetails.alsoknownas\": \"Também Conhecido(a) Como: {names}\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.view\": \"Exibir\",\n  \"i18n.tvshow\": \"Série\",\n  \"i18n.testing\": \"Testando…\",\n  \"i18n.test\": \"Testar\",\n  \"i18n.status\": \"Estado\",\n  \"i18n.showingresults\": \"Exibindo de <strong>{from}</strong> até <strong>{to}</strong> de <strong>{total}</strong> resultado(s)\",\n  \"i18n.saving\": \"Salvando…\",\n  \"i18n.save\": \"Salvar Mudanças\",\n  \"i18n.resultsperpage\": \"Exibir {pageSize} resultados por página\",\n  \"i18n.requesting\": \"Solicitando…\",\n  \"i18n.request4k\": \"Solicitar em 4K\",\n  \"i18n.previous\": \"Anterior\",\n  \"i18n.notrequested\": \"Não Solicitado(a)\",\n  \"i18n.noresults\": \"Sem resultados.\",\n  \"i18n.next\": \"Próxima\",\n  \"i18n.movie\": \"Filme\",\n  \"i18n.canceling\": \"Cancelando…\",\n  \"i18n.back\": \"Voltar\",\n  \"i18n.areyousure\": \"Você tem certeza?\",\n  \"i18n.all\": \"Todas\",\n  \"components.UserProfile.requestsperdays\": \"{limit} restante(s)\",\n  \"components.UserProfile.unlimited\": \"Ilimitadas\",\n  \"components.UserProfile.totalrequests\": \"Total de Solicitações\",\n  \"components.UserProfile.seriesrequest\": \"Solicitações de Séries\",\n  \"components.UserProfile.pastdays\": \"{type} (últimos {days} dias)\",\n  \"components.UserProfile.movierequests\": \"Solicitações de Filmes\",\n  \"components.UserProfile.limit\": \"{remaining} de {limit}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Limite de Solicitações de Séries\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Limite de Solicitações de Filmes\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Sobrepor Limite Global\",\n  \"components.TvDetails.originaltitle\": \"Título Original\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Limite Global de Solicitações de Séries\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Limite Global de Solicitações de Filmes\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {temporada} other {temporadas}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"temporada\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Esse usuário precisa ter ao menos <strong>{seasons}</strong> {seasons, plural, one {solicitação restante de série} other {solicitações restantes de séries}} para poder solicitar essa série.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Você precisa ter ao menos <strong>{seasons}</strong> {seasons, plural, one {solicitação restante de série} other {solicitações restantes de séries}} para poder solicitar essa série.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Nenhuma} other {<strong>#</strong>}} {remaining, plural, one {solicitação de {type} restante} other {solicitações de {type}s restantes}}\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Você pode ver um resumo dos limites de solicitação desse usuário em seu <ProfileLink>perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Você pode ver um resumo dos seus limites de solicitação em seu <ProfileLink>perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Não há solicitações de temporada suficientes restantes\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {filme} other {filmes}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"filme\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Esse usuário pode solicitar <strong>{limit}</strong> {type} a cada <strong>{days}</strong> dias.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Você pode solicitar <strong>{limit}</strong> {type} a cada <strong>{days}</strong> dias.\",\n  \"components.QuotaSelector.unlimited\": \"Ilimitados(as)\",\n  \"components.MovieDetails.originaltitle\": \"Título Original\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Todos Idiomas\",\n  \"components.LanguageSelector.languageServerDefault\": \"Padrão ({language})\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Nenhuma Tag.\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Teste a conexão para carregar as tags\",\n  \"components.Settings.SonarrModal.tags\": \"Tags\",\n  \"components.Settings.SonarrModal.selecttags\": \"Selecione as tags\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Nenhuma tag.\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Carregando tags…\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Editar Servidor Sonarr 4K\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Servidor 4K Padrão\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Adicionar Novo Servidor Sonarr 4K\",\n  \"components.Settings.SonarrModal.animeTags\": \"Tags Para Animes\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Teste a conexão para carregar as tags\",\n  \"components.Settings.RadarrModal.tags\": \"Tags\",\n  \"components.Settings.RadarrModal.selecttags\": \"Selecione as tags\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Nenhuma tag.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Carregando tags…\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Editar Servidor Radarr 4K\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Servidor 4K Padrão\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Adicionar Novo Servidor Radarr 4K\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Tags\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Selecione as tags\",\n  \"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.\",\n  \"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.\\\"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Você deve prover uma chave pública PGP válida\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Criptografa mensagens de e-mail usando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"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.\",\n  \"components.Settings.noDefaultServer\": \"Ao menos um servidor {serverType} deve ser marcado como padrão para que as solicitações de {mediaType} sejam processadas.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Configurações de notificação via Telegram salvas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Falha ao salvar configurações de notificação via Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Chave Pública PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Configurações de notificação via e-mail salvas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Falha ao salvar configurações de notificação via e-mail.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Configurações de notificação via Discord salvas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Falha ao salvar configurações de notificação via Discord.\",\n  \"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} <strong>NÃO</strong> deve ser designado como um servidor 4K.\",\n  \"components.Settings.mediaTypeSeries\": \"série\",\n  \"components.Settings.mediaTypeMovie\": \"filme\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Atualizado\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Desatualizado\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Você deve prover uma chave PGP privada válida\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Você deve prover uma senha PGP\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Permitir que usuários iniciem uma conversa com o seu bot e configure suas próprias notificações\",\n  \"components.RequestModal.pendingapproval\": \"Sua solicitação está aguardando aprovação.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} Não Encontrado\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Apagar Solicitação\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Cancelar Solicitação\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} Não Encontrado\",\n  \"components.RequestCard.deleterequest\": \"Apagar Solicitação\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Tipos de Notificação\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Estável\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Desenvolvedor\",\n  \"components.Layout.VersionStatus.outofdate\": \"Desatualizado\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {versão} other {versões}} atrasado(a)\",\n  \"components.UserList.autogeneratepasswordTip\": \"Envia para o usuário uma senha gerada automaticamente\",\n  \"i18n.retrying\": \"Tentando Novamente…\",\n  \"components.UserList.usercreatedfailedexisting\": \"O e-mail informado já está em uso por outro usuário.\",\n  \"components.Settings.serverSecure\": \"segura\",\n  \"components.RequestModal.edit\": \"Editar Solicitação\",\n  \"components.RequestList.RequestItem.editrequest\": \"Editar Solicitação\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Habilitar Busca Automática\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Habilitar Busca Automática\",\n  \"components.PermissionEdit.requestMovies\": \"Solicitar Filmes\",\n  \"components.DownloadBlock.estimatedtime\": \"Estimativa {time}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Padrão ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Idioma da Interface\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Permite que novos usuários do Plex entrem sem terem que ser importados\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Habilitar Novo Método de Início de Sessão do Plex\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Criar um <DiscordWebhookLink>webhook de integração</DiscordWebhookLink> no seu servidor\",\n  \"components.Settings.Notifications.encryptionTip\": \"Na maioria do casos TLS Implícito usa a porta 465 e STARTTLS usa a porta 587\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Sempre usar STARTTLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"Nenhuma\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Usar TLS Implícito\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Usar STARTTLS se disponível\",\n  \"components.Settings.Notifications.encryption\": \"Método de Encriptação\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Criar um bot</CreateBotLink> para usar com Seerr\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Configurações de notificação via web push salvas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Falha ao salvar configurações de notificação via web push.\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Para receber notificações via web push, o Seerr deve ser acessível via HTTPS.\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Criar integração para um <WebhookLink>webhook de entrada</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Seu <UsersGroupsLink>identificador de usuário ou grupo</UsersGroupsLink> contendo 30 caractéres\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registre uma aplicação</ApplicationRegistrationLink> para usar com Seerr\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Notificação de teste via Telegram enviada!\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Notificação de teste via e-mail enviada!\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Notificação de teste via Discord enviada!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Notificação de teste via webhook enviada!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Notificação de teste via web push enviada!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Notificação de teste via Slack enviada!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Notificação de teste via Pushover enviada!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Notificação de teste via Pushbullet enviada!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Falha ao enviar notificação de teste via web push.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Falha ao enviar notificação de teste via webhook.\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Falha ao enviar notificação de teste via e-mail.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Enviando notificação de teste via Telegram…\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Enviando notificação de teste via e-mail…\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Enviando notificação de teste via Discord…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Enviando notificação de teste via webhook…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Enviando notificação de teste via web push…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Enviando notificação de teste via Slack…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Enviando notificação de teste via Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Enviando notificação de teste via Pushbullet…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Falha ao enviar notificação de teste via Telegram.\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Falha ao enviar notificação de teste via Discord.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Falha ao enviar notificação de teste via Slack.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Falha ao enviar notificação de teste via Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Falha ao enviar notificação de teste via Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Criar um token à partir de sua <PushbulletSettingsLink>Configuração de Conta</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Habilitar Agente\",\n  \"components.PermissionEdit.requestTvDescription\": \"Concede permissão para solicitar séries em não 4K.\",\n  \"components.PermissionEdit.requestTv\": \"Solicitar Séries\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Concede permissão para solicitar filmes em não 4K.\",\n  \"components.Settings.Notifications.chatIdTip\": \"Inicie um chat com seu bot, adicione <GetIdBotLink>@get_id_bot</GetIdBotLink> e execute o comando <code>/my_id</code>\",\n  \"components.UserList.localLoginDisabled\": \"A opção <strong>Habilitar Autenticação Local</strong> está atualmente desabilitada.\",\n  \"components.Settings.webAppUrlTip\": \"Você tem a opção de direcionar os usuários ao aplicativo web ao invés da versão \\\"hospedada\\\" em seu servidor\",\n  \"components.Settings.webAppUrl\": \"URL do <WebAppLink>Aplicativo Web</WebAppLink>\",\n  \"components.Settings.noDefault4kServer\": \"Um servidor {serverType} 4K deve ser marcado como padrão para que usuários possam solicitar {mediaType} em 4K.\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Solicitado\",\n  \"components.RequestCard.failedretry\": \"Algo deu errado ao retentar fazer a solicitação.\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Permitir que usuários se autentiquem usando seus endereços e-mails e senhas ao invés de Plex OAuth\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Permissões iniciais atribuídas à novos usuários\",\n  \"components.Settings.Notifications.validationTypes\": \"Você deve selecionar ao menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Você deve selecionar ao menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Você deve selecionar ao menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Você deve selecionar ao menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Você deve selecionar ao menos um tipo de notificação\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{temporadas} a cada {quotaDays} {dias}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {temporada} other {temporadas}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {file} other {filmes}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{filmes} a cada {quotaDays} {dias}</quotaUnits>\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {dia} other {dias}}\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Seja notificado quando outros usuários solicitarem novas mídias que requerem aprovação.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Seja notificado quando solicitações de mídia falharem ao serem adicionadas ao Radarr ou Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Seja notificado quando suas solicitações de mídia forem rejeitadas.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Seja notificado quando suas solicitações de mídia se tornarem disponíveis.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Seja notificado quando suas solicitações de mídia são aprovadas.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Seja notificado quando outros usuários solicitarem novas mídias que são automaticamente aprovadas.\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Idioma da Interface\",\n  \"components.MovieDetails.showmore\": \"Mostrar Mais\",\n  \"components.MovieDetails.showless\": \"Mostrar Menos\",\n  \"components.TvDetails.streamingproviders\": \"Em Exibição na\",\n  \"components.MovieDetails.streamingproviders\": \"Em Exibição na\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Tarefa modificada com sucesso!\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Nova Frequência\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"A cada {jobScheduleHours, plural, one {hora} other {{jobScheduleHours} horas}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"A cada {jobScheduleMinutes, plural, one {minuto} other {{jobScheduleMinutes} minutos}}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Você tem certeza que deseja apagar este comentário?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Apagar Comentário\",\n  \"components.IssueDetails.IssueComment.edit\": \"Editar Comentário\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Feito {relativeTime} por {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Feito {relativeTime} por {username} (Edited)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Você deve escrever uma mensagem\",\n  \"components.IssueDetails.closeissueandcomment\": \"Fechar com Comentário\",\n  \"components.IssueDetails.comments\": \"Comentários\",\n  \"components.IssueDetails.episode\": \"Episódio {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Problema\",\n  \"components.IssueDetails.issuetype\": \"Tipo\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Apagar Problema\",\n  \"components.IssueDetails.IssueDescription.description\": \"Descrição\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Você tem certeza que deseja apagar este problema?\",\n  \"components.IssueDetails.nocomments\": \"Nenhum comentário.\",\n  \"components.IssueDetails.allepisodes\": \"Todos Episódios\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Alterar Descrição\",\n  \"components.IssueDetails.allseasons\": \"Todas Temporadas\",\n  \"components.IssueDetails.leavecomment\": \"Comentar\",\n  \"components.IssueDetails.closeissue\": \"Encerrar Problema\",\n  \"components.IssueDetails.deleteissue\": \"Apagar Problema\",\n  \"components.IssueDetails.lastupdated\": \"Última Atualização\",\n  \"components.IssueDetails.openedby\": \"#{issueId} aberto {relativeTime} por {username}\",\n  \"components.IssueDetails.openinarr\": \"Abrir no {arr}\",\n  \"components.IssueDetails.reopenissue\": \"Re-abrir Problema\",\n  \"components.IssueDetails.problemepisode\": \"Episódio Afetado\",\n  \"components.IssueDetails.problemseason\": \"Temporada Afetada\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Re-abrir com Comentário\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Algo deu errado ao editar a descrição do problema.\",\n  \"components.IssueDetails.toastissuedeleted\": \"Problema apagado com sucesso!\",\n  \"components.IssueDetails.openin4karr\": \"Abrir em {arr} 4K\",\n  \"components.IssueDetails.playonplex\": \"Assistir no Plex\",\n  \"components.IssueDetails.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Descrição do problema alterada com sucesso!\",\n  \"components.IssueDetails.play4konplex\": \"Assistir em 4K no Plex\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Algo deu errado ao apagar problema.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Estado do problema atualizado com sucesso!\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Espisódio} other {Episódios}}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extras\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Por favor, explique em detalhes o problema que você encontrou.\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Estado\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tipo\",\n  \"components.IssueList.IssueItem.opened\": \"Aberto\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} por {user}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Desconhecido\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Algo deu errado ao atualizar o estado do problema.\",\n  \"components.IssueDetails.unknownissuetype\": \"Desconhecido\",\n  \"components.IssueList.issues\": \"Problemas\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Episódio Afetado\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Temporada Afetada\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Episódio Afetado\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.IssueList.IssueItem.viewissue\": \"Ver Problema\",\n  \"components.IssueList.showallissues\": \"Exibir Todos Problemas\",\n  \"components.IssueList.sortAdded\": \"Mais Recente\",\n  \"components.IssueList.sortModified\": \"Última Modificação\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Todos Episódios\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Todas Temporadas\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episódio {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Enviar Problema\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Relato de problema em <strong>{title}</strong> enviado com sucesso!\",\n  \"components.IssueModal.issueVideo\": \"Vídeo\",\n  \"components.Layout.Sidebar.issues\": \"Problemas\",\n  \"components.ManageSlideOver.downloadstatus\": \"Downloads\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Algo deu errado ao enviar problema.\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Ver Problema\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Reportar um Problema\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Você deve prover uma descrição\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"O quê há de errado?\",\n  \"components.IssueModal.issueAudio\": \"Áudio\",\n  \"components.IssueModal.issueOther\": \"Outros\",\n  \"components.IssueModal.issueSubtitles\": \"Legenda\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Limpar Dados\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Isso irá remover em definitivo todos dados desse(a) {mediaType}, incluindo quaisquer solicitações para esse item. Se este item existir in sua biblioteca do {mediaServerName}, os dados de mídia serão recriados na próxima sincronia.\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Problemas Abertos\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Nenhuma solicitação.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Solicitações\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Gerenciar {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Marcar como Disponível em 4K\",\n  \"components.ManageSlideOver.markavailable\": \"Marcar como Disponível\",\n  \"components.ManageSlideOver.movie\": \"filme\",\n  \"components.ManageSlideOver.openarr4k\": \"Abrir no {arr} 4K\",\n  \"components.ManageSlideOver.tvshow\": \"série\",\n  \"components.PermissionEdit.createissuesDescription\": \"Concede permissão para reportar problemas com mídias.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Comentário no Problema\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Enviar notificações quando problemas receberem novos comentários.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problema Re-aberto\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Enviar notificações quando problemas são re-abertos.\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Enviar notificações quando problemas são resolvidos.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Receber notificação quando problemas que você reportou forem re-abertos.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Receber notificação quando problemas que você reportou forem resolvidos.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Receber notificação quando outros usuários reportarem problemas.\",\n  \"components.PermissionEdit.manageissues\": \"Gerenciar Problemas\",\n  \"components.PermissionEdit.viewissues\": \"Ver Problemas\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Concede permissão para ver problemas em mídias reportados por outros problemas.\",\n  \"components.RequestModal.requestmovies4k\": \"Solicitar {count} {count, plural, one {Filme} other {Filmes}} em 4K\",\n  \"components.RequestModal.selectmovies\": \"Selecionar Filme(s)\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Token de Acesso\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registre uma aplicação</ApplicationRegistrationLink> para uso com {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Chave do Usuário ou Grupo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Seu <UsersGroupsLink>identificador de usuário ou grupo</UsersGroupsLink> contendo 30 caractéres\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problema Resolvido\",\n  \"components.ManageSlideOver.openarr\": \"Abrir no {arr}\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Receber notificação quando outros usuários comentarem nos problemas.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Receber notificação quando problemas são resolvidos por outros usuários.\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Enviar notificações quando problemas são reportados.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Receber notificação quando problemas reportados por você receberem novos comentários.\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {País} other {Países}} de Produção\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Concede permissão para gerenciar problemas com mídia.\",\n  \"components.RequestModal.requestmovies\": \"Solicitar {count} {count, plural, one {Filme} other {Filmes}}\",\n  \"components.RequestModal.requestseasons4k\": \"Solicitar {seasonCount} {seasonCount, plural, one {Temporada} other {Temporadas}} em 4K\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Editar Tarefa\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Você está usando a versão <code>develop</code> do Seerr que é recomendada apenas para àqueles contribuindo com o desenvolvimento ou ajudando no teste de novas funcionalidades.\",\n  \"components.TvDetails.productioncountries\": \"{countryCount, plural, one {País} other {Países}} de Produção\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Token de Acesso\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Falha ao salvar configurações de notificação via Pushover.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Criar um token à partir de sua <PushbulletSettingsLink>Configuração de Conta</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Configurações de notificação via Pushbullet salvas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Falha ao salvar configurações de notificação via Pushover.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Você deve prover um token de acesso\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Configurações de notificação via Pushover salvas com sucesso!\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Receber notificação quando problemas forem re-abertos por outros usuários.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Algo deu errado ao salvar tarefa.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Você deve prover uma chave válida de acesso\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Você deve prover uma chave válida de usúario ou grupo\",\n  \"components.PermissionEdit.createissues\": \"Reportar Problemas\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problema Reportado\",\n  \"i18n.open\": \"Aberto\",\n  \"i18n.resolved\": \"Resolvido\",\n  \"components.IssueDetails.commentplaceholder\": \"Adicionar um comentário…\",\n  \"components.RequestModal.requestApproved\": \"Solicitação de <strong>{title}</strong> aprovada!\",\n  \"components.RequestModal.approve\": \"Aprovar Solicitação\",\n  \"components.Settings.RadarrModal.announced\": \"Anunciado\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Nos Cinemas\",\n  \"components.Settings.RadarrModal.released\": \"Lançado\",\n  \"components.Settings.Notifications.enableMentions\": \"Habilitar Menções\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Habilitar Agente\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Falha ao salvar configurações de notificação via Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Falha ao enviar notificação de teste via Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Enviando notificação de teste via Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Notificação de teste via Gotify enviada!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token de Acesso\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL do Servidor\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Você deve selecionar ao menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"A URL não deve terminar com uma barra\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Você deve prover uma URL válida\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Configurações de notificação via Gotify salvas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Você deve prover um token de acesso\",\n  \"components.Settings.externalUrl\": \"URL Externa\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avançado\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Mídia 4K\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Mídia\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Marcar Todas Temporadas como Disponíveis em 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Marcar Todas Temporadas como Disponíveis\",\n  \"components.ManageSlideOver.opentautulli\": \"Abrir no Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Últimos {days, number} Dias\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {Reprodução} other {Reproduções}}\",\n  \"components.Settings.tautulliApiKey\": \"Chave de API\",\n  \"components.Settings.tautulliSettings\": \"Configurações do Tautulli\",\n  \"components.Settings.tautulliSettingsDescription\": \"Você tem a opção de configurar a integração com seu servidor Tautulli. Overseer irá obter o histórico de reproduções de suas mídias no Plex através do Tautulli.\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Algo deu errado ao salvar configurações do Tautulli.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Configurações do Tautulli salvas com sucesso!\",\n  \"components.Settings.urlBase\": \"URL Base\",\n  \"components.Settings.validationApiKey\": \"Você deve prover uma chave de API válida\",\n  \"components.Settings.validationUrl\": \"Você deve prover uma URL válida\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL Base deve iniciar com uma barra\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"A URL base não pode terminar com uma barra\",\n  \"components.Settings.validationUrlTrailingSlash\": \"A URL não pode terminar com uma barra\",\n  \"components.UserList.newplexsigninenabled\": \"A opção <strong>Habilitar Novo Método de Início de Sessão do Plex</strong> está habilitada. Usuários Plex com acesso à bibliotecas podem se autenticar sem que precisem serem importados.\",\n  \"i18n.importing\": \"Importando…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID do Usuário Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"O <FindDiscordIdLink>número de identificação</FindDiscordIdLink> associado à sua conta Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Você deve prover um ID válido de usuário Discord\",\n  \"components.UserProfile.recentlywatched\": \"Assistidos Recentemente\",\n  \"i18n.import\": \"Importar\",\n  \"components.ManageSlideOver.alltime\": \"Desde Início\",\n  \"components.ManageSlideOver.playedby\": \"Reproduzido por\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Tag do Canal\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Configurações\",\n  \"components.RequestBlock.languageprofile\": \"Perfil de Idioma\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Atualizado\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Por favor, reinicie o servidor para aplicar as novas configurações.\",\n  \"i18n.restartRequired\": \"Reinicialização Necessária\",\n  \"components.StatusChecker.reloadApp\": \"Recarregar {applicationTitle}\",\n  \"components.StatusChecker.restartRequired\": \"Reinicialização do Servidor Necessária\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Por favor, clique no botão abaixo para recarregar a aplicação.\",\n  \"components.Settings.deleteServer\": \"Remover Servidor {serverType}\",\n  \"components.MovieDetails.digitalrelease\": \"Lançamento Digital\",\n  \"components.MovieDetails.physicalrelease\": \"Lançamento em Disco\",\n  \"components.MovieDetails.theatricalrelease\": \"Lançamento no Cinema\",\n  \"components.PermissionEdit.viewrecent\": \"Ver Recentemente Adicionados\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Concede permissão para ver lista de mídias adicionadas recentemente.\",\n  \"components.RequestCard.tmdbid\": \"ID do TMDB\",\n  \"components.RequestCard.tvdbid\": \"ID do TheTVDB\",\n  \"components.RequestList.RequestItem.tmdbid\": \"ID do TMDB\",\n  \"components.RequestList.RequestItem.tvdbid\": \"ID do TheTVDB\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} Não Encontrado\",\n  \"components.TitleCard.tmdbid\": \"ID do TMDB\",\n  \"components.TitleCard.tvdbid\": \"ID do TheTVDB\",\n  \"components.TitleCard.cleardata\": \"Limpar Dados\",\n  \"components.PermissionEdit.autorequest\": \"Solicitar Automaticamente\",\n  \"components.PermissionEdit.autorequestMovies\": \"Solicitar Filmes Automaticamente\",\n  \"components.PermissionEdit.autorequestSeries\": \"Solicitar Séries Automaticamente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Solicitar Filmes Automaticamente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Solicitar Séries Automaticamente\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Sua Lista Para Assistir do Plex\",\n  \"components.Discover.plexwatchlist\": \"Sua Lista Para Assistir do Plex\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Lista Para Assistir do Plex\",\n  \"components.AirDateBadge.airedrelative\": \"Exibido em {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Exibição {relativeTime}\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Solicitações de Filmes\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Solicitações de Séries\",\n  \"components.Layout.UserDropdown.requests\": \"Solicitações\",\n  \"components.MovieDetails.managemovie\": \"Gerenciar Filme\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Ser notificado quando novas mídias de sua Lista Para Assistir do Plex forem automaticamente solicitadas.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Solicitação Enviada Automaticamente\",\n  \"components.PermissionEdit.autorequestDescription\": \"Concede permissão para enviar automaticamente solicitações de mídias não 4K via Lista Para Assistir do Plex.\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Concede permissão para enviar automaticamente solicitações de filmes não 4K via Lista Para Assistir do Plex.\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Concede permissão para enviar automaticamente solicitações de séries não 4K via Lista Para Assistir do Plex.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Ver Listas Para Assistir do Plex\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Conceder permissão para ver a Lista Para Assistir do Plex de outros usuários.\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Sincronizar Lista Para Assistir do Plex\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Ver Detalhes\",\n  \"components.Settings.advancedTooltip\": \"Se configurada incorretamente essa funcionalidade pode parar de funcionar\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr deve ser reiniciado para as mudanças nessa configuração terem efeito\",\n  \"components.Settings.experimentalTooltip\": \"Habilitar essa opção pode resultar em um comportamento inesperado da aplicação\",\n  \"components.TvDetails.reportissue\": \"Reportar um Problema\",\n  \"components.MovieDetails.reportissue\": \"Reportar um Problema\",\n  \"components.StatusBadge.managemedia\": \"Gerenciar {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Abrir em {arr}\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Algo deu errado ao obter dados da temporada.\",\n  \"components.TvDetails.manageseries\": \"Gerenciar Série\",\n  \"components.TvDetails.rtcriticsscore\": \"Tomatômetro do Rotten Tomatoes\",\n  \"components.TvDetails.seasonnumber\": \"Temporada {seasonNumber}\",\n  \"components.TvDetails.seasonstitle\": \"Temporadas\",\n  \"components.TvDetails.rtaudiencescore\": \"Avaliação da Audiência no Rotten Tomatoes\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.tmdbuserscore\": \"Avaliação de Usuários do TMDB\",\n  \"components.MovieDetails.tmdbuserscore\": \"Avaliação de Usuários do TMDB\",\n  \"components.MovieDetails.rtaudiencescore\": \"Avaliação da Audiência no Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatômetro do Rotten Tomatoes\",\n  \"components.RequestBlock.edit\": \"Editar Solicitação\",\n  \"components.RequestCard.approverequest\": \"Aprovar Solicitação\",\n  \"components.RequestBlock.approve\": \"Aprovar Solicitação\",\n  \"components.RequestBlock.requestdate\": \"Data de Solicitação\",\n  \"components.RequestCard.declinerequest\": \"Rejeitar Solicitação\",\n  \"components.RequestCard.editrequest\": \"Editar Solicitação\",\n  \"components.StatusBadge.playonplex\": \"Assitir no {mediaServerName}\",\n  \"components.RequestBlock.decline\": \"Rejeitar Solicitação\",\n  \"components.RequestBlock.lastmodifiedby\": \"Última Mudança Feita Por\",\n  \"components.RequestBlock.delete\": \"Apagar Solicitação\",\n  \"components.RequestBlock.requestedby\": \"Solicitado Por\",\n  \"components.RequestCard.cancelrequest\": \"Cancelar Solicitação\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Frequência Atual\",\n  \"components.Discover.networks\": \"Emissora\",\n  \"components.Discover.studios\": \"Estúdios\",\n  \"components.Settings.SettingsMain.apikey\": \"Chave de API\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Armazenar em cache imagens de origem externa (requer uma quantidade significativa de espaço em disco)\",\n  \"components.Settings.SettingsMain.general\": \"Geral\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Configurações Gerais\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Algo de errado ao salvar configurações.\",\n  \"components.Discover.CreateSlider.addSlider\": \"Adicionar Carrossel\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Criar Carrossel Personalizado\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Pesquisar estúdios…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Nome do Carrossel\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Filmes\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Carrossel removido com sucesso.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Alternar a Visibilidade\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Sua Lista Para Assistir do Plex\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Adicionado Recentemente\",\n  \"components.Discover.createnewslider\": \"Criar Novo Carrossel\",\n  \"components.Discover.customizediscover\": \"Personalizar Exploração\",\n  \"components.Discover.resettodefault\": \"Restaurar Padrão\",\n  \"components.Discover.tmdbsearch\": \"Pesquisa no TMDB\",\n  \"components.Discover.tmdbstudio\": \"Estúdio no TMDB\",\n  \"components.Discover.tmdbtvgenre\": \"Gênero de Série no TMDB\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularidade Ascendente\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Data de Lançamento Descendente\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Título (A-Z) Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Título (Z-A) Descendente\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Falha ao remover carrossel.\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Remover\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Título (A-Z) Ascendente\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Classificação TMDB Ascendente\",\n  \"components.Discover.tmdbtvkeyword\": \"Palavra-chave de Série no TMDB\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmes\",\n  \"components.Layout.Sidebar.browsetv\": \"Séries\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Temporada {seasonNumber} Episódio {episodeNumber}\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Solicitação Coleção em 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Solicitar Filme\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Cache de Imagens\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Imagens Armazenadas em Cache\",\n  \"components.UserProfile.emptywatchlist\": \"Mídia adicionadas à sua <PlexWatchlistSupportLink>Lista Para Assistir do Plex</PlexWatchlistSupportLink> aparecerão aqui.\",\n  \"components.UserProfile.plexwatchlist\": \"Lista Para Assistir do Plex\",\n  \"components.Discover.emptywatchlist\": \"Mídia adicionadas à sua <PlexWatchlistSupportLink>Lista Para Assistir do Plex</PlexWatchlistSupportLink> aparecerão aqui.\",\n  \"components.RequestCard.unknowntitle\": \"Título Desconhecido\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Título Desconhecido\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Tamanho Total do Cache\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Solicitar automaticamente filmes em sua <PlexWatchlistSupportLink>Lista Para Assistir do Plex</PlexWatchlistSupportLink>\",\n  \"components.Discover.CreateSlider.addfail\": \"Falha ao criar novo carrossel.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Editar Carrossel\",\n  \"components.Discover.CreateSlider.editfail\": \"Falha ao editar carrossel.\",\n  \"components.Discover.CreateSlider.needresults\": \"Você precisa ter ao menos 1 resultado.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Forneça um ID de gênero do TMDB\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Data de lançamento Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Classificação TMDB Descendente\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularidade Descendente\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Classificação TMDB Descendente\",\n  \"components.Discover.CreateSlider.nooptions\": \"Sem resultados.\",\n  \"components.Selector.nooptions\": \"Sem resultados.\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Forneça um ID de palavra-chave do TMDB\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Forneça um dado para pesquisa\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Forneça o ID do estúdio no TMDB\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Forneça o ID de emissora do TMDB\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Pesquisar gêneros…\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Avaliações entre {minValue} e {maxValue}\",\n  \"components.Discover.CreateSlider.starttyping\": \"Comece a digitar para pesquisar.\",\n  \"components.Selector.starttyping\": \"Comece a digitar para pesquisar.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Você deve prover um título.\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Filtro Ativo} other {# Filtros Ativos}}\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularidade Descendente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Classificação TMDB Ascendente\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularidade Ascendente\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmes\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Filtro Ativo} other {# Filtros Ativos}}\",\n  \"components.Selector.searchStudios\": \"Pesquisar estúdios…\",\n  \"components.TvDetails.Season.noepisodes\": \"Lista de episódios indisponível.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Solicitar automaticamente séries em sua <PlexWatchlistSupportLink>Lista Para Assistir do Plex</PlexWatchlistSupportLink>\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Séries\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Primeira Data de Exibição Ascendente\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Primeira Data de Exibição Descendente\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Filtro Ativo} other {# Filtros Ativos}}\",\n  \"components.Discover.FilterSlideover.from\": \"De\",\n  \"components.Discover.FilterSlideover.genres\": \"Gêneros\",\n  \"components.Discover.FilterSlideover.keywords\": \"Palavras-chave\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Título (Z-A) Descendente\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Limpar Filtros Ativos\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtros\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Primeira Exibição\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Pesquisar palavras-chave…\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Língua Original\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Data de Lançamento\",\n  \"components.Discover.FilterSlideover.runtime\": \"Duração\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Séries\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"Duração de {minValue}-{maxValue} minutos\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Serviços de Streaming\",\n  \"components.Discover.FilterSlideover.studio\": \"Estúdio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Avaliação de Usuários do TMDB\",\n  \"components.Discover.FilterSlideover.to\": \"Até\",\n  \"components.Discover.tmdbmoviekeyword\": \"Palavra-chave de Filme no TMDB\",\n  \"components.Discover.tmdbnetwork\": \"Emissora no TMDB\",\n  \"components.Discover.tvgenres\": \"Gêneros de Séries\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Mídia adicionadas à sua <PlexWatchlistSupportLink>Lista Para Assistir do Plex</PlexWatchlistSupportLink> aparecerão aqui.\",\n  \"components.Discover.moviegenres\": \"Gêneros de Filmes\",\n  \"components.Discover.stopediting\": \"Cancelar Edição\",\n  \"components.Discover.tmdbmoviegenre\": \"Gênero de Filmes no TMDB\",\n  \"components.RequestModal.requestseriestitle\": \"Solicitar Série\",\n  \"components.RequestModal.requestcollectiontitle\": \"Solicitar Coleção\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Solicitar Filme em 4K\",\n  \"components.RequestModal.requestseries4ktitle\": \"Solicitar Série em 4K\",\n  \"components.Selector.searchGenres\": \"Selecione os gêneros…\",\n  \"components.Selector.showless\": \"Mostrar Menos\",\n  \"components.Selector.showmore\": \"Mostrar Mais\",\n  \"components.Selector.searchKeywords\": \"Pesquisar palavras-chave…\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Defina configurações globais e padrões para o Seerr.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Nova chave de API gerada com sucesso!\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Limpeza de Cache de Imagens\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Título da Aplicação\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL da Aplicação\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Habilitar Cache de Imagens\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Ocultar Títulos Disponíveis\",\n  \"components.Settings.SettingsMain.locale\": \"Idioma da Interface\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Idioma de Exploração\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrar conteúdo pelo idioma original\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Permitir Solicitações Parciais de Séries\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Algo deu errado ao gerar a nova chave de API.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Configurações salvas com sucesso!\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"A URL não deve terminar com uma barra\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Você deve prover um título para a aplicação\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Você deve prover uma URL válida\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Espisódio} other {# Episódios}}\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Deslizador editado e configurações customizadas de procura salvas.\",\n  \"components.Discover.resetwarning\": \"Todos os deslizadores resetados para os valores padrões. Isso também deletará todos os deslizadores personalizados!\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Nós fomos incapazes de encontrar um série correspondente à serie solicitada.\",\n  \"components.Discover.resetsuccess\": \"As configurações de descoberta personalizadas foram resetadas com sucesso.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Novo deslizador criado e configurações de procura customizada salvas.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Você deve informar um valor.\",\n  \"components.Discover.resetfailed\": \"Algo deu errado com o reset das configurações personalizadas de descoberta.\",\n  \"components.Discover.updatefailed\": \"Algo deu errado com a mudança das configurações de descoberta personalizadas.\",\n  \"components.Discover.updatesuccess\": \"Configurações personalizadas de descoberta atualizadas.\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Quando ativado nas configurações, o Seer irá obter e guardar imagens de fontes externas pré configuradas. As imagens guardadas são salvas na sua pasta de configuração. Você pode encontrar os arquivos em <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"A cada {jobScheduleSeconds, plural, one {segundo} other {{jobScheduleSeconds} segundos}}\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Sincronização de Disponibilidade de Mídia\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Serviços de Streaming de Filmes do TMDB TV\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Serviços de Streaming de Filmes do TMDB\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Qtd de Votos de Usuários TMDB\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Qtd the votos entre {minValue} e {maxValue}\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Adicione automaticamente uma tag extra com o ID de usuário e o nome de exibição do solicitante\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Um endereço de e-mail é necessário.\",\n  \"components.Login.credentialerror\": \"O nome de usuário ou senha está incorreto.\",\n  \"components.Login.description\": \"Já que é sua primeira vez entrando em {applicationName}, você precisa adicionar um e-mail válido.\",\n  \"components.Login.initialsignin\": \"Conectar\",\n  \"components.Login.initialsigningin\": \"Conectando…\",\n  \"components.Login.save\": \"Adicionar\",\n  \"components.Login.saving\": \"Adicionando…\",\n  \"components.Login.signinwithjellyfin\": \"Use sua conta de {mediaServerName}\",\n  \"components.Login.title\": \"Adicionar E-Mail\",\n  \"components.Login.username\": \"Nome de usuário\",\n  \"components.Login.validationEmailFormat\": \"E-mail inválido\",\n  \"components.Login.validationEmailRequired\": \"Você precisa providenciar um e-mail\",\n  \"components.Login.validationemailformat\": \"E-mail válido necessário\",\n  \"components.Login.validationhostformat\": \"URL válido necessário\",\n  \"components.Login.validationusernamerequired\": \"Nome de usuário necessário\",\n  \"components.ManageSlideOver.removearr\": \"Remover de {arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"Remover de {arr} 4K\",\n  \"components.MovieDetails.downloadstatus\": \"Status de download\",\n  \"components.MovieDetails.imdbuserscore\": \"Avaliação de usuário no IMDB - votos: {formattedCount}\",\n  \"components.MovieDetails.openradarr\": \"Abrir filme no Radarr\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Som de notificação\",\n  \"components.Login.emailtooltip\": \"Endereço não precisa ser associado à sua instância de {mediaServerName}.\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Endereço de e-mail inválido.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Uma senha é necessária.\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Padrão do dispositivo\",\n  \"components.Login.validationhostrequired\": \"URL de {mediaServerName} necessário\",\n  \"components.MovieDetails.openradarr4k\": \"Abrir filme em Radarr 4K\",\n  \"components.MovieDetails.play\": \"Reproduzir em {mediaServerName}\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Isto irá remover este {mediaType} de {arr}, incluindo todos os arquivos.\",\n  \"components.MovieDetails.play4k\": \"Reproduzir em 4K em {mediaServerName}\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"A URL base deve iniciar com uma barra\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Requer o email do usuário\",\n  \"components.Login.invalidurlerror\": \"Não foi possível conectar-se ao servidor {mediaServerName}.\",\n  \"components.MovieDetails.removefromwatchlist\": \"Remover da Lista para Assistir\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"As bibliotecas {mediaServerName} procuram por títulos. Clique no botão abaixo se nenhuma biblioteca estiver listada.\",\n  \"components.UserList.importfromJellyfinerror\": \"Algo deu errado durante a importação de usuários {mediaServerName}.\",\n  \"components.Login.back\": \"Voltar\",\n  \"components.Selector.ended\": \"Finalizada\",\n  \"components.Login.enablessl\": \"Usar SSL\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> Removido da lista para assistir com sucesso!\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Opcionalmente, configure os endpoints internos e externos do seu servidor {mediaServerName}. Na maioria dos casos, o URL externo é diferente do URL interno. Uma URL de redefinição de senha personalizado também pode ser definido para o login {mediaServerName}, caso você queira redirecionar para uma página de redefinição de senha diferente. Você também pode alterar a chave de API do Jellyfin, que foi gerada automaticamente anteriormente.\",\n  \"components.UserList.newJellyfinsigninenabled\": \"A configuração <strong>Ativar novo login {mediaServerName}</strong> está ativada no momento. Os usuários do {mediaServerName} com acesso a biblioteca não precisam ser importados para fazer login.\",\n  \"components.TitleCard.addToWatchList\": \"Adicionar a lista para assistir\",\n  \"components.Login.port\": \"Porta\",\n  \"components.Login.servertype\": \"Tipo de Servidor\",\n  \"components.Login.validationPortRequired\": \"Você deve fornecer um número de porta válido\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"A URL base não deve terminar com uma barra\",\n  \"components.Login.validationUrlTrailingSlash\": \"A URL não deve terminar com uma barra\",\n  \"components.Login.validationservertyperequired\": \"Por favor, selecione um tipo de servidor\",\n  \"components.MovieDetails.addtowatchlist\": \"Adicionar a Lista para Assistir\",\n  \"components.MovieDetails.watchlistError\": \"Algo deu errado, Por favor, tente novamente.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> adicionado a lista para assistir com sucesso!\",\n  \"components.RequestList.RequestItem.profileName\": \"Perfil\",\n  \"components.Selector.canceled\": \"Cancelado\",\n  \"components.Selector.inProduction\": \"Em Produção\",\n  \"components.Selector.pilot\": \"Piloto\",\n  \"components.Selector.planned\": \"Planejada\",\n  \"components.Selector.returningSeries\": \"Séries Retornando\",\n  \"components.Selector.searchStatus\": \"Selecione status...\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Escaneamento completa da biblioteca Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Escanear adicionados recentemente ao Jellyfin\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Adiciona automaticamente uma tag extra com o ID de usuário e o nome de exibição do solicitante\",\n  \"components.Settings.invalidurlerror\": \"Não foi possível conectar-se ao servidor {mediaServerName}.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"URL do Esqueci minha senha\",\n  \"components.Settings.jellyfinSettings\": \"Ajustes do {mediaServerName}\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Algo deu errado ao salvar as configurações de {mediaServerName}.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"As configurações de {mediaServerName} foram salvas com sucesso!\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Não há suporte para autenticação personalizada com Agrupamento Automático de Bibliotecas\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Algo deu errado durante a sincronização das bibliotecas\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Não foram encontradas bibliotecas\",\n  \"components.Settings.jellyfinlibraries\": \"Bibliotecas {mediaServerName}\",\n  \"components.Settings.jellyfinsettings\": \"Ajustes do {mediaServerName}\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Defina as configurações do seu servidor {mediaServerName}. {mediaServerName} examina suas bibliotecas {mediaServerName} para ver qual conteúdo está disponível.\",\n  \"components.Settings.saving\": \"Salvando…\",\n  \"components.Settings.syncJellyfin\": \"Sincronizar Bibliotecas\",\n  \"components.Settings.syncing\": \"Sincronizando\",\n  \"components.Setup.back\": \"Voltar\",\n  \"components.Setup.servertype\": \"Selecione o tipo de servidor\",\n  \"components.Setup.signin\": \"Entrar\",\n  \"components.Setup.signinWithJellyfin\": \"Insira seus dados Jellyfin\",\n  \"components.Setup.signinWithEmby\": \"Insira seus dados Emby\",\n  \"components.Setup.signinWithPlex\": \"Insira seus dados Plex\",\n  \"components.Setup.subtitle\": \"Comece escolhendo seu servidor de mídia\",\n  \"components.TitleCard.watchlistCancel\": \"lista para assistir para <strong>{title}</strong> cancelada.\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> removido da lista para assistir com sucesso!\",\n  \"components.TitleCard.watchlistError\": \"Algo deu errado, tente novamente.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> adicionado a lista para assistir com sucesso!\",\n  \"components.TvDetails.addtowatchlist\": \"Adicionar a lista para assistir\",\n  \"components.TvDetails.play\": \"Reproduzir em {mediaServerName}\",\n  \"components.TvDetails.play4k\": \"Reproduzir 4K em {mediaServerName}\",\n  \"components.TvDetails.removefromwatchlist\": \"Remover da lista para assistir\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> removido da lista para assistir com sucesso!\",\n  \"components.TvDetails.watchlistError\": \"Algo deu errado, tente novamente.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> adicionado a lista para assistir com sucesso!\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} importados com sucesso!\",\n  \"components.UserList.importfromJellyfin\": \"Importar usuários {mediaServerName}\",\n  \"components.UserList.importfrommediaserver\": \"Importar usuários {mediaServerName}\",\n  \"components.UserList.mediaServerUser\": \"Usuário {mediaServerName}\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Não há usuários {mediaServerName} para importar.\",\n  \"components.UserList.username\": \"Nome de Usuário\",\n  \"components.UserList.validationUsername\": \"Você precisa fornecer um nome de usuário\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Usuário {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Salvar Alterações\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Salvando…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Email válido necessário\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Email necessário\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Dispositivo Padrão\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Som de Notificação\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalmente, isso só é executado uma vez a cada 24 horas. O Seerr verificará os recentemente adicionados do {mediaServerName} de forma mais agressiva. Se esta for sua primeira vez configurando o Seerr, recomenda-se uma verificação manual completa da biblioteca uma única vez!\",\n  \"components.Settings.manualscanJellyfin\": \"Escaneamento Manual da Biblioteca\",\n  \"components.Settings.save\": \"Salvar Alterações\",\n  \"components.UserProfile.localWatchlist\": \"Lista para Assistir de {username}\",\n  \"i18n.collection\": \"Coleção\",\n  \"components.Login.adminerror\": \"Você deve usar uma conta de administrador para fazer login.\",\n  \"components.Discover.FilterSlideover.certification\": \"Classificação Indicativa\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Excluir palavra-chave\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Próximas séries\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Descrição do Problema\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.loginwithapp\": \"Conecte-se com {appName}\",\n  \"components.Login.noadminerror\": \"Nenhum usuário administrador encontrado no servidor.\",\n  \"components.Login.orsigninwith\": \"Ou conecte-se com\",\n  \"components.Login.urlBase\": \"URL Base\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Selecione um provedor de metadados\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.RequestList.RequestItem.removearr\": \"Remover de {arr}\",\n  \"components.RequestList.sortDirection\": \"Alternar Direção da Ordenação\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Erro ao carregar as classificações indicativas\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Nota máxima\",\n  \"components.Selector.CertificationSelector.minRating\": \"Nota mínima\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Sem opções disponíveis\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Selecione a classificação indicativa\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Selecione um país\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Comece a escrever para pesquisar.\",\n  \"components.Selector.searchUsers\": \"Selecionar usuários…\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Prioridade\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Você deve definir um número da prioridade\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Habilitar agente\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Inserir Poster\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Não foi possível salvar as configurações de notificação Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Configuração de notificação Ntfy salva com sucesso!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Senha\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Falha ao enviar notificação de teste via Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Enviando notificação de teste via Ntfy…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Notificação de teste via Ntfy enviada!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Token de autenticação\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Tópico\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"URL raiz do servidor\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Nome do usuário\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Nome do usuário + Senha de autenticação\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Você deve definir um tópico\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Você deve definir uma URL válida\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Você deve selecionar pelo menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Inserir Poster\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Inserir Poster\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Suporte a variáveis de URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"As variáveis disponíveis estão documentadas na seção de variáveis do modelo de webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"O URL de notificação de teste está definido como {testUrl} em vez do URL atual do webhook.\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Inserir Poster\",\n  \"components.Settings.Notifications.embedPoster\": \"Inserir Poster\",\n  \"components.Settings.Notifications.messageThreadId\": \"Thread/ID do Tópico\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Se o seu grupo de tópicos estiver ativo, você pode especificar o Thread/ID do Tópico aqui\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"O Thread/ID do Tópico deve ser um número inteiro positivo\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Você deve fornecer um Role ID do Discord válido\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Role ID da notificação\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"O role ID a ser mencionado na mensagem do webhook. Deixe em branco para desativar as menções\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Condições\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Especifica as condições antes de aplicar as alterações de parâmetros. Cada campo deve ser validado para que as regras sejam aplicadas (operação AND). Um campo é considerado verificado se alguma de suas propriedades corresponder (operação OR).\",\n  \"components.Settings.OverrideRuleModal.create\": \"Criar regra\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Nova regra de sobreposição\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Editar regra de sobreposição\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Gêneros\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Palavras-chave\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Linguagens\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Sem tags.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Perfil de Qualidade\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Pasta Raiz\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Regra de sobreposição criada com sucesso!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Regra de sobreposição atualizada com sucesso!\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Selecione um perfil de qualidade\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Selecione a pasta raiz\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Selecione o serviço\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Selecione as tags\",\n  \"components.Settings.OverrideRuleModal.service\": \"Serviço\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Aplicar essa regra no serviço selecionado.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Configurações\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Especifica quais configurações serão alteradas quando as condições acima forem atendidas.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleModal.users\": \"Usuários\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Condições\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Gêneros\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Palavras-chave\",\n  \"components.Settings.OverrideRuleTile.language\": \"Linguagem\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Perfil de Qualidade\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Pasta Raiz\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Configurações\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleTile.users\": \"Usuários\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Tag Solicitada\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNS Cache\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"O Seerr armazena em cache as pesquisas de DNS para otimizar o desempenho e evitar chamadas de API desnecessárias.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Estatísticas globais do cache DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Essas estatísticas são agregadas em todas as entradas do cache DNS.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Endereço Ativo\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Idade\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"cache dns {hostname} limpo.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Acertos\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Falhas\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Nome do Host\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Cada {jobScheduleDays, plural, one {day} other {{jobScheduleDays} days}}\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Falhas\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Limpar cache do DNS\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Taxa de acertos\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Acertos\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4 Fallbacks\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Falhas\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Token de atualização do Plex\",\n  \"components.Settings.SettingsJobsCache.size\": \"Tamanho\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Avatares dos usuários\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"Chave da API copiada para a área de transferência.\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Descubra a região\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filtro de conteúdo por região disponível\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Permitir pedidos de episódios especias\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Ocultar conteúdo disponível nas páginas de descoberta, mas não nos resultados de pesquisa\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Região de Streaming\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Mostrar sites de streaming por região disponível\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Você deve fornecer uma URL válida\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"A URL não deve terminar com uma barra\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube URL\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"URL base para vídeos do YouTube caso seja utilizada uma instância do YouTube auto-hospedada.\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Habilitar Proteção CSRF\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"NÃO ative esta configuração a menos que você entenda o que está fazendo!\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Defina o acesso à API externa como somente leitura (requer HTTPS)\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNS Cache\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"TTL máximo do cache DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"TTL máximo do cache DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"NÃO habilite esta opção se estiver enfrentando problemas com as pesquisas de DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Habilite o armazenamento em cache de pesquisas de DNS para otimizar o desempenho e evitar chamadas de API desnecessárias\",\n  \"components.Settings.SettingsNetwork.docs\": \"documentação\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Forçar a resolução de IPv4 primeiro\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Forçar o Seerr a resolver primeiro os endereços IPv4 em vez dos IPv6\",\n  \"components.Settings.SettingsNetwork.network\": \"Rede\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Os parâmetros de rede do seu contêiner/sistema devem ser usados em vez dessas configurações. Consulte a {docs} para obter mais informações.\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Configurações de Rede\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Configure as definições de rede para a sua instância do Seerr.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Endereços ignorados pelo proxy\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Use ',' como separador e '*.' como caractere curinga para subdomínios\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Ignorar proxy para endereços locais\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) Proxy\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Nome do host do proxy\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Senha do Proxy\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Porta do Proxy\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Use SSL para proxy\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Nome do Proxy\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Ocorreu um erro ao salvar as configurações.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Configurações salvas com sucesso!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Habilitar suporte a proxy\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Permitir que o Seerr registre corretamente os endereços IP dos clientes por trás de um proxy\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Você deve fornecer uma porta válida\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Sobre o Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Fazer uma contribuição\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Suporte Seerr\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Você deve fornecer um TTL máximo válido\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Você deve fornecer um TTL mínimo válido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\",\n  \"component.BlocklistBlock.blocklistdate\": \"Data de bloqueio\",\n  \"component.BlocklistBlock.blocklistedby\": \"Bloqueado por\",\n  \"component.BlocklistModal.blocklisting\": \"Lista de bloqueio\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> não está na lista de bloqueio.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Gerenciar mídia bloqueada.\",\n  \"components.Blocklist.blocklistdate\": \"data\",\n  \"components.Blocklist.blocklistedby\": \"{date} por {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Configurações da Lista de Bloqueio\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Tags Bloqueadas\",\n  \"components.Blocklist.filterManual\": \"Manual\",\n  \"components.Blocklist.mediaName\": \"Nome\",\n  \"components.Blocklist.mediaTmdbId\": \"ID do tmdb\",\n  \"components.Blocklist.mediaType\": \"Tipo\",\n  \"components.Blocklist.showAllBlocklisted\": \"Mostrar Todas as Mídias Bloqueadas\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Não foi possível conectar-se a {services}. Algumas informações podem estar indisponíveis.\",\n  \"components.Layout.Sidebar.blocklist\": \"Lista de Bloqueio\",\n  \"components.PermissionEdit.blocklistedItems\": \"Bloquear mídia.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Concede permissão para a lista de mídia bloqueada.\",\n  \"components.PermissionEdit.manageblocklist\": \"Gerenciar Lista de Bloqueio\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Conceder permissão para gerenciar lista de mídia bloqueada.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Ver lista de bloqueio.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Concede permissão para visualizar a lista de mídia bloqueada.\",\n  \"components.RequestList.unableToConnect\": \"Não foi possível conectar-se a {services}. Algumas informações podem estar indisponíveis.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Nenhuma consulta DNS foi armazenada em cache ainda.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Processar tags bloqueadas\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Conteúdo bloqueado com tags\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Limite de conteúdo bloqueado por tag\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"A tarefa \\\"Processar Tags Bloqueadas\\\" bloqueará essa quantidade de páginas em cada classificação. Números maiores criarão uma lista de bloqueio mais precisa, mas usarão mais espaço.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Adicione automaticamente conteúdo com tags à lista de bloqueio usando a tarefa \\\"Processar Tags da Bloqueadas\\\"\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Ocultar itens bloqueados\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Ocultar itens bloqueados das páginas de descoberta para todos os usuários com a permissão \\\"Gerenciar lista de bloqueio\\\"\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"Tempo limite da solicitação da API\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Tempo máximo (em segundos) para aguardar respostas de serviços externos como Radarr/Sonarr. Defina como 0 para nenhum tempo limite.\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Envia TODAS as solicitações HTTP/HTTPS de saída por meio de um servidor proxy (host/porta). NÃO habilita HTTPS, SSL ou configuração de certificado.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Você deve fornecer um valor de tempo limite válido\"\n}\n"
  },
  {
    "path": "src/i18n/locale/pt_PT.json",
    "content": "{\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Testar ligação para carregar as pastas raiz\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Testar ligação para carregar perfis de qualidade\",\n  \"components.Settings.RadarrModal.ssl\": \"Usar SSL\",\n  \"components.Settings.SonarrModal.servername\": \"Nome do Servidor\",\n  \"components.Settings.SonarrModal.server4k\": \"Servidor 4K\",\n  \"components.Settings.RadarrModal.server4k\": \"Servidor 4K\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Selecione a pasta raiz\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Selecione a pasta raiz\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Selecione o perfil de qualidade\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Selecione o perfil de qualidade\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Selecione disponibilidade mínima\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Pasta Raiz\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Pasta Raiz\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Perfil de Qualidade\",\n  \"components.Settings.RadarrModal.port\": \"Porta\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Disponibilidade Mínima\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"A carregar Pastas Raiz…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"A carregar Perfis de Qualidade…\",\n  \"components.Settings.RadarrModal.hostname\": \"Nome do hospedeiro ou endereço IP\",\n  \"components.Settings.RadarrModal.servername\": \"Nome do Servidor\",\n  \"components.Settings.RadarrModal.editradarr\": \"Modificar Servidor Radarr\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Servidor Predefinido\",\n  \"components.Settings.RadarrModal.createradarr\": \"Adicionar Novo Servidor Radarr\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Base do URL\",\n  \"components.Settings.RadarrModal.apiKey\": \"Chave API\",\n  \"components.Settings.RadarrModal.add\": \"Adicionar Servidor\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Deve fornecer um número de porta válido\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Deve fornecer um nome de hospedeiro ou endereço IP válido\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Deve fornecer um ID de chat válido\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Deve fornecer um token de autorização de bot\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Definições de notificação Telegram gravadas com sucesso!\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Falha ao gravar as definições de notificação Telegram.\",\n  \"components.Settings.Notifications.smtpPort\": \"Porta SMTP\",\n  \"components.Settings.Notifications.smtpHost\": \"Servidor SMTP\",\n  \"components.Settings.Notifications.senderName\": \"Nome do Remetente\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Definições de notificação e-mail gravadas com sucesso!\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Definições de notificação Discord gravadas com sucesso!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Falha ao gravar das definições de notificação Discord.\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Falha ao gravar das definições de notificação e-mail.\",\n  \"components.Settings.Notifications.emailsender\": \"Endereço do remetente\",\n  \"components.Settings.Notifications.chatId\": \"ID do Chat\",\n  \"components.Settings.Notifications.botAPI\": \"Token de Autorização do Bot\",\n  \"components.Settings.Notifications.authUser\": \"Utilizador SMTP\",\n  \"components.Settings.Notifications.authPass\": \"Palavra-passe SMTP\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Permitir Certificados Auto-Assinados\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Definições de notificação Webhook gravadas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Falha ao gravar as definições de notificação Webhook.\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Deve fornecer um conteúdo JSON valido\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Ajuda Com Modelos de Variáveis\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"Conteúdo JSON reiniciado com sucesso!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Restaurar Predefinição\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Conteúdo JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Cabeçalho de Autorização\",\n  \"components.Settings.Notifications.agentenabled\": \"Ativar Agente\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Ativar Agente\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL de Webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Definições de notificação Slack gravadas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Falha ao gravas as definições de notificação do Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Ativar Agente\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Tem de fornecer um utilizador válido ou uma chave de grupo\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Deve fornecer um token de aplicação válido\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Chave de Utilizador ou Grupo\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Definições de notificação Pushover gravadas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Falha ao gravar as definições de notificação Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Ativar Agente\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token de Aplicação API\",\n  \"components.Search.searchresults\": \"Resultados da Pesquisa\",\n  \"components.RequestModal.selectseason\": \"Selecionar Semporada(s)\",\n  \"components.RequestModal.seasonnumber\": \"Temporada {number}\",\n  \"components.RequestModal.season\": \"Temporada\",\n  \"components.RequestModal.requestseasons\": \"Pedir {seasonCount} {seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestModal.requestfrom\": \"O peido de {username} está com aprovação pendente.\",\n  \"components.RequestModal.requestedited\": \"Pedido para <strong>{title}</strong> modificado com sucesso!\",\n  \"components.RequestModal.requestcancelled\": \"Pedido para <strong>{title}</strong> cancelado.\",\n  \"components.RequestModal.requestadmin\": \"Este pedido será aprovado automaticamente.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> pedido com sucesso!\",\n  \"components.RequestModal.requestCancel\": \"Pedido para <strong>{title}</strong> cancelado.\",\n  \"components.RequestModal.pendingrequest\": \"Solicitação Pendente\",\n  \"components.RequestModal.pending4krequest\": \"Solicitação em 4K Pendente\",\n  \"components.RequestModal.numberofepisodes\": \"# de Episódios\",\n  \"components.RequestModal.errorediting\": \"Ocorreu um erro durante a edição do pedido.\",\n  \"components.RequestModal.cancel\": \"Cancelar Pedido\",\n  \"components.RequestModal.autoapproval\": \"Aprovação Automática\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Pasta Raiz\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Perfil de Qualidade\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Servidor de Destino\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Predefinição)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Esta série é um anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avançado\",\n  \"components.RequestList.sortModified\": \"Última Alteração\",\n  \"components.RequestList.sortAdded\": \"Data do Pedido\",\n  \"components.RequestList.showallrequests\": \"Mostrar Todos os Pedidos\",\n  \"components.RequestList.requests\": \"Pedidos\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestList.RequestItem.failedretry\": \"Ocorreu um erro ao voltar a tentar o pedido.\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestButton.viewrequest4k\": \"Ver Pedido 4K\",\n  \"components.RequestButton.viewrequest\": \"Ver Pedido\",\n  \"components.RequestButton.requestmore4k\": \"Pedir Mais em 4K\",\n  \"components.RequestButton.requestmore\": \"Pedir Mais\",\n  \"components.RequestButton.declinerequests\": \"Rejeitar {requestCount, plural, one {pedido} other {{requestCount} pedidos}}\",\n  \"components.RequestButton.declinerequest4k\": \"Rejeitar Pedido 4K\",\n  \"components.RequestButton.declinerequest\": \"Rejeitar Pedido\",\n  \"components.RequestButton.decline4krequests\": \"Rejeitar {requestCount, plural, one {pedido 4K} other {{requestCount} pedidos 4K}}\",\n  \"components.RequestButton.approverequests\": \"Aprovar {requestCount, plural, one {pedido} other {{requestCount} pedidos}}\",\n  \"components.RequestButton.approverequest4k\": \"Aprovar Pedido 4K\",\n  \"components.RequestButton.approverequest\": \"Aprovar Pedido\",\n  \"components.RequestButton.approve4krequests\": \"Aprovar {requestCount, plural, one {pedido 4K} other {{requestCount} pedidos 4K}}\",\n  \"components.RequestBlock.server\": \"Servidor de Destino\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.RequestBlock.rootfolder\": \"Pasta Raiz\",\n  \"components.RequestBlock.requestoverrides\": \"Alterações de Pedidos\",\n  \"components.RequestBlock.profilechanged\": \"Perfil de Qualidade\",\n  \"components.PersonDetails.crewmember\": \"Equipa Técnica\",\n  \"components.PersonDetails.ascharacter\": \"como {character}\",\n  \"components.PersonDetails.appearsin\": \"Presenças\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Enviar notificações quando os pedidos de multimédia não forem adicionados ao Radarr ou Sonarr.\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Enviar notificações quando os utilizadores enviam novos pedidos de multimédia que requerem aprovação.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Multimédia Pedida\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Multimédia Falhou\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Envia uma notificação quando um pedido de multimédia é rejeitado.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Multimédia Rejeitada\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Enviar notificações quando os pedidos da multimédia ficarem disponíveis.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Multimédia Disponível\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Enviar notificações quando os pedidos de multimédia são aprovados manualmente.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Multimédia Aprovada\",\n  \"components.MovieDetails.watchtrailer\": \"Ver Trailer\",\n  \"components.MovieDetails.viewfullcrew\": \"Ver Equipa Técnica Completa\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Estúdio} other {Estúdios}}\",\n  \"components.MovieDetails.similar\": \"Títulos Similares\",\n  \"components.MovieDetails.runtime\": \"{minutes} minutos\",\n  \"components.MovieDetails.revenue\": \"Receita\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Data} other {Datas}} de Estreia\",\n  \"components.MovieDetails.recommendations\": \"Recomendações\",\n  \"components.MovieDetails.overviewunavailable\": \"Sinopse indisponível.\",\n  \"components.MovieDetails.overview\": \"Sinopse\",\n  \"components.MovieDetails.originallanguage\": \"Idioma Original\",\n  \"components.MovieDetails.cast\": \"Elenco\",\n  \"components.MovieDetails.budget\": \"Orçamento\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Equipa Técnica Completa\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Elenco Completo\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Ver Mais\",\n  \"components.Login.validationpasswordrequired\": \"Deve fornecer uma palavra-passe\",\n  \"components.Login.validationemailrequired\": \"Deve fornecer um e-mail válido\",\n  \"components.Login.signinwithoverseerr\": \"Utilizar a sua conta {applicationTitle}\",\n  \"components.Login.loginerror\": \"Ocorreu um erro ao tentar iniciar a sessão.\",\n  \"components.Login.password\": \"Palavra-passe\",\n  \"components.Login.email\": \"Endereço E-mail\",\n  \"components.Layout.UserDropdown.signout\": \"Sair\",\n  \"components.Layout.Sidebar.users\": \"Utilizadores\",\n  \"components.Layout.Sidebar.settings\": \"Definições\",\n  \"components.Layout.Sidebar.requests\": \"Pedidos\",\n  \"components.Layout.Sidebar.dashboard\": \"Descobrir\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Pesquisar Filmes e Séries\",\n  \"components.Discover.upcomingmovies\": \"Filmes a Estrear\",\n  \"components.Discover.upcoming\": \"Filmes a Estrear\",\n  \"components.Discover.trending\": \"Tendências\",\n  \"components.Discover.recentrequests\": \"Pedidos Recentes\",\n  \"components.Discover.recentlyAdded\": \"Adicionado Recentemente\",\n  \"components.Discover.populartv\": \"Séries Populares\",\n  \"components.Discover.popularmovies\": \"Filmes Populares\",\n  \"components.CollectionDetails.requestcollection\": \"Pedir Coleção\",\n  \"components.CollectionDetails.overview\": \"Sinopse\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Filmes\",\n  \"pages.returnHome\": \"Voltar Para Página Inicial\",\n  \"pages.oops\": \"Ups\",\n  \"i18n.tvshows\": \"Séries\",\n  \"i18n.retry\": \"Tentar Novamente\",\n  \"i18n.requested\": \"Pedido\",\n  \"i18n.processing\": \"A Processar\",\n  \"i18n.partiallyavailable\": \"Parcialmente Disponível\",\n  \"i18n.movies\": \"Filmes\",\n  \"i18n.failed\": \"Falha\",\n  \"i18n.experimental\": \"Experimental\",\n  \"i18n.deleting\": \"A eliminar…\",\n  \"i18n.declined\": \"Rejeitado\",\n  \"i18n.close\": \"Fechar\",\n  \"i18n.cancel\": \"Cancelar\",\n  \"i18n.approved\": \"Aprovada\",\n  \"i18n.approve\": \"Aprovar\",\n  \"components.UserList.validationpasswordminchars\": \"Palavra-passe muito curta; necessário ter no mínimo 8 caracteres\",\n  \"components.UserList.userlist\": \"Lista de Utilizadores\",\n  \"components.UserList.userdeleteerror\": \"Ocorreu um erro ao eliminar o utilizador.\",\n  \"components.UserList.userdeleted\": \"Utilizador eliminado com sucesso!\",\n  \"components.UserList.usercreatedsuccess\": \"Utilizador criado com sucesso!\",\n  \"components.UserList.usercreatedfailed\": \"Ocorreu um erro ao criar o utilizador.\",\n  \"components.UserList.user\": \"Utilizador\",\n  \"components.UserList.totalrequests\": \"Pedidos\",\n  \"components.UserList.role\": \"Função\",\n  \"components.UserList.plexuser\": \"Utilizador Plex\",\n  \"components.UserList.passwordinfodescription\": \"Configurar um URL de aplicação e ativar as notificações por e-mail para permitir a geração automática de palavra-passe.\",\n  \"components.UserList.localuser\": \"Utilizador Local\",\n  \"components.UserList.importfromplexerror\": \"Ocorreu um erro ao importar utilizadores do Plex.\",\n  \"components.UserList.importfrommediaserver\": \"Importar Utilizadores do {mediaServerName}\",\n  \"components.UserList.importfromplex\": \"Importar Utilizadores do Plex\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> {userCount, plural, one {utilizador Plex importado} other {utilizadores Plex importados}} com sucesso!\",\n  \"components.UserList.email\": \"Endereço de E-mail\",\n  \"components.UserList.deleteuser\": \"Apagar Utilizador\",\n  \"components.UserList.deleteconfirm\": \"Tem certeza que deseja apagar este utilizador? Todos os seus dados de pedidos serão removidos permanentemente.\",\n  \"components.UserList.creating\": \"A criar…\",\n  \"components.UserList.createlocaluser\": \"Criar Utilizador Local\",\n  \"components.Setup.welcome\": \"Bem-vindo ao Seerr\",\n  \"components.Setup.signinMessage\": \"Comece iniciando sessão com a sua conta Plex\",\n  \"components.Setup.finishing\": \"A finalizar…\",\n  \"components.Setup.finish\": \"Finalizar Configurações\",\n  \"components.Setup.continue\": \"Continuar\",\n  \"components.Setup.configureservices\": \"Configurar Serviços\",\n  \"components.Settings.startscan\": \"Iniciar Sincronização\",\n  \"components.Settings.sonarrsettings\": \"Definições do Sonarr\",\n  \"components.Settings.radarrsettings\": \"Definições Radarr\",\n  \"components.Settings.port\": \"Porta\",\n  \"components.Settings.plexsettingsDescription\": \"Configure as definições do seu servidor Plex. O Seerr analisa as suas bibliotecas Plex para determinar a disponibilidade de conteúdo.\",\n  \"components.Settings.plexlibraries\": \"Bibliotecas do Plex\",\n  \"components.Settings.plexsettings\": \"Definições do Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"As bibliotecas que o Seerr analisa para encontrar títulos. Configure e guarde as suas definições de ligação ao Plex, depois clique no botão abaixo se nenhuma biblioteca estiver listada.\",\n  \"components.Settings.notrunning\": \"Parado\",\n  \"components.Settings.notificationsettings\": \"Definições de Notificação\",\n  \"components.Settings.menuServices\": \"Serviços\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Notificações\",\n  \"components.Settings.menuLogs\": \"Registos\",\n  \"components.Settings.menuJobs\": \"Tarefas e Cache\",\n  \"components.Settings.menuAbout\": \"Sobre\",\n  \"components.Settings.manualscanDescription\": \"Normalmente, isto só será executado uma vez a cada 24 horas. O Seerr verificará os itens adicionados recentemente no seu servidor Plex de forma mais agressiva. Se for a primeira vez que está a configurar o Plex, recomenda-se uma análise completa e manual única das bibliotecas!\",\n  \"components.Settings.manualscan\": \"Sincronização Manual da Biblioteca\",\n  \"components.Settings.cancelscan\": \"Cancelar Sincronização\",\n  \"components.Settings.librariesRemaining\": \"Bibliotecas Restantes: {count}\",\n  \"components.Settings.hostname\": \"Nome do hospedeiro ou endereço IP\",\n  \"components.Settings.menuGeneralSettings\": \"Geral\",\n  \"i18n.edit\": \"Modificar\",\n  \"components.Settings.deleteserverconfirm\": \"Tem certeza que deseja eliminar este servidor?\",\n  \"i18n.delete\": \"Eliminar\",\n  \"components.Settings.default4k\": \"Predefinição 4K\",\n  \"components.Settings.default\": \"Predefinição\",\n  \"components.Settings.currentlibrary\": \"Biblioteca Atual: {name}\",\n  \"components.Settings.addsonarr\": \"Adicionar Servidor Sonarr\",\n  \"components.Settings.address\": \"Endereço\",\n  \"components.Settings.addradarr\": \"Adicionar Servidor Radarr\",\n  \"components.Settings.activeProfile\": \"Perfil Ativo\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Deve selecionar uma pasta raiz\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Deve selecionar um perfil de qualidade\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Deve fornecer o nome do servidor\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Deve fornecer um nome de hospedeiro ou endereço IP\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Deve fornecer um nome de hospedeiro ou endereço IP\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Deve fornecer um número de porta válido\",\n  \"components.Settings.validationPortRequired\": \"Deve fornecer um número de porta válido\",\n  \"components.Settings.validationHostnameRequired\": \"Deve fornecer um nome de hospedeiro ou endereço IP válido\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Deve fornecer uma chave API\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Testar ligação para carregar as pastas raiz\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Testar ligação para carregar perfis de qualidade\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.SonarrModal.ssl\": \"Usar SSL\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Temporadas Em Pastas\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Perfil de Qualidade\",\n  \"components.Settings.SonarrModal.port\": \"Porta\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"A carregar pastas raiz…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"A carregar Perfis de Qualidade…\",\n  \"components.Settings.SonarrModal.hostname\": \"Nome do hospedeiro ou endereço IP\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Modificar Servidor Sonarr\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Servidor Predefinido\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Adicionar Novo Servidor Sonarr\",\n  \"components.Settings.SonarrModal.apiKey\": \"Chave API\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Deve fornecer uma chave API\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Base do URL\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Pasta Raiz de Anime\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Perfil de Qualidade Para Anime\",\n  \"components.Settings.SonarrModal.add\": \"Adicionar Servidor\",\n  \"components.Settings.SettingsAbout.version\": \"Versão\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Todos os Pedidos\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Total de Multimédia\",\n  \"components.Settings.SettingsAbout.timezone\": \"Fuso Horário\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Discussões no GitHub\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Obter Suporte\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentação\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Ver no GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Ver Mudanças\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Mudanças Nesta Versão\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Versões\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Os dados de versão estão atualmente indisponíveis.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Última Versão\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Versão Atual\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Deve selecionar uma pasta raiz\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Deve selecionar um perfil de qualidade\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Deve fornecer um número de porta válido\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Deve fornecer o nome do servidor\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Deve selecionar a disponibilidade mínima\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Ligação ao Radarr estabelecida com sucesso!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Falhar a ligar ao Radarr.\",\n  \"components.UserList.password\": \"Palavra-passe\",\n  \"components.UserList.created\": \"Criado\",\n  \"components.UserList.create\": \"Criar\",\n  \"components.UserList.autogeneratepassword\": \"Gerar Palavra-passe Automaticamente\",\n  \"i18n.request\": \"Pedir\",\n  \"components.UserList.admin\": \"Administrador\",\n  \"components.TvDetails.watchtrailer\": \"Ver Trailer\",\n  \"components.TvDetails.viewfullcrew\": \"Ver Equipa Técnica Completa\",\n  \"i18n.unavailable\": \"Indisponível\",\n  \"components.TvDetails.similar\": \"Séries Semelhantes\",\n  \"components.TvDetails.showtype\": \"Tipo de Série\",\n  \"components.TvDetails.recommendations\": \"Recomendações\",\n  \"i18n.pending\": \"Pendente\",\n  \"components.TvDetails.overviewunavailable\": \"Sinopse indisponível.\",\n  \"components.TvDetails.overview\": \"Sinopse\",\n  \"components.TvDetails.originallanguage\": \"Língua original\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Emissor} other {Emissores}}\",\n  \"components.TvDetails.firstAirDate\": \"Data da Estreia\",\n  \"i18n.decline\": \"Rejeitar\",\n  \"components.TvDetails.cast\": \"Elenco\",\n  \"i18n.available\": \"Disponível\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Equipa Técnica Completa da Série\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Elenco Completo da Série\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Login.signinwithplex\": \"Iniciar sessão com a sua conta Plex\",\n  \"components.RequestModal.requesterror\": \"Ocorreu um erro ao submeter o pedido.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Não conseguimos correlacionar a sua solicitação automaticamente. Por favor selecione a correspondência correta na lista abaixo.\",\n  \"components.Login.signinheader\": \"Iniciar sessão para continuar\",\n  \"components.Login.signingin\": \"A Iniciar Sessão…\",\n  \"components.Login.signin\": \"Iniciar Sessão\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Configurar e ativar agentes de notificação.\",\n  \"components.UserList.userssaved\": \"Permissões de utilizador gravadas com sucesso!\",\n  \"components.UserList.bulkedit\": \"Edição em Massa\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Lista de servidores Plex obtida com sucesso!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Falha ao recuperar a lista de servidores Plex.\",\n  \"components.Settings.toastPlexRefresh\": \"A obter lista de servidores do Plex…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Ligação ao Plex estabelecida com sucesso!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Falha ao ligar ao Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"A tentar ligar ao Plex…\",\n  \"components.Settings.settingUpPlexDescription\": \"Para configurar o Plex, pode inserir os detalhes manualmente ou selecionar um dos servidores disponíveis obtidos de <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Clique no botão à direita da lista de servidores disponíveis.\",\n  \"components.Settings.serverpresetRefreshing\": \"A obter servidores…\",\n  \"components.Settings.serverpresetManualMessage\": \"Configuração Manual\",\n  \"components.Settings.serverpresetLoad\": \"Clique no botão para carregar os servidores disponíveis\",\n  \"components.Settings.serverpreset\": \"Servidor\",\n  \"components.Settings.serverRemote\": \"remoto\",\n  \"components.Settings.serverLocal\": \"local\",\n  \"components.PermissionEdit.usersDescription\": \"Conceder permissão para gerir utilizadores Seerr. Os utilizadores com essa permissão não podem modificar os utilizadores ou conceder o privilégio de administrador.\",\n  \"components.PermissionEdit.users\": \"Gerir Utilizadores\",\n  \"components.PermissionEdit.requestDescription\": \"Conceder permissão para pedir multimédia não 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Conceder permissão para pedir séries em 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"Pedir Séries 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Conceder permissão para pedir filmes em 4K.\",\n  \"components.PermissionEdit.request4kMovies\": \"Pedir Filmes 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Conceder permissão para pedir multimédia 4K.\",\n  \"components.PermissionEdit.request4k\": \"Pedir 4K\",\n  \"components.PermissionEdit.request\": \"Pedir\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Conceder permissão para gerir pedidos Seerr. Todas os pedidos feitos por um utilizador com essa permissão serão aprovados automaticamente.\",\n  \"components.PermissionEdit.managerequests\": \"Gerir Pedidos\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Conceder aprovação automática para pedidos de séries não 4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Aprovar Séries Automaticamente\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Conceder aprovação automática para pedidos de filmes não 4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Aprovar Filmes Automaticamente\",\n  \"components.PermissionEdit.autoapprove\": \"Aprovar Automaticamente\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Conceder aprovação automática para todas os pedidos não 4K.\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Conceder permissão para fazer pedidos avançados.\",\n  \"components.PermissionEdit.advancedrequest\": \"Pedidos Avançados\",\n  \"components.PermissionEdit.adminDescription\": \"Acesso total de administrador. Ignora todas as outras verificações de permissão.\",\n  \"components.PermissionEdit.admin\": \"Administrador\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Ligação Sonarr estabelecida com sucesso!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Falha ao ligar ao Sonarr.\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Ativar Sincronização\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Ativar sincronização\",\n  \"components.Settings.SonarrModal.externalUrl\": \"URL Externa\",\n  \"components.Settings.RadarrModal.externalUrl\": \"URL Externa\",\n  \"components.MovieDetails.markavailable\": \"Marcar como Disponível\",\n  \"components.MovieDetails.mark4kavailable\": \"Marcar como Disponível em 4K\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Acertos\",\n  \"i18n.advanced\": \"Avançado\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Executar Agora\",\n  \"components.Settings.SettingsJobsCache.process\": \"Processo\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Próxima Execução\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tipo\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} iniciado(a).\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"O Seerr executa certas tarefas de manutenção como tarefas agendadas regularmente, mas também podem ser acionadas manualmente abaixo. Executar uma tarefa manualmente não irá alterar o seu agendamento.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Tarefas\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Nome da Tarefa\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} cancelado(a).\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Limpar Cache\",\n  \"components.Settings.SettingsJobsCache.command\": \"Comando\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Cancelar Tarefa\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Tamanho do Valor\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Nome do Cache\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Falhas\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Tamanho da Chave\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Chaves Totais\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Cache {cachename} limpo.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"O Seerr armazena em cache os pedidos a endpoints API externos para otimizar o desempenho e evitar chamadas API desnecessárias.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"components.UserList.users\": \"Utilizadores\",\n  \"components.Search.search\": \"Pesquisar\",\n  \"components.Setup.setup\": \"Configurar\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"A URL não deve terminar com uma barra final\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"A URL não deve terminar com uma barra final\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Deve fornecer um URL valido\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Deve fornecer um URL valido\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Pedir Como\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Conceder permissão para ver pedidos de outros utilizadores.\",\n  \"components.PermissionEdit.viewrequests\": \"Ver Pedidos\",\n  \"components.Discover.discover\": \"Descobrir\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"O ponto de montagem <code>{appDataPath}</code> não foi configurado corretamente . Todos dados serão perdidos quando o contentor parar ou reiniciar.\",\n  \"components.TvDetails.nextAirDate\": \"Data do próximo Episódio\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"URL Base não deve terminar com uma barra\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"URL Base deve iniciar com uma barra\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL Base não deve terminar com uma barra\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL Base deve iniciar com uma barra\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Deve fornecer um URL valido\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Deve fornecer um URL valido\",\n  \"components.Settings.Notifications.validationEmail\": \"Deve fornecer um e-mail válido\",\n  \"components.UserList.validationEmail\": \"E-mail obrigatório\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Deve fornecer uma palavra-passe\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Palavra-passe muito curta; necessário ter no mínimo 8 caracteres\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Palavras-passe devem corresponder\",\n  \"components.ResetPassword.validationemailrequired\": \"Deve fornecer um e-mail válido\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Palavra-passe reposta com sucesso!\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Um endereço para o recuperar palavra-passe será enviado ao endereço de e-mail fornecido se estiver associado a um utilizador válido.\",\n  \"components.ResetPassword.password\": \"Palavra-passe\",\n  \"components.ResetPassword.gobacklogin\": \"Voltar a Página de Inicio de Sessão\",\n  \"components.ResetPassword.resetpassword\": \"Repor a sua Palavra-passe\",\n  \"components.ResetPassword.emailresetlink\": \"Link de Recuperação por E-mail\",\n  \"components.ResetPassword.email\": \"Endereço E-mail\",\n  \"components.ResetPassword.confirmpassword\": \"Confirmar Palavra-passe\",\n  \"components.Login.forgotpassword\": \"Esqueceu a Palavra-passe?\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Deve selecionar um perfil de idioma\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Testar ligação para carregar perfis de idioma\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Selecione um perfil de Idioma\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"A carregar perfis de Idioma…\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Perfil de Idioma de Anime\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Perfil de Idioma\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Perfil de Idioma\",\n  \"components.UserList.sortRequests\": \"Número de Pedidos\",\n  \"components.UserList.sortDisplayName\": \"Nome de Exibição\",\n  \"components.UserList.sortCreated\": \"Data de Criação\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Enviar notificações sem som\",\n  \"components.Settings.Notifications.sendSilently\": \"Enviar Silenciosamente\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Conceder aprovação automática para pedidos de séries 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Aprovar Séries 4K Automaticamente\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Conceder aprovação automática para pedidos de filmes 4K.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Aprovar Filmes 4K Automaticamente\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Conceder aprovação automática para todas os pedidos 4K.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Aprovar 4K Automaticamente\",\n  \"components.UserProfile.recentrequests\": \"Pedidos Recentes\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Permissões\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notificações\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Geral\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Palavra-passe\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Permissões gravadas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Ocorreu um erro ao gravar as definições.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Permissões\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Deve fornecer uma nova palavra-passe\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Deve fornecer sua palavra-passe atual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Palavras-passe devem corresponder\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Deve confirmar a nova palavra-passe\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Palavra-passe gravada com sucesso!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Palavra-passe\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nova Palavra-passe\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Palavra-passe Atual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Confirmar Palavra-passe\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Definicções de Notificação\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Definições gravadas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Ocorreu um erro ao gravar as definições.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Utilizador Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Utilizador Local\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Definições Gerais\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Nome de Exibição\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Modificar Definições\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Ver Perfil\",\n  \"components.UserList.edituser\": \"Modificar Permissões do Utilizador\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Deve fornecer um token de acesso\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Ativar Agente\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Token de acesso\",\n  \"components.Layout.UserDropdown.settings\": \"Definições\",\n  \"components.Layout.UserDropdown.myprofile\": \"Perfil\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Palavra-passe muito curta; necessário ter no mínimo 8 caracteres\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Ocorreu um erro ao gravar a palavra-passe.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Deve fornecer um ID de utilizador válido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"O número de <FindDiscordIdLink>ID</FindDiscordIdLink> da sua conta de utilizador\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID de Utilizador\",\n  \"components.UserList.userfail\": \"Ocorreu um erro ao gravar as permissões do utilizador.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Definições de notificação Pushbullet gravadas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Falha ao gravar as definições de notificação Pushbullet.\",\n  \"components.CollectionDetails.requestcollection4k\": \"Pedir Coleção em 4K\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtrar conteúdo por disponibilidade da região\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Descubrir Região\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtrar conteúdo por idioma original\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Descobrir Idioma\",\n  \"components.Discover.upcomingtv\": \"Séries a Estrear\",\n  \"components.RegionSelector.regionDefault\": \"Todas as Regiões\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.email\": \"E-Mail\",\n  \"components.RegionSelector.regionServerDefault\": \"Predefinição ({region})\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Não tem permissão para modificar a palavra-passe deste utilizador.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Utilizador\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Função\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Proprietário\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrador\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Tipo de Conta\",\n  \"components.UserList.owner\": \"Proprietário\",\n  \"components.UserList.accounttype\": \"Tipo\",\n  \"i18n.loading\": \"A carregar…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Deve fornecer um ID de chat válido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Iniciar uma conversa</TelegramBotLink>, adicionar <GetIdBotLink>@get_id_bot</GetIdBotLink>, e enviar o comando <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID do Chat\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Envia notificações sem som\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Enviar Silenciosamente\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Temporada} other {# Temporadas}}\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Tarefa Desconhecida\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Reiniciar Sincronização de Transferências\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Sincronizar Transferências\",\n  \"components.Settings.Notifications.botUsername\": \"Utilizador do Bot\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Séries de {genre}\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Filmes por {studio}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Séries por {network}\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Filmes de {genre}\",\n  \"components.Settings.scanning\": \"A sincronizar…\",\n  \"components.Settings.scan\": \"Sincronizar Bibliotecas Plex\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sincronizar Sonarr\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Sincronizar Radarr\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Sincronizar Adicionado Recentemente do Plex\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Sincronização Completa da Biblioteca Plex\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Sincronização Completa da Biblioteca Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Sincronizar Adicionado Recentemente do Jellyfin\",\n  \"components.RequestList.RequestItem.requested\": \"Pedido\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} por {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Modificado\",\n  \"components.Discover.StudioSlider.studios\": \"Estúdios\",\n  \"components.Discover.NetworkSlider.networks\": \"Emissoras\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL do Avatar do Bot\",\n  \"components.Settings.Notifications.validationUrl\": \"Deve fornecer um URL valido\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Séries em {language}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Filmes em {language}\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID de Utilizador: {userid}\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Entrou no {joindate}\",\n  \"components.Settings.menuUsers\": \"Utilizadores\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Configurar as definições de utilizador global e predefinição.\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Definições de Utilizador\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Definições de utilizador gravadas com sucesso!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Ocorreu um erro enquanto guardava as definições.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Ativar Inicio de Sessão Local\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Permissões Predefinições\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Não tem permissão para modificar as definições deste utilizador.\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Não pode modificar suas próprias permissões.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Enviar notificações quando os utilizadores apresentarem novos pedidos de multimédia que são automaticamente aprovados.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Multimédia Aprovada Automaticamente\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minutos\",\n  \"components.TvDetails.episodeRuntime\": \"Duração do Episódio\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Assinar mensagens de e-mail encriptadas utilizando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Assinar mensagens de e-mail encriptadas utilizando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Chave Privada PGP\",\n  \"components.Settings.Notifications.pgpPassword\": \"Palavra-passe PGP\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.alreadyrequested\": \"Já Foi Pedido\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Géneros de Série\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Géneros de Série\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Géneros de Filmes\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Géneros de Filmes\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.somethingwentwrong\": \"Ocorreu um erro\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Ocorreu um erro ao grvar a palavra-passe. A sua palavra-passe atual foi inserida corretamente?\",\n  \"pages.serviceunavailable\": \"Serviço Indisponível\",\n  \"pages.pagenotfound\": \"Página Não Encontrada\",\n  \"pages.internalservererror\": \"Erro Interno do Servidor\",\n  \"i18n.usersettings\": \"Utilizadores\",\n  \"i18n.settings\": \"Definições\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notificações\",\n  \"components.Settings.services\": \"Serviços\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Notificações\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Geral\",\n  \"components.Settings.SettingsUsers.users\": \"Utilizadores\",\n  \"components.Settings.SettingsLogs.time\": \"Marcação Horária\",\n  \"components.Settings.SettingsLogs.showall\": \"Mostrar Todos os Registos\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Retomar\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pausa\",\n  \"components.Settings.SettingsLogs.message\": \"Mensagem\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Também pode ver estes registos diretamente através de <code>stdout</code>, ou em <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.logs\": \"Registos\",\n  \"components.Settings.SettingsLogs.level\": \"Gravidade\",\n  \"components.Settings.SettingsLogs.label\": \"Rótulo\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Aviso\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Informação\",\n  \"components.Settings.SettingsLogs.filterError\": \"Erro\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Depuração\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Tarefas e Cache\",\n  \"components.Settings.SettingsAbout.about\": \"Sobre\",\n  \"components.ResetPassword.passwordreset\": \"Repor Palavra-passe\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Detalhes do registo\",\n  \"components.Settings.SettingsLogs.extraData\": \"Dados Adicionais\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Copiar Para a Área de Transferência\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Mensagem do registo copiada para o área de transferência.\",\n  \"components.Settings.enablessl\": \"Usar SSL\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Nasceu {birthdate}\",\n  \"components.PersonDetails.alsoknownas\": \"Também Conhecido Como: {nomes}\",\n  \"components.UserList.nouserstoimport\": \"Não há novos utilizadores para importar do Plex.\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {filme} other {filmes}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"filme\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Este utilizador tem direito a pedir <strong>{limit}</strong> {type} cada <strong>{days}</strong> dias.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Tem direito para pedir <strong>{limit}</strong> {type} cada <strong>{days}</strong> dias.\",\n  \"components.QuotaSelector.unlimited\": \"Ilimitado\",\n  \"components.UserProfile.unlimited\": \"Ilimitado\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Precisa ter pelo menos <strong>{seasons}</strong> {seasons, plural, one {pedido de temporada} other {pedidos de temporadas}} para enviar um pedido para esta série.\",\n  \"components.UserProfile.totalrequests\": \"Total de Pedidos\",\n  \"components.UserProfile.seriesrequest\": \"Pedidos de Séries\",\n  \"components.UserProfile.requestsperdays\": \"{limit} restante(s)\",\n  \"components.UserProfile.pastdays\": \"{type} (últimos {days} dias)\",\n  \"components.UserProfile.movierequests\": \"Pedidos de Filmes\",\n  \"components.UserProfile.limit\": \"{remaining} de {limit}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Limite de Pedidos para Séries\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Limite de Pedidos para Filmes\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Substituir o limite global\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Limite Global de Pedidos de Séries\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Limite Global de Pedidos de Filmes\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {temporada} other {temporadas}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"temporada\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Nenhum} other {<strong>#</strong>}} {type} {remaining, plural, one {pedido} other {pedidos}} restantes\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Pode ver um resumo dos limites de pedidos deste utilizador na sua <ProfileLink>página de perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Pode ver um resumo dos seus limites de pedidos na sua <ProfileLink>página de perfil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Não há pedidos de temporada suficientes\",\n  \"i18n.next\": \"Próxima\",\n  \"i18n.all\": \"Todas\",\n  \"i18n.view\": \"Ver\",\n  \"i18n.tvshow\": \"Séries\",\n  \"i18n.testing\": \"A testar…\",\n  \"i18n.test\": \"Testar\",\n  \"i18n.status\": \"Estado\",\n  \"i18n.showingresults\": \"A mostrar <strong>{from}</strong> para <strong>{to}</strong> de <strong>{total}</strong> resultados\",\n  \"i18n.saving\": \"A Gravar…\",\n  \"i18n.save\": \"Gravar Alterações\",\n  \"i18n.resultsperpage\": \"Mostrar {pageSize} resultados por página\",\n  \"i18n.requesting\": \"A Pedir…\",\n  \"i18n.request4k\": \"Pedir em 4K\",\n  \"i18n.previous\": \"Anterior\",\n  \"i18n.notrequested\": \"Não Pedido\",\n  \"i18n.noresults\": \"Sem resultados.\",\n  \"i18n.movie\": \"Filme\",\n  \"i18n.canceling\": \"A cancelar…\",\n  \"i18n.back\": \"Voltar\",\n  \"i18n.areyousure\": \"Tem certeza?\",\n  \"components.TvDetails.originaltitle\": \"Título Original\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Este utilizador precisa ter pelo menos <strong>{seasons}</strong> {seasons, plural, one {pedido de temporada} other {pedidos de temporadas}} restantes para enviar um pedido para esta série.\",\n  \"components.MovieDetails.originaltitle\": \"Título Original\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Todos Idiomas\",\n  \"components.LanguageSelector.languageServerDefault\": \"Predefinição ({language})\",\n  \"components.Settings.SonarrModal.loadingTags\": \"A carregar tags…\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Modificar Servidor Sonarr 4K\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Servidor 4K Predefinido\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Adicionar Novo Servidor Sonarr 4K\",\n  \"components.Settings.SonarrModal.animeTags\": \"Tags Para Anime\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Testar ligação para carregar tags\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Testar ligação para carregar tags\",\n  \"components.Settings.SonarrModal.tags\": \"Tags\",\n  \"components.Settings.RadarrModal.tags\": \"Tags\",\n  \"components.Settings.SonarrModal.selecttags\": \"Selecionar tags\",\n  \"components.Settings.RadarrModal.selecttags\": \"Selecionar tags\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Nenhuma tag.\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Nenhuma tag.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"A carregar tags…\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Modificar Servidor Radarr 4K\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Servidor 4K Predefinido\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Adicionar Novo Servidor Radarr 4K\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Tags\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Selecionar tags\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Nenhuma tag.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Deve fornecer uma chave pública PGP válida\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Chave Pública PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Encriptar mensagens de e-mail usando <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Deve fornecer uma chave privada PGP válida\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Deve fornecer uma palavra-passe PGP\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Permitir que utilizadores iniciem uma conversa com o seu bot e configurem as suas próprias notificações\",\n  \"components.RequestModal.pendingapproval\": \"O seu pedido está com aprovação pendente.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} não encontrado\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Apagar Pedido\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} não encontrado\",\n  \"components.RequestCard.deleterequest\": \"Apagar Pedido\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Tipos de Notificação\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stable\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Develop\",\n  \"components.Layout.VersionStatus.outofdate\": \"Desatualizado\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} atrás\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Definições de notificação Telegram gravadas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Falha ao gravas as definições de notificação Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Definições de notificação e-mail gravadas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Falha ao gravas as definições de notificação e-mail.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-Mail\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Definições de notificação Discord gravadas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Falha ao gravar as definições de notificação Discord.\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Cancelar Pedido\",\n  \"components.Settings.serviceSettingsDescription\": \"Configure o seu(s) servidor(es) {serverType} abaixo. Pode ligar vários servidores {serverType}, mas apenas dois deles podem ser marcados como predefinidos (um não 4K e um 4K). Os administradores podem mudar o servidor usado para processar novos pedidos antes da aprovação.\",\n  \"components.Settings.noDefaultServer\": \"Pelo menos um servidor {serverType} deve ser marcado como predefinido para que os pedidos de {mediaType} sejam processados.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Se tiver apenas um único servidor {serverType} para conteúdo não 4K e 4K (ou se apenas transfere conteúdo 4K), o seu servidor {serverType} <strong>NÃO</strong> deve ser designado como um servidor 4K.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Atualmente, sua conta não tem uma palavra-passe definida. Configure uma palavra-passe abaixo para permitir o inicio de sessão como um \\\"utilizador local\\\" usando o seu e-mail.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Esta conta de utilizador não tem atualmente uma palavra-passe definida. Configure uma palavra-passe abaixo para permitir que esta conta se autentique como \\\"utilizador local\\\".\",\n  \"components.Settings.mediaTypeSeries\": \"séries\",\n  \"components.Settings.mediaTypeMovie\": \"filme\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Atualizado\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Desatualizado\",\n  \"components.UserList.autogeneratepasswordTip\": \"Enviar uma palavra-passe gerada pelo servidor para o utilizador por e-mail\",\n  \"i18n.retrying\": \"A tentar novamente…\",\n  \"components.Settings.serverSecure\": \"seguro\",\n  \"components.UserList.usercreatedfailedexisting\": \"A e-mail fornecido já está a ser usado por outro utilizador.\",\n  \"components.RequestModal.edit\": \"Modificar Pedido\",\n  \"components.RequestList.RequestItem.editrequest\": \"Modificar Pedido\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Ativar Pesquisa Automática\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Ativar Pesquisa Automática\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Idioma de Exibição\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Definições de notificação web push gravadas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Falha ao gravar as definições de notificação web push.\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Ativar Agente\",\n  \"components.Settings.noDefault4kServer\": \"Um servidor 4K {serverType} deve ser marcado como predefinido para permitir que os utilizador enviem pedidos 4K de {mediaType}.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Permitir que Utilizadores do {mediaServerName} iniciem sessão sem primeiro serem importados\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Ativar novo inicio de sessão {mediaServerName}\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Notificação de teste Telegram enviada!\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Notificação de teste e-mail enviada!\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Notificação de teste Discord enviada!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Notificação de teste webhook enviada!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Notificação de teste web push enviada!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Notificação de teste Slack enviada!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Notificação de teste Pushover enviada!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Notificação de teste Pushbullet enviada!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"A enviar notificação de teste Telegram…\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"A enviar notificação de teste e-mail…\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"A enviar notificação de teste Discord…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"A enviar notificação de teste webhook…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"A enviar notificação de teste web push…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"A enviar notificação de teste Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"A enviar notificação de teste Pushbullet…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Falha ao enviar notificação de teste Telegram.\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Falha ao enviar notificação de teste e-mail.\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Falha ao enviar notificação de teste Discord.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Falha ao enviar notificação de teste webhook.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Falha ao enviar notificação de teste web push.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"A enviar notificação de teste Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Falha ao enviar notificação de teste Slack.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Falha ao enviar notificação de teste Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Falha ao enviar notificação de teste Pushbullet.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Conceder permissão para pedir séries não 4K.\",\n  \"components.PermissionEdit.requestTv\": \"Pedir Séries\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Conceder permissão para pedir filmes não 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Pedir Filmes\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Predefinido ({language})\",\n  \"components.UserList.localLoginDisabled\": \"A configuração <strong>Ativar inicio de sessão Local</strong> está desativada de momento.\",\n  \"components.Settings.webAppUrlTip\": \"Opcionalmente direcionar os utilizadores para a aplicação de web app no seu servidor, em vez da aplicação de web app \\\"hospedada\\\"\",\n  \"components.Settings.webAppUrl\": \"URL <WebAppLink>Web App</WebAppLink>\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Criar um <DiscordWebhookLink>webhook de integração</DiscordWebhookLink> no seu servidor\",\n  \"components.Settings.Notifications.encryptionTip\": \"Na maioria dos casos, o TLS implícito usa a porta 465 e o STARTTLS usa a porta 587\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Usar STARTTLS sempre\",\n  \"components.Settings.Notifications.encryptionNone\": \"Nenhuma\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Usar TLS Implícito\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Usar STARTTLS se disponível\",\n  \"components.Settings.Notifications.encryption\": \"Método de Encriptação\",\n  \"components.Settings.Notifications.chatIdTip\": \"Iniciar uma conversa com o seu bot, adicione <GetIdBotLink>@get_id_bot</GetIdBotLink> e execute o comando <code>/my_id</code>\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registe uma aplicação</ApplicationRegistrationLink> para utilizar com Seerr\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Criar um bot</CreateBotLink> para utilizar com Seerr\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Para receber notificações push web, o Seerr deve ser servido via HTTPS.\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Criar integração para um <WebhookLink>Webhook de Entrada</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"O seu <UsersGroupsLink>identificador de utilizador ou grupo</UsersGroupsLink> contendo 30 caractéres\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Criar um token a partir das suas <PushbulletSettingsLink>Definições de Conta</PushbulletSettingsLink>\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Pedido\",\n  \"components.RequestCard.failedretry\": \"Ocorreu um erro ao voltar a tentar o pedido.\",\n  \"components.DownloadBlock.estimatedtime\": \"Estimativa {time}\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Permitir que os utilizadores se autentiquem com o seu endereço de e-mail e palavra-passe\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Permissões iniciais atribuídas a novos utilizadores\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} por {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {temporada} other {temporadas}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {fime} other {filmes}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} por {quotaDays} {days}</quotaUnits>\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Notificar quando os seus pedidos de multimédia forem aprovados.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Notificar quando outros utilizadores submeteres novos pedidos de multimédia que são automaticamente aprovados.\",\n  \"components.Settings.Notifications.validationTypes\": \"Deve selecionar pelo menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Deve selecionar pelo menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Deve selecionar pelo menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Deve selecionar pelo menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Deve selecionar pelo menos um tipo de notificação\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Notificar quando outros utilizadores enviarem novos pedidos de multimédia que requeiram aprovação.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Notificar quando os pedidos de multimédia não forem adicionados ao Radarr ou Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Notificar quando seus pedidos de multimédia forem recusados.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Notificar quando os seus pedidos de multimédia ficarem disponíveis.\",\n  \"components.QuotaSelector.days\": \"{conta, plural, one {dia} other {dias}}\",\n  \"components.MovieDetails.streamingproviders\": \"Atualmente a Exibir em\",\n  \"components.TvDetails.streamingproviders\": \"Atualmente a Exibir em\",\n  \"components.MovieDetails.showmore\": \"Mostrar Mais\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Idioma da Interface\",\n  \"components.MovieDetails.showless\": \"Mostrar Menos\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Algo deu errado ao gravar tarefa.\",\n  \"components.StatusBadge.managemedia\": \"Gerir {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Abrir em {arr}\",\n  \"components.IssueDetails.allseasons\": \"Todas Temporadas\",\n  \"components.IssueDetails.nocomments\": \"Nenhum comentário.\",\n  \"components.IssueDetails.openinarr\": \"Abrir no {arr}\",\n  \"components.PermissionEdit.viewissues\": \"Ver Problemas\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Ativar Agente\",\n  \"components.TvDetails.rtaudiencescore\": \"Pontuação de audiência no Rotten Tomatoes\",\n  \"components.TvDetails.rtcriticsscore\": \"Pontuação de audiência no Rotten Tomatoes\",\n  \"components.TvDetails.seasonnumber\": \"Temporada {seasonNumber}\",\n  \"components.TvDetails.seasonstitle\": \"Temporadas\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Pedir séries automaticamente\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Deve prover um ID válido de utilizador Discord\",\n  \"i18n.resolved\": \"Resolvido\",\n  \"components.PermissionEdit.createissuesDescription\": \"Concede permissão para reportar problemas com mídias.\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Concede permissão para gerir problemas com mídia.\",\n  \"components.RequestModal.selectmovies\": \"Selecionar Filme(s)\",\n  \"components.IssueList.IssueItem.opened\": \"Aberto\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} por {user}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Desconhecido\",\n  \"components.IssueList.IssueItem.viewissue\": \"Ver Problema\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Todos Episódios\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Problemas Abertos\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {País} other {Países}} de Produção\",\n  \"components.PermissionEdit.viewrecent\": \"Ver Recentemente Adicionados\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Concede permissão para ver lista de mídias adicionadas recentemente.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Cada {jobScheduleMinutes, plural, one {minuto} other {{jobScheduleMinutes} minutos}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID do Utilizador Discord\",\n  \"i18n.restartRequired\": \"Reinicialização Necessária\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Atualizado\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Por favor, reinicie o servidor para aplicar as novas configurações.\",\n  \"components.TitleCard.cleardata\": \"Limpar Dados\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"O seu <UsersGroupsLink>identificador de utilizador ou grupo</UsersGroupsLink> contendo 30 caractéres\",\n  \"components.RequestCard.tmdbid\": \"ID do TMDB\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Configurações de notificação via Pushover salvas com sucesso!\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"A sua lista para ver do Plex\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Tem certeza que deseja apagar este problema?\",\n  \"components.IssueDetails.toaststatusupdated\": \"Estado do problema atualizado com sucesso!\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Espisódio} other {Episódios}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Estado\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Episódio Afetado\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Temporada Afetada\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Reportar um Problema\",\n  \"components.IssueModal.issueAudio\": \"Áudio\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Gerir {mediaType}\",\n  \"components.RequestList.RequestItem.tmdbid\": \"ID do TMDB\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Sincronização da lista para ver do Plex\",\n  \"components.Settings.deleteServer\": \"Remover Servidor {serverType}\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Por favor, clique no botão abaixo para recarregar a aplicação.\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avançado\",\n  \"components.ManageSlideOver.alltime\": \"Desde Início\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Mídia\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Mídia 4K\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Marcar Todas Temporadas como Disponíveis em 4K\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Receber notificação quando problemas que reportou forem re-abertos.\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Concede permissão para ver problemas em mídias reportados por outros problemas.\",\n  \"components.RequestModal.requestmovies\": \"Solicitar {count} {count, plural, one {Filme} other {Filmes}}\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL Base deve iniciar com uma barra\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Lista para ver do Plex\",\n  \"components.Discover.plexwatchlist\": \"A sua lista para ver do Plex\",\n  \"components.IssueDetails.closeissue\": \"Encerrar Problema\",\n  \"components.IssueDetails.commentplaceholder\": \"Adicionar um comentário…\",\n  \"components.IssueDetails.closeissueandcomment\": \"Fechar com Comentário\",\n  \"components.IssueDetails.leavecomment\": \"Comentar\",\n  \"components.IssueDetails.comments\": \"Comentários\",\n  \"components.IssueDetails.deleteissue\": \"Apagar Problema\",\n  \"components.IssueDetails.problemseason\": \"Temporada Afetada\",\n  \"components.IssueDetails.reopenissue\": \"Re-abrir Problema\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Re-abrir com Comentário\",\n  \"components.IssueDetails.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Algo deu errado ao editar a descrição do problema.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Descrição do problema alterada com sucesso!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Problema apagado com sucesso!\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"O quê há de errado?\",\n  \"components.IssueModal.issueOther\": \"Outros\",\n  \"components.IssueModal.issueSubtitles\": \"Legenda\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Receber notificação quando problemas forem re-abertos por outros utilizadores.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Comentário no Problema\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Enviar notificações quando problemas receberem novos comentários.\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Enviar notificações quando problemas são reportados.\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Enviar notificações quando problemas são resolvidos.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Pedido automaticamente enviado\",\n  \"components.PermissionEdit.viewwatchlists\": \"Ver lista para ver do Plex\",\n  \"components.RequestModal.requestseasons4k\": \"Solicitar {seasonCount} {seasonCount, plural, one {Temporada} other {Temporadas}} em 4K\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Algo deu errado ao gravar configurações do Tautulli.\",\n  \"components.TitleCard.tmdbid\": \"ID do TMDB\",\n  \"components.TitleCard.tvdbid\": \"ID do TheTVDB\",\n  \"components.TvDetails.manageseries\": \"Gerir Séries\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Receber notificação quando problemas são resolvidos por outros utilizadores.\",\n  \"components.PermissionEdit.autorequest\": \"Solicitar Automaticamente\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Ser notificado quando novos pedidos de média forem enviados automaticamente para itens na sua lista para ver.\",\n  \"components.PermissionEdit.autorequestDescription\": \"Concede permissão para enviar automaticamente pedidos de média não 4K via lista para ver do Plex.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Solicitar Filmes Automaticamente\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Concede permissão para enviar automaticamente pedidos para filmes não-4K via lista para ver do Plex.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Solicitar Séries Automaticamente\",\n  \"components.RequestCard.tvdbid\": \"ID do TheTVDB\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Ver Detalhes\",\n  \"components.Settings.advancedTooltip\": \"Configurar incorretamente esta opção pode resultar numa funcionalidade quebrada\",\n  \"components.StatusChecker.restartRequired\": \"Reinicialização do Servidor Necessária\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} Não Encontrado\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Configurações do Tautulli salvas com sucesso!\",\n  \"components.Settings.RadarrModal.released\": \"Lançado\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Tem certeza que deseja apagar este comentário?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Apagar Comentário\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Feito {relativeTime} por {username} (Edited)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Deve escrever uma mensagem\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Apagar Problema\",\n  \"components.IssueDetails.openedby\": \"#{issueId} aberto {relativeTime} por {username}\",\n  \"components.IssueDetails.problemepisode\": \"Episódio Afetado\",\n  \"components.IssueList.sortAdded\": \"Mais Recente\",\n  \"components.IssueList.sortModified\": \"Última Modificação\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problema Reportado\",\n  \"components.PermissionEdit.manageissues\": \"Gerir Problemas\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Alterar Descrição\",\n  \"components.IssueDetails.allepisodes\": \"Todos Episódios\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Algo deu errado ao apagar problema.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Algo deu errado ao atualizar o estado do problema.\",\n  \"components.IssueDetails.unknownissuetype\": \"Desconhecido\",\n  \"components.RequestModal.requestmovies4k\": \"Solicitar {count} {count, plural, one {Filme} other {Filmes}} em 4K\",\n  \"components.TvDetails.tmdbuserscore\": \"Pontuação de Utilizador do TMDB\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Pedir filmes automaticamente\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Criar um token da sua <PushbulletSettingsLink>Configuração de Conta</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Token de acesso\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Deve prover um token de acesso\",\n  \"i18n.open\": \"Aberto\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Está a executar o branch <code>develop</code> do Seerr, que só é recomendado para quem contribui para o desenvolvimento ou ajuda com testes de versões experimentais.\",\n  \"components.AirDateBadge.airedrelative\": \"Exibido em {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Exibindo {relativeTime}\",\n  \"components.IssueDetails.IssueDescription.description\": \"Descrição\",\n  \"components.IssueDetails.play4konplex\": \"Assistir em 4K no Plex\",\n  \"components.IssueDetails.playonplex\": \"Assistir no Plex\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Relato de problema em <strong>{title}</strong> enviado com sucesso!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Ver Problema\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Concede permissão para enviar automaticamente pedidos para séries não-4K via lista para ver do Plex.\",\n  \"components.TvDetails.reportissue\": \"Reportar um Problema\",\n  \"components.RequestBlock.languageprofile\": \"Perfil de Idioma\",\n  \"components.RequestModal.requestApproved\": \"Solicitação de <strong>{title}</strong> aprovada!\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Falha ao gravar configurações de notificação via Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Configurações de notificação via Gotify salvas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Falha ao enviar notificação de teste via Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL do Servidor\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Deve fornecer um token de aplicação\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Deve selecionar ao menos um tipo de notificação\",\n  \"components.Settings.Notifications.enableMentions\": \"Ativar Menções\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Nos Cinemas\",\n  \"components.Settings.tautulliSettings\": \"Configurações do Tautulli\",\n  \"components.Settings.tautulliSettingsDescription\": \"Opcionalmente, configure as definições do seu servidor Tautulli. O Seerr obtém os dados do histórico de visualização dos seus média Plex a partir do Tautulli.\",\n  \"components.Settings.urlBase\": \"Base do URL\",\n  \"components.Settings.validationApiKey\": \"Deve prover uma chave API válida\",\n  \"components.Settings.validationUrl\": \"Deve prover uma URL válida\",\n  \"components.TvDetails.productioncountries\": \"{countryCount, plural, one {País} other {Países}} de Produção\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"O <FindDiscordIdLink>número de identificação</FindDiscordIdLink> associado à sua conta Discord\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Falha ao gravar configurações de notificação via Pushover.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Deve prover uma chave válida de acesso\",\n  \"components.UserProfile.recentlywatched\": \"Assistidos Recentemente\",\n  \"i18n.import\": \"Importar\",\n  \"i18n.importing\": \"Importando…\",\n  \"components.IssueDetails.issuetype\": \"Tipo\",\n  \"components.IssueDetails.openin4karr\": \"Abrir em {arr} 4K\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Episódio Afetado\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Temporada} other {Temporadas}}\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Nenhuma solicitação.\",\n  \"components.ManageSlideOver.downloadstatus\": \"Downloads\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Limpar Dados\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Isso irá remover em definitivo todos dados desse(a) {mediaType}, incluindo quaisquer solicitações para esse item. Se este item existir na sua biblioteca do Plex, os dados de mídia serão recriados na próxima sincronia.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Solicitações\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Receber notificação quando outros utilizadores reportarem problemas.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Receber notificação quando problemas reportados por receberem novos comentários.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Receber notificação quando problemas que reportou forem resolvidos.\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Editar Tarefa\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"A cada {jobScheduleHours, plural, one {hora} other {{jobScheduleHours} horas}}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Deve prover uma chave válida de usúario ou grupo\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Configurações\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Tag do Canal\",\n  \"components.RequestBlock.edit\": \"Editar Pedido\",\n  \"components.RequestBlock.lastmodifiedby\": \"Última modificação por\",\n  \"components.RequestBlock.requestdate\": \"Data do pedido\",\n  \"components.RequestBlock.requestedby\": \"Pedido por\",\n  \"components.RequestCard.approverequest\": \"Aprovar pedido\",\n  \"components.RequestCard.cancelrequest\": \"Cancelar pedido\",\n  \"components.RequestCard.declinerequest\": \"Rejeitar Pedido\",\n  \"components.RequestCard.editrequest\": \"Editar Pedido\",\n  \"components.RequestModal.approve\": \"Aprovar Solicitação\",\n  \"components.IssueDetails.IssueComment.edit\": \"Editar Comentário\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Feito {relativeTime} por {username}\",\n  \"components.IssueDetails.episode\": \"Episódio {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Problema\",\n  \"components.IssueDetails.lastupdated\": \"Última Atualização\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tipo\",\n  \"components.IssueList.issues\": \"Problemas\",\n  \"components.IssueList.showallissues\": \"Exibir Todos Problemas\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Todas Temporadas\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episódio {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extras\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Por favor, explique em detalhes o problema que encontrou.\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Temporada {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Enviar Problema\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Algo deu errado ao enviar problema.\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Deve prover uma descrição\",\n  \"components.IssueModal.issueVideo\": \"Vídeo\",\n  \"components.Layout.Sidebar.issues\": \"Problemas\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Pedidos de Filmes\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Pedidos de Séries\",\n  \"components.Layout.UserDropdown.requests\": \"Pedidos\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Marcar como Disponível em 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Marcar Todas Temporadas como Disponíveis\",\n  \"components.ManageSlideOver.markavailable\": \"Marcar como Disponível\",\n  \"components.ManageSlideOver.movie\": \"filme\",\n  \"components.ManageSlideOver.openarr\": \"Abrir no {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Abrir no {arr} 4K\",\n  \"components.ManageSlideOver.opentautulli\": \"Abrir no Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Últimos {days, number} Dias\",\n  \"components.ManageSlideOver.playedby\": \"Reproduzido por\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {Reprodução} other {Reproduções}}\",\n  \"components.ManageSlideOver.tvshow\": \"série\",\n  \"components.MovieDetails.digitalrelease\": \"Lançamento Digital\",\n  \"components.MovieDetails.managemovie\": \"Gerir Filme\",\n  \"components.MovieDetails.physicalrelease\": \"Lançamento em Disco\",\n  \"components.MovieDetails.reportissue\": \"Reportar um problema\",\n  \"components.MovieDetails.rtaudiencescore\": \"Nota do público no Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatômetro do Rotten Tomatoes\",\n  \"components.MovieDetails.theatricalrelease\": \"Lançamento no Cinema\",\n  \"components.MovieDetails.tmdbuserscore\": \"Pontuação de utilizador do TMDB\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Receber notificação quando outros utilizadores comentarem nos problemas.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problema Re-aberto\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Enviar notificações quando problemas são re-abertos.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problema Resolvido\",\n  \"components.PermissionEdit.createissues\": \"Reportar Problemas\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Concede permissão para ver a lista para ver do Plex de outros utilizadores.\",\n  \"components.RequestBlock.approve\": \"Aprovar pedido\",\n  \"components.RequestBlock.decline\": \"Rejeitar pedido\",\n  \"components.RequestBlock.delete\": \"Deletar pedido\",\n  \"components.RequestList.RequestItem.tvdbid\": \"ID do TheTVDB\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Solicitar Coleção em 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Solicitar Coleção\",\n  \"components.RequestModal.requestseriestitle\": \"Solicitar Séries\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Enviando notificação de teste via Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Notificação de teste via Gotify enviada!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token de Acesso\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Deve prover uma URL válida\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"A URL não deve terminar com uma barra\",\n  \"components.Settings.RadarrModal.announced\": \"Anunciado\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Tarefa modificada com sucesso!\",\n  \"components.Settings.experimentalTooltip\": \"Ativar essa opção pode resultar num comportamento não esperado da aplicação\",\n  \"components.Settings.externalUrl\": \"URL Externa\",\n  \"components.Settings.restartrequiredTooltip\": \"O Seerr deve ser reiniciado para que as alterações a esta definição tenham efeito\",\n  \"components.Settings.tautulliApiKey\": \"Chave API\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"A URL base não pode terminar com uma barra\",\n  \"components.Settings.validationUrlTrailingSlash\": \"A URL não pode terminar com uma barra\",\n  \"components.StatusBadge.playonplex\": \"Reproduzir no Plex\",\n  \"components.StatusChecker.reloadApp\": \"Recarregar {applicationTitle}\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Algo deu errado enquanto os dados da temporada eram adquiridos.\",\n  \"components.UserList.newplexsigninenabled\": \"A opção <strong>Ativar Novo Método de Início de Sessão do Plex</strong> está ativada. Utilizadores Plex com acesso à bibliotecas podem se autenticar sem que precisem serem importados.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Configurações de notificação via Pushbullet salvas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Token de Acesso\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registe uma aplicação</ApplicationRegistrationLink> para uso com {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Chave do Utilizador ou Grupo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Falha ao gravar configurações de notificação via Pushover.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Filmes\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Nova Frequência\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Tamanho Total do Cache\",\n  \"components.Settings.SettingsMain.apikey\": \"Chave API\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Configurar definições globais e predefinidas para o Seerr.\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Espisódio} other {# Episódios}}\",\n  \"components.Discover.CreateSlider.needresults\": \"Precisa ter ao menos 1 resultado.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Sem resultados.\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Data de lançamento Ascendente\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Data de Lançamento Descendente\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Título (A-Z) Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Título (Z-A) Descendente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Classificação TMDB Ascendente\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Classificação TMDB Descendente\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Remover\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Séries\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Primeira Data de Exibição Ascendente\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Primeira Data de Exibição Descendente\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularidade Ascendente\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularidade Descendente\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Título (Z-A) Descendente\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Classificação TMDB Ascendente\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Séries\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Limpar Filtros Ativos\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtros\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Primeira Exibição\",\n  \"components.Discover.FilterSlideover.from\": \"De\",\n  \"components.Discover.FilterSlideover.genres\": \"Gêneros\",\n  \"components.Discover.FilterSlideover.keywords\": \"Palavras-chave\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Língua Original\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Avaliações entre {minValue} e {maxValue}\",\n  \"components.Discover.FilterSlideover.runtime\": \"Duração\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"Duração de {minValue}-{maxValue} minutos\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Serviços de Streaming\",\n  \"components.Discover.FilterSlideover.studio\": \"Estúdio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Avaliação de Utilizadores do TMDB\",\n  \"components.Discover.FilterSlideover.to\": \"Até\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Média adicionados à sua <PlexWatchlistSupportLink>lista para ver Plex</PlexWatchlistSupportLink> aparecerão aqui.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"A sua lista para ver do Plex\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Adicionado Recentemente\",\n  \"components.Discover.createnewslider\": \"Criar Novo Carrossel\",\n  \"components.Discover.customizediscover\": \"Personalizar Exploração\",\n  \"components.Discover.resettodefault\": \"Restaurar o Padrão\",\n  \"components.Discover.tmdbstudio\": \"Estúdio no TMDB\",\n  \"components.Discover.resetwarning\": \"Todos os deslizadores resetados para os valores padrões. Isso também deletará todos os deslizadores personalizados!\",\n  \"components.Discover.tmdbtvgenre\": \"Gênero de Série no TMDB\",\n  \"components.Discover.stopediting\": \"Cancelar Edição\",\n  \"components.Discover.tmdbmoviegenre\": \"Gênero de Filmes no TMDB\",\n  \"components.Discover.tmdbmoviekeyword\": \"Palavra-chave de Filme no TMDB\",\n  \"components.Discover.tmdbnetwork\": \"Emissora no TMDB\",\n  \"components.Discover.tmdbsearch\": \"Pesquisa no TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Palavra-chave de Série no TMDB\",\n  \"components.Discover.tvgenres\": \"Gêneros de Séries\",\n  \"components.Discover.updatefailed\": \"Algo deu errado com a mudança das configurações de descoberta personalizadas.\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Temporada {seasonNumber} Episódio {episodeNumber}\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmes\",\n  \"components.Layout.Sidebar.browsetv\": \"Séries\",\n  \"components.RequestCard.unknowntitle\": \"Título Desconhecido\",\n  \"components.Selector.searchStudios\": \"Pesquisar estúdios…\",\n  \"components.Selector.showless\": \"Mostrar Menos\",\n  \"components.Selector.showmore\": \"Mostrar Mais\",\n  \"components.Selector.starttyping\": \"Comece a digitar para pesquisar.\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Título da Aplicação\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL da Aplicação\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Ativar Cache de Imagens\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Armazenar em cache imagens de origem externa (requer uma quantidade significativa de espaço em disco)\",\n  \"components.Settings.SettingsMain.general\": \"Geral\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Configurações Gerais\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Ocultar Títulos Disponíveis\",\n  \"components.Settings.SettingsMain.locale\": \"Idioma da Interface\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Idioma de Exploração\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrar conteúdo pelo idioma original\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Permitir Solicitações Parciais de Séries\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Algo deu errado ao gerar a nova chave API.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Nova chave API gerada com sucesso!\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Algo de errado ao gravar configurações.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Configurações salvas com sucesso!\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Deve prover um título para a aplicação\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Deve prover uma URL válida\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"A URL não deve terminar com uma barra\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.TvDetails.Season.noepisodes\": \"Lista de episódios indisponível.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Pedir automaticamente filmes na sua <PlexWatchlistSupportLink>lista para ver do Plex</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Pedir automaticamente séries na sua <PlexWatchlistSupportLink>lista para ver do Plex</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.plexwatchlist\": \"Lista para ver do Plex\",\n  \"components.Discover.CreateSlider.addSlider\": \"Adicionar Carrossel\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Criar Carrossel Personalizado\",\n  \"components.Discover.CreateSlider.addfail\": \"Falha ao criar novo carrossel.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Novo deslizador criado e configurações de procura customizada salvas.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Editar Carrossel\",\n  \"components.Discover.CreateSlider.editfail\": \"Falha ao editar carrossel.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Deslizador editado e configurações customizadas de procura salvas.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Forneça um ID de gênero do TMDB\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Forneça um ID de palavra-chave do TMDB\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Forneça o ID de emissora do TMDB\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Forneça um dado para pesquisa\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Forneça o ID do estúdio no TMDB\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Pesquisar gêneros…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Pesquisar palavras-chave…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Pesquisar estúdios…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Nome do Carrossel\",\n  \"components.Discover.CreateSlider.starttyping\": \"Comece a digitar para pesquisar.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Deve informar um valor.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Deve prover um título.\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Falha ao remover carrossel.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Carrossel removido com sucesso.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Alternar a Visibilidade\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Filtro Ativo} other {# Filtros Ativos}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmes\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularidade Ascendente\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularidade Descendente\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Filtro Ativo} other {# Filtros Ativos}}\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Título (A-Z) Ascendente\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Classificação TMDB Descendente\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Filtro Ativo} other {# Filtros Ativos}}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Data de Lançamento\",\n  \"components.Discover.moviegenres\": \"Gêneros de Filmes\",\n  \"components.Discover.networks\": \"Emissora\",\n  \"components.Discover.resetfailed\": \"Algo deu errado com o reset das configurações personalizadas de descoberta.\",\n  \"components.Discover.resetsuccess\": \"As configurações de descoberta personalizadas foram resetadas com sucesso.\",\n  \"components.Discover.studios\": \"Estúdios\",\n  \"components.Discover.updatesuccess\": \"Configurações personalizadas de descoberta atualizadas.\",\n  \"components.Selector.nooptions\": \"Sem resultados.\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Cache de Imagens\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Limpeza de Cache de Imagens\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Quando ativado nas definições, o Seerr irá obter e guardar em cache as imagens de fontes externas pré-configuradas. As imagens em cache são guardadas na sua pasta de configuração. Pode encontrar os ficheiros em <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Imagens Armazenadas em Cache\",\n  \"components.UserProfile.emptywatchlist\": \"Média adicionado à sua <PlexWatchlistSupportLink>para ver no Plex</PlexWatchlistSupportLink> aparecerá aqui.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Solicitar Filme em 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Solicitar Filme\",\n  \"components.RequestModal.requestseries4ktitle\": \"Solicitar Série em 4K\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Frequência Atual\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Fomos incapazes de encontrar um série correspondente à serie solicitada.\",\n  \"components.Discover.emptywatchlist\": \"Média adicionado à sua <PlexWatchlistSupportLink>lista para ver do Plex</PlexWatchlistSupportLink> aparecerão aqui.\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Título Desconhecido\",\n  \"components.Selector.searchGenres\": \"Selecione os gêneros…\",\n  \"components.Selector.searchKeywords\": \"Pesquisar palavras-chave…\",\n  \"components.Discover.FilterSlideover.certification\": \"Classificação do conteúdo\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Excluir palavras-chave\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Contagem de votos de utilizadores TMDB\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Número de votos entre {minValue} e {maxValue}\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Próximas séries\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Serviços de streaming de filmes TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Serviços de streaming de TV TMDB\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Descrição do problema\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Endereço de e-mail é inválido.\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Um endereço de e-mail é necessário.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Requer uma palavra-passe.\",\n  \"components.Login.adminerror\": \"Deve utilizar uma conta de administrador para iniciar sessão.\",\n  \"components.Login.back\": \"Voltar\",\n  \"components.Login.credentialerror\": \"O nome de utilizador ou a palavra-passe estão incorretos.\",\n  \"components.Login.description\": \"Como esta é a sua primeira vez a conectar-se a {applicationName}, precisa adicionar um endereço de e-mail válido.\",\n  \"components.Login.emailtooltip\": \"O endereço não precisa ser associado à sua instância {mediaServerName}.\",\n  \"components.Login.enablessl\": \"Utilizar SSL\",\n  \"components.Login.hostname\": \"URL de {mediaServerName}\",\n  \"components.Login.initialsignin\": \"Conectar\",\n  \"components.Login.initialsigningin\": \"Conectando…\",\n  \"components.Login.invalidurlerror\": \"Não foi possível conectar-se ao servidor {mediaServerName}.\",\n  \"components.Login.loginwithapp\": \"Conecte-se com {appName}\",\n  \"components.Login.noadminerror\": \"Nenhum utilizador administrativo foi encontrado no servidor.\",\n  \"components.Login.orsigninwith\": \"Ou inicie sessão com\",\n  \"components.Login.save\": \"Adicionar\",\n  \"components.Login.saving\": \"Adicionando…\",\n  \"components.Login.servertype\": \"Tipo de servidor\",\n  \"components.Login.signinwithjellyfin\": \"Utilize a sua conta {mediaServerName}\",\n  \"components.Login.title\": \"Adicionar e-mail\",\n  \"components.Login.urlBase\": \"Base URL\",\n  \"components.Login.username\": \"Nome de utilizador\",\n  \"components.Login.validationEmailFormat\": \"E-mail inválido\",\n  \"components.Login.validationEmailRequired\": \"Você deve fornecer um e-mail\",\n  \"components.Login.validationPortRequired\": \"Você deve fornecer um número de porta válido\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"A base URL deve iniciar com uma barra\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"A base URL não deve terminar com uma barra\",\n  \"components.Login.validationUrlTrailingSlash\": \"A URL não deve terminar com uma barra\",\n  \"components.Login.validationemailformat\": \"E-mail válido necessário\",\n  \"components.Login.validationhostformat\": \"URL válido necessário\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL necessário\",\n  \"components.Login.validationservertyperequired\": \"Por favor, selecione um tipo de servidor\",\n  \"components.Login.validationusernamerequired\": \"Nome de utilizador necessário\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Isto irá remover irreversivelmente este {mediaType} de {arr}, incluindo todos os ficheiros.\",\n  \"components.ManageSlideOver.removearr\": \"Remover de {arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"Remover de {arr} 4K\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Selecione um fornecedor de metadados\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.MovieDetails.addtowatchlist\": \"Adicionar à lista para ver\",\n  \"components.MovieDetails.downloadstatus\": \"Status do download\",\n  \"components.MovieDetails.imdbuserscore\": \"Nota dos utilizadores IMDB – votos: {formattedCount}\",\n  \"components.MovieDetails.openradarr\": \"Abrir filme no Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"Abrir filme no Radarr 4K\",\n  \"components.MovieDetails.play\": \"Reproduzir em {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Reproduzir em 4K em {mediaServerName}\",\n  \"components.MovieDetails.removefromwatchlist\": \"Remover da lista para ver\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> Removido da lista para ver com sucesso!\",\n  \"components.MovieDetails.watchlistError\": \"Algo falhou. Por favor, tente novamente.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> adicionado a lista para ver com sucesso!\",\n  \"components.RequestList.RequestItem.profileName\": \"Perfil\",\n  \"components.RequestList.RequestItem.removearr\": \"Remover de {arr}\",\n  \"components.RequestList.sortDirection\": \"Alternar direção de ordenação\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Falha ao carregar as classificações etárias\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Nota máxima\",\n  \"components.Selector.CertificationSelector.minRating\": \"Nota mínima\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Sem opções disponíveis\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Selecionar uma classificação etária\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Selecionar um país\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Comece a escrever para pesquisar.\",\n  \"components.Selector.canceled\": \"Cancelado\",\n  \"components.Selector.ended\": \"Terminado\",\n  \"components.Selector.inProduction\": \"Em Produção\",\n  \"components.Selector.pilot\": \"Piloto\",\n  \"components.Selector.planned\": \"Planeado\",\n  \"components.Selector.returningSeries\": \"Série em regresso\",\n  \"components.Selector.searchStatus\": \"Selecionar estado...\",\n  \"components.Selector.searchUsers\": \"Selecionar utilizadores…\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Prioridade\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Deve definir um número de prioridade\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Ativar agente\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Incorporar cartaz\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Não foi possível guardar as definições de notificação Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Definições de notificação Ntfy guardadas com sucesso!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Palavra-passe\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Não foi possível enviar a notificação de teste Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"A enviar notificação de teste Ntfy…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Notificação de teste Ntfy enviada!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Autenticação por token\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Tópico\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"URL raiz do servidor\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Nome de utilizador\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Autenticação por nome de utilizador + palavra-passe\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Deve fornecer um tópico\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Deve fornecer um URL válido\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Deve selecionar pelo menos um tipo de notificação\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Predefinição do dispositivo\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Incorporar cartaz\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Som de notificação\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Incorporar cartaz\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Suportar variáveis de URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"As variáveis disponíveis estão documentadas na secção de variáveis de modelo do webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"O URL de notificação de teste está definido como {testUrl} em vez do URL real do webhook.\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Incorporar cartaz\",\n  \"components.Settings.Notifications.embedPoster\": \"Incorporar cartaz\",\n  \"components.Settings.Notifications.messageThreadId\": \"ID do tópico/thread\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Se o seu grupo tiver tópicos ativados, pode especificar o ID do tópico/thread aqui\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Requer e-mail do utilizador\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"O ID do tópico/thread deve ser um número inteiro positivo\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Deve fornecer um ID de cargo do Discord válido\",\n  \"components.Settings.Notifications.webhookRoleId\": \"ID de cargo de notificação\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"O ID de cargo a mencionar na mensagem do webhook. Deixe vazio para desativar menções\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Condições\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Especifica condições antes de aplicar alterações de parâmetros. Cada campo deve ser validado para que as regras sejam aplicadas (operação E). Um campo é considerado verificado se alguma das suas propriedades corresponder (operação OU).\",\n  \"components.Settings.OverrideRuleModal.create\": \"Criar regra\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Nova regra de exceção\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Editar regra de exceção\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Géneros\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Palavras-chave\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Idiomas\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Sem tags.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Perfil de qualidade\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Pasta raiz\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Regra de exceção criada com sucesso!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Regra de exceção atualizada com sucesso!\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Selecionar perfil de qualidade\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Selecionar pasta raiz\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Selecionar serviço\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Selecionar tags\",\n  \"components.Settings.OverrideRuleModal.service\": \"Serviço\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Aplicar esta regra ao serviço selecionado.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Definições\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Especifica quais definições serão alteradas quando as condições acima forem cumpridas.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleModal.users\": \"Utilizadores\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Condições\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Género\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Palavras-chave\",\n  \"components.Settings.OverrideRuleTile.language\": \"Idioma\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Perfil de qualidade\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Pasta raiz\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Definições\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Tags\",\n  \"components.Settings.OverrideRuleTile.users\": \"Utilizadores\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Etiquetar pedidos\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Adicionar automaticamente uma tag extra com o ID de utilizador e nome de exibição do requerente\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Sincronização de disponibilidade de média\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"Cache DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr armazena em cache as pesquisas DNS para otimizar o desempenho e evitar chamadas API desnecessárias.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Estatísticas globais de cache DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Estas estatísticas são agregadas de todas as entradas de cache DNS.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Endereço ativo\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Idade\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"Cache DNS {hostname} limpa.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Acertos\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Falhas\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Nome de anfitrião\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Cada {jobScheduleDays, plural, one {dia} other {{jobScheduleDays} dias}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Cada {jobScheduleSeconds, plural, one {segundo} other {{jobScheduleSeconds} segundos}}\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Falhas\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Limpar cache DNS\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Taxa de acertos\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Acertos\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"Recursos a IPv4\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Falhas\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Token de atualização do Plex\",\n  \"components.Settings.SettingsJobsCache.size\": \"Tamanho\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Avatares dos utilizadores\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"Chave API copiada para a área de transferência.\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Região de descoberta\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filtrar conteúdo por disponibilidade regional\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Permitir pedidos de episódios especiais\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Ocultar média disponíveis das páginas de descoberta, mas não dos resultados de pesquisa\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Região de streaming\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Mostrar sites de streaming por disponibilidade regional\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Deve fornecer um URL válido\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"O URL não deve terminar com uma barra\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"URL YouTube\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"URL base para vídeos do YouTube se uma instância auto-hospedada do YouTube for utilizada.\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Ativar proteção CSRF\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"NÃO ative esta definição a menos que saiba o que está a fazer!\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Definir acesso externo à API como apenas leitura (requer HTTPS)\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"Cache DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"TTL máximo de cache DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"TTL mínimo de cache DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"NÃO ative esta opção se estiver a ter problemas com pesquisas DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Ativar cache de pesquisas DNS para otimizar o desempenho e evitar chamadas API desnecessárias\",\n  \"components.Settings.SettingsNetwork.docs\": \"documentação\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Forçar resolução IPv4 primeiro\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Forçar o Seerr a resolver endereços IPv4 primeiro em vez de IPv6\",\n  \"components.Settings.SettingsNetwork.network\": \"Rede\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Os parâmetros de rede do seu contentor/sistema devem ser utilizados em vez destas definições. Consulte a {docs} para mais informações.\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Definições de rede\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Configure as definições de rede da sua instância Seerr.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Endereços ignorados pelo proxy\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Utilize ',' como separador e '*.' como caractere universal para subdomínios\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Ignorar proxy para endereços locais\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"Proxy HTTP(S)\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Nome de anfitrião do proxy\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Palavra-passe do proxy\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Porta do proxy\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Utilizar SSL para o proxy\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Nome de utilizador do proxy\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Ocorreu um erro ao guardar as definições.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Definições guardadas com sucesso!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Ativar suporte de proxy\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Permitir que o Seerr registe corretamente os endereços IP dos clientes atrás de um proxy\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Deve fornecer uma porta válida\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Métodos de autenticação\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Configurar métodos de autenticação para utilizadores.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Ativar autenticação com {mediaServerName}\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Permitir que os utilizadores se autentiquem com a sua conta {mediaServerName}\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Tipo de série anime\",\n  \"components.Settings.SonarrModal.seriesType\": \"Tipo de série\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Marcar pedidos com tags\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Adicionar automaticamente uma tag extra com o ID de utilizador e nome de exibição do requerente\",\n  \"components.Settings.addrule\": \"Nova regra de exceção\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Todos os fornecedores de metadados selecionados estão operacionais\",\n  \"components.Settings.animeMetadataProvider\": \"Fornecedor de metadados de anime\",\n  \"components.Settings.apiKey\": \"Chave API\",\n  \"components.Settings.chooseProvider\": \"Escolher fornecedores de metadados para diferentes tipos de conteúdo\",\n  \"components.Settings.clickTest\": \"Clique no botão \\\"Testar\\\" para verificar a conectividade com os fornecedores de metadados\",\n  \"components.Settings.connectionTestFailed\": \"Teste de ligação falhou\",\n  \"components.Settings.failed\": \"Não funciona\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Falha ao guardar definições do fornecedor de metadados\",\n  \"components.Settings.general\": \"Geral\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} não é uma palavra-chave TMDB.\",\n  \"components.Settings.invalidurlerror\": \"Não foi possível ligar ao servidor {mediaServerName}.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"URL de palavra-passe esquecida\",\n  \"components.Settings.jellyfinSettings\": \"Definições de {mediaServerName}\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Opcionalmente, configure os endpoints internos e externos do seu servidor {mediaServerName}. Na maioria dos casos, o URL externo é diferente do URL interno. Também pode ser definido um URL personalizado de reposição de palavra-passe para a autenticação em {mediaServerName}, caso pretenda redirecionar para uma página de reposição de palavra-passe diferente. Também pode alterar a chave API do Jellyfin, que foi gerada automaticamente anteriormente.\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Ocorreu um erro ao guardar as definições de {mediaServerName}.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"Definições de {mediaServerName} guardadas com sucesso!\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Autenticação personalizada com agrupamento automático de bibliotecas não é suportada\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Ocorreu um erro ao sincronizar as bibliotecas\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Nenhuma biblioteca foi encontrada\",\n  \"components.Settings.jellyfinlibraries\": \"Bibliotecas {mediaServerName}\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"As bibliotecas que o {mediaServerName} analisa para encontrar títulos. Clique no botão abaixo se nenhuma biblioteca estiver listada.\",\n  \"components.Settings.jellyfinsettings\": \"Definições de {mediaServerName}\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Configure as definições do seu servidor {mediaServerName}. O {mediaServerName} analisa as suas bibliotecas {mediaServerName} para ver que conteúdo está disponível.\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalmente, isto só será executado uma vez a cada 24 horas. O Seerr verificará os itens adicionados recentemente no seu servidor {mediaServerName} de forma mais agressiva. Se for a primeira vez que está a configurar o Seerr, recomenda-se uma análise completa e manual única das bibliotecas!\",\n  \"components.Settings.manualscanJellyfin\": \"Scan manual de bibliotecas\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.menuMetadataProviders\": \"Fornecedores de metadados\",\n  \"components.Settings.menuNetwork\": \"Rede\",\n  \"components.Settings.metadataProviderSelection\": \"Seleção de fornecedores de metadados\",\n  \"components.Settings.metadataProviderSettings\": \"Fornecedores de metadados\",\n  \"components.Settings.metadataSettings\": \"Definições do fornecedor de metadados\",\n  \"components.Settings.metadataSettingsSaved\": \"Definições do fornecedor de metadados guardadas\",\n  \"components.Settings.no\": \"Não\",\n  \"components.Settings.noSpecialCharacters\": \"A configuração deve ser uma lista de IDs de palavras-chave TMDB delimitada por vírgulas, e não deve começar nem terminar com uma vírgula.\",\n  \"components.Settings.nooptions\": \"Sem resultados.\",\n  \"components.Settings.notTested\": \"Não testado\",\n  \"components.Settings.operational\": \"Operacional\",\n  \"components.Settings.overrideRules\": \"Regras de exceção\",\n  \"components.Settings.overrideRulesDescription\": \"As regras de exceção permitem especificar propriedades que serão substituídas se um pedido corresponder à regra.\",\n  \"components.Settings.providerStatus\": \"Status do fornecedor de metadados\",\n  \"components.Settings.save\": \"Guardar alterações\",\n  \"components.Settings.saving\": \"Guardando…\",\n  \"components.Settings.scanbackground\": \"A análise será executada em segundo plano. Pode continuar o processo de configuração entretanto.\",\n  \"components.Settings.searchKeywords\": \"Pesquisar palavras-chave…\",\n  \"components.Settings.seriesMetadataProvider\": \"Fornecedor de metadados de séries\",\n  \"components.Settings.settings\": \"Definições\",\n  \"components.Settings.starttyping\": \"Comece a escrever para pesquisar.\",\n  \"components.Settings.syncJellyfin\": \"Sincronizar bibliotecas\",\n  \"components.Settings.syncing\": \"A sincronizar\",\n  \"components.Settings.timeout\": \"Tempo esgotado\",\n  \"components.Settings.tip\": \"Dica\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"O fornecedor TMDB não funciona, por favor selecione outro fornecedor de metadados\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"O fornecedor TVDB não funciona, por favor selecione outro fornecedor de metadados\",\n  \"components.Settings.valueRequired\": \"Deve fornecer um valor.\",\n  \"components.Settings.yes\": \"Sim\",\n  \"components.Setup.back\": \"Voltar\",\n  \"components.Setup.configemby\": \"Configurar Emby\",\n  \"components.Setup.configjellyfin\": \"Configurar Jellyfin\",\n  \"components.Setup.configplex\": \"Configurar Plex\",\n  \"components.Setup.configuremediaserver\": \"Configurar servidor de média\",\n  \"components.Setup.librarieserror\": \"A validação falhou. Por favor, alterne as bibliotecas novamente para continuar.\",\n  \"components.Setup.servertype\": \"Escolher tipo de servidor\",\n  \"components.Setup.signin\": \"Iniciar sessão\",\n  \"components.Setup.signinWithEmby\": \"Introduza os seus dados Emby\",\n  \"components.Setup.signinWithJellyfin\": \"Introduza os seus dados Jellyfin\",\n  \"components.Setup.signinWithPlex\": \"Introduza os seus dados Plex\",\n  \"components.Setup.subtitle\": \"Comece por escolher o seu servidor de média\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.TitleCard.addToWatchList\": \"Adicionar à lista para ver\",\n  \"components.TitleCard.watchlistCancel\": \"lista para ver para <strong>{title}</strong> cancelada.\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> foi removido da lista para ver com sucesso!\",\n  \"components.TitleCard.watchlistError\": \"Algo falhou. Por favor, tente novamente.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> foi adicionado à lista para ver com sucesso!\",\n  \"components.TvDetails.addtowatchlist\": \"Adicionar a lista para ver\",\n  \"components.TvDetails.play4k\": \"Reproduzir em 4K em {mediaServerName}\",\n  \"components.TvDetails.removefromwatchlist\": \"Remover da lista para ver\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> foi removido da lista para ver com sucesso!\",\n  \"components.TvDetails.watchlistError\": \"Algo falhou. Por favor, tente novamente.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> foi adicionado à lista para ver com sucesso!\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {userCount, plural, one {utilizador {mediaServerName} importado} other {utilizadores {mediaServerName} importados}} com sucesso!\",\n  \"components.UserList.importfromJellyfin\": \"Importar utilizadores de {mediaServerName}\",\n  \"components.UserList.importfromJellyfinerror\": \"Ocorreu um erro ao importar utilizadores de {mediaServerName}.\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName} Utilizador\",\n  \"components.UserList.newJellyfinsigninenabled\": \"A definição <strong>Ativar nova autenticação de {mediaServerName}</strong> está atualmente ativada. Os utilizadores de {mediaServerName} com acesso à biblioteca não precisam de ser importados para se autenticarem.\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Não há utilizadores de {mediaServerName} para importar.\",\n  \"components.UserList.username\": \"Nome de utilizador\",\n  \"components.UserList.validationUsername\": \"Você deve fornecer um nome de utilizador\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Introduza as suas credenciais de {mediaServerName} para associar a sua conta ao {applicationName}.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Esta conta já está associada a um utilizador de {applicationName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Não foi possível ligar a {mediaServerName} com as suas credenciais\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Ocorreu um erro desconhecido\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Palavra-passe\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Deve fornecer uma palavra-passe\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Associar\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"A adicionar…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Associar conta {mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Nome de utilizador\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Deve fornecer um nome de utilizador\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Região de descoberta\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Filtrar conteúdo por disponibilidade regional\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Utilizador {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Guardar alterações\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Guardando…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Região de streaming\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Mostrar sites de streaming por disponibilidade regional\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Este e-mail já está a ser utilizado!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Outro utilizador já tem este nome de utilizador. Deve definir um e-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"E-mail válido obrigatório\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"E-mail obrigatório\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Não foi possível eliminar a conta associada.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Ocorreu um erro desconhecido\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Contas associadas\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Estas contas externas estão associadas à sua conta {applicationName}.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Não tem nenhuma conta externa associada à sua conta.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Não tem permissão para modificar as contas associadas deste utilizador.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Esta conta já está associada a um utilizador Plex\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Não foi possível ligar ao Plex com as suas credenciais\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Navegador\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Criado\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Eliminar subscrição\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Dispositivo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Desativar web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Ocorreu um erro ao desativar web push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Ativar web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Ocorreu um erro ao ativar web push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Motor\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Gerir dispositivos\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Não tem subscrições web push para mostrar.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Sistema operativo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Subscrição eliminada.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Ocorreu um erro ao eliminar a subscrição do utilizador.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"tipo\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Desconhecido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Web push foi desativado.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Web push foi ativado.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Não foi possível guardar as definições de notificações web push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Definições de notificações web push guardadas com sucesso!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Dispositivo padrão\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Som de notificação\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"ID de tópico/thread\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Se o seu grupo tiver tópicos ativados, pode especificar o ID do tópico/thread aqui\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"O ID do tópico/thread deve ser um número inteiro positivo\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Contas associadas\",\n  \"components.UserProfile.localWatchlist\": \"Lista para ver de {username}\",\n  \"i18n.collection\": \"Coleção\",\n  \"i18n.completed\": \"Concluído\",\n  \"i18n.deleted\": \"Eliminado\",\n  \"i18n.specials\": \"Especiais\",\n  \"components.Login.port\": \"Porta\",\n  \"components.TvDetails.play\": \"Reproduzir em {mediaServerName}\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Deve ser selecionado pelo menos um método de autenticação.\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Apoiar Seerr\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Sobre Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Fazer uma contribuição\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Deve fornecer um TTL máximo válido\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Deve fornecer um TTL mínimo válido\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Subscrição ativa\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Impossível de ligar-se a {services}. Algumas informações podem não estar disponíveis.\",\n  \"component.BlocklistBlock.blocklistdate\": \"Data de bloqueio\",\n  \"component.BlocklistBlock.blocklistedby\": \"Bloqueado por\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> não está na lista de bloqueio.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Gerir média na lista de bloqueio.\",\n  \"components.Blocklist.blocklistdate\": \"data\",\n  \"components.Blocklist.blocklistedby\": \"{date} por {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Parâmetros da lista de bloqueio\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Tags bloqueadas\",\n  \"components.Blocklist.filterManual\": \"Manual\",\n  \"components.Blocklist.mediaName\": \"Nome\",\n  \"components.Blocklist.mediaTmdbId\": \"Id tmdb\",\n  \"components.Blocklist.mediaType\": \"Tipo\",\n  \"components.Blocklist.showAllBlocklisted\": \"Mostrar todos os média bloqueados\",\n  \"components.Layout.Sidebar.blocklist\": \"Lista de bloqueio\",\n  \"component.BlocklistModal.blocklisting\": \"Bloqueio\",\n  \"components.PermissionEdit.blocklistedItems\": \"Bloquear média.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Conceder permissão para bloquear média.\",\n  \"components.PermissionEdit.manageblocklist\": \"Gerir lista de bloqueio\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Conceder permissão para gerir os média na lista de bloqueio.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Ver os média bloqueados.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Conceder permissão para ver os média bloqueados.\",\n  \"components.RequestList.unableToConnect\": \"Não foi possível ligar a {services}. Algumas informações podem estar indisponíveis.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Ainda não foram armazenadas pesquisas DNS em cache.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Processar tags bloqueadas\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Bloquear conteúdo com tags\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Limitar conteúdo bloqueado por tag\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"A tarefa \\\"Processar tags bloqueadas\\\" irá bloquear esta quantidade de páginas em cada ordenação. Números maiores criarão uma lista de bloqueio mais precisa, mas usarão mais espaço.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Adicionar automaticamente conteúdo com tags à lista de bloqueio usando a tarefa \\\"Processar tags bloqueadas\\\"\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Ocultar itens bloqueados\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Ocultar itens bloqueados das páginas de descoberta para todos os utilizadores com a permissão \\\"Gerir lista de bloqueio\\\"\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Enviar TODOS os pedidos HTTP/HTTPS de saída através de um servidor proxy (anfitrião/porta). NÃO ativa configuração HTTPS, SSL ou de certificados.\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Colar a configuração de tag da lista de bloqueio abaixo.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Importar configuração de tags bloqueadas\",\n  \"components.Settings.blocklistedTagsText\": \"Tags bloqueadas\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Tem a certeza de querer limpar as tags bloqueadas?\",\n  \"components.Settings.copyBlocklistedTags\": \"Tags bloqueadas copiadas para a área de transferência.\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Nada paraa copiar\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Copiar configuração de tags bloqueadas\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Importar configuração de tags bloqueadas\",\n  \"i18n.addToBlocklist\": \"Adicionar à lista de bloqueio\",\n  \"i18n.blocklist\": \"Lista de bloqueio\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> já está na lista de bloqueio.\",\n  \"i18n.blocklistError\": \"Ocorreu um erro. Por favor, tente novamente.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> foi bloqueado com sucesso.\",\n  \"i18n.blocklisted\": \"Na lista de bloqueio\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> foi removido da lista de bloqueio com sucesso.\",\n  \"i18n.removefromBlocklist\": \"Remover da lista de bloqueio\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"Tempo limite da solicitação da API\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Tempo máximo (em segundos) para aguardar respostas de serviços externos como o Radarr/Sonarr. Defina como 0 para nenhum tempo limite.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Deve fornecer um valor de tempo limite válido\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Acompanhe as novas temporadas\"\n}\n"
  },
  {
    "path": "src/i18n/locale/ro.json",
    "content": "{\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Filme de la {studio}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Montarea volumului <code>{appDataPath}</code> nu a fost configurată corespunzător. Toate datele vor fi șterse atunci când containerul este oprit sau repornit.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Filme\",\n  \"components.CollectionDetails.overview\": \"Prezentare generală\",\n  \"components.CollectionDetails.requestcollection\": \"Solicită Colecția\",\n  \"components.CollectionDetails.requestcollection4k\": \"Solicită Colecția în 4K\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genul} Filme\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Filme\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Seriale de la {network}\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Genuri Filme\",\n  \"components.Discover.NetworkSlider.networks\": \"Rețele\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Genuri Seriale\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Editați descrierea\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Trebuie să introduceți un mesaj\",\n  \"components.IssueDetails.IssueDescription.description\": \"Descriere\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Postat {relativeTime} de {username} (Editat)\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Seriale de {genre}\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Seriale în limba {language}\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Genuri Filme\",\n  \"components.Discover.StudioSlider.studios\": \"Studiouri\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Genuri Seriale\",\n  \"components.Discover.discover\": \"Descoperă\",\n  \"components.Discover.popularmovies\": \"Filme Populare\",\n  \"components.Discover.populartv\": \"Seriale Populare\",\n  \"components.Discover.recentlyAdded\": \"Adăugate Recent\",\n  \"components.Discover.recentrequests\": \"Solicitări Recente\",\n  \"components.Discover.upcoming\": \"Filme Viitoare\",\n  \"components.Discover.upcomingmovies\": \"Filme Viitoare\",\n  \"components.Discover.upcomingtv\": \"Seriale Viitoare\",\n  \"components.DownloadBlock.estimatedtime\": \"Estimat {time}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Sunteți sigur că doriți să ștergeți acest comentariu?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Șterge comentariul\",\n  \"components.IssueDetails.IssueComment.edit\": \"Editați comentariul\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Postat {relativeTime} de {username}\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Ștergeți problema\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Lista ta de Urmărire în Plex\",\n  \"components.Discover.plexwatchlist\": \"Lista ta de Urmărire în Plex\",\n  \"components.IssueDetails.allseasons\": \"Toate sezoanele\",\n  \"components.IssueDetails.closeissue\": \"Închide problema\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Ești sigur că vrei să ștergi această problema?\",\n  \"components.IssueDetails.commentplaceholder\": \"Adaugă un comentariu…\",\n  \"components.IssueDetails.comments\": \"Comentarii\",\n  \"components.IssueDetails.issuetype\": \"Tip\",\n  \"components.IssueDetails.lastupdated\": \"Ultimul update\",\n  \"components.IssueDetails.leavecomment\": \"Comentează\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Listă de urmărire în Plex\",\n  \"components.Discover.trending\": \"Tendințe\",\n  \"components.IssueDetails.openinarr\": \"Deschide în {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Vizionează în 4K în Plex\",\n  \"components.IssueDetails.playonplex\": \"Vizionează în Plex\",\n  \"components.IssueDetails.problemepisode\": \"Episoade afectate\",\n  \"components.IssueDetails.problemseason\": \"Sezoane afectate\",\n  \"components.IssueDetails.reopenissue\": \"Redeschide problemă\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Redeschide cu comentariu\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"A intervenit o eroare în timpul editării descrierii problemei.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Descrierea problemei editată cu succes!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Problemă ștearsă cu succes!\",\n  \"components.IssueDetails.season\": \"Sezon {seasonNumber}\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"A intervenit o eroare în timpul ștergerii problemei.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Statusul problemei a fost actualizat cu succes!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"A intervenit o eroare în timpul actualizării statusului problemei.\",\n  \"components.IssueDetails.unknownissuetype\": \"Necunoscut\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, un {Episod} alte {Episoade}}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Stare\",\n  \"components.IssueList.IssueItem.opened\": \"Deschis\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Necunoscut\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} de către {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Episodul afectat\",\n  \"components.IssueList.IssueItem.viewissue\": \"Vedeți problema\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Episodul afectat\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Vă rugăm să furnizați o explicație detaliată a problemei pe care ați întâmpinat-o.\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Sezonul afectat\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episodul {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extra\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Sezonul {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Trimiteți problema\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Ceva nu a mers bine în timpul trimiterii problemei.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Raportul problemei pentru <strong>{title}</strong> a fost trimis cu succes!\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Ce nu e bine?\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueModal.issueOther\": \"Altele\",\n  \"components.IssueModal.issueSubtitles\": \"Subtitrare\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.LanguageSelector.languageServerDefault\": \"Implicit ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Toate limbile\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Limba de afișare\",\n  \"components.Layout.Sidebar.dashboard\": \"Descoperiți\",\n  \"components.Layout.Sidebar.issues\": \"Probleme\",\n  \"components.Layout.Sidebar.requests\": \"Solicitări\",\n  \"components.Layout.Sidebar.settings\": \"Setări\",\n  \"components.Layout.Sidebar.users\": \"Utilizatori\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} altul {commits}} în spate\",\n  \"components.IssueDetails.allepisodes\": \"Toate episoadele\",\n  \"components.IssueDetails.episode\": \"Episod {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Problemă\",\n  \"components.IssueDetails.openedby\": \"#{issueId} deschis {relativeTime} de către {username}\",\n  \"components.IssueDetails.openin4karr\": \"Deschide în 4K {arr}\",\n  \"components.AirDateBadge.airedrelative\": \"Difuzat la {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Se va difuza la {relativeTime}\",\n  \"components.IssueList.issues\": \"Probleme\",\n  \"components.IssueList.showallissues\": \"Afișați toate problemele\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Toate sezoanele\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Raportați o problemă\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Vedeți problema\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Solicitări de Seriale\",\n  \"components.Layout.UserDropdown.requests\": \"Solicitări\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tip\",\n  \"components.IssueList.sortModified\": \"Ultima modificare\",\n  \"components.Discover.emptywatchlist\": \"Media adăugată în <PlexWatchlistSupportLink>Lista de Urmărire Plex</PlexWatchlistSupportLink> va apărea aici.\",\n  \"components.IssueDetails.closeissueandcomment\": \"Închide cu comentariu\",\n  \"components.IssueDetails.deleteissue\": \"Șterge problema\",\n  \"components.IssueDetails.nocomments\": \"Niciun comentariu.\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Toate episoadele\",\n  \"components.IssueList.sortAdded\": \"Cele mai recente\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Căutați Filme și Seriale\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Trebuie să furnizați o descriere\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Solicitări de Filme\",\n  \"components.Layout.UserDropdown.settings\": \"Setări\",\n  \"components.Layout.UserDropdown.signout\": \"Deconectare\",\n  \"components.Layout.VersionStatus.outofdate\": \"Expirat\",\n  \"components.Login.loginerror\": \"A apărut o eroare în timp ce încercam să vă conectați.\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avansat\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.ManageSlideOver.openarr\": \"Deschide în {arr}\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Primiți notificări când problemele sunt rezolvate de alți utilizatori.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Comentariu la Problemă\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Trimiteți notificări când problemele sunt redeschise.\",\n  \"components.MovieDetails.digitalrelease\": \"Lansare Digitală\",\n  \"components.MovieDetails.originaltitle\": \"Titlu Original\",\n  \"components.MovieDetails.overview\": \"Prezentare Generală\",\n  \"components.MovieDetails.recommendations\": \"Recomandări\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Data de Lansare} other {Date de Lansare}}\",\n  \"components.MovieDetails.revenue\": \"Venituri\",\n  \"components.MovieDetails.runtime\": \"{minutes} minute\",\n  \"components.MovieDetails.showless\": \"Arată Mai Puțin\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studiouri}}\",\n  \"components.MovieDetails.theatricalrelease\": \"Lansare la Cinema\",\n  \"components.MovieDetails.viewfullcrew\": \"Vizualizați Echipa Completă\",\n  \"components.MovieDetails.streamingproviders\": \"În Prezent se Difuzează pe\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Trimiteți notificări când problemele primesc comentarii noi.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problemă Raportată\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problemă Rezolvată\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Trimiteți notificări când problemele sunt rezolvate.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Solicitare Aprobată Automat\",\n  \"components.Login.email\": \"Adresă de Mail\",\n  \"components.Login.forgotpassword\": \"Ai uitat parola?\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Nicio solicitare.\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Administrează {mediaType}\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Solicitări\",\n  \"components.MovieDetails.overviewunavailable\": \"Prezentare Generală Indisponibilă.\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Trimiteți notificări când sunt raportate probleme.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problemă Redeschisă\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Sezon} other {Sezoane}}\",\n  \"components.Login.signinwithplex\": \"Folosește contul tău Plex\",\n  \"components.Login.validationemailrequired\": \"Trebuie să furnizați o adresă de e-mail validă\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Probleme Deschise\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Golește Datele\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Media\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Media 4K\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Marcați ca Disponibil în 4K\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Marcați Toate Sezoanele ca fiind Disponibile în 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Marcați Toate Sezoanele ca Disponibile\",\n  \"components.ManageSlideOver.markavailable\": \"Marcați ca Disponibil\",\n  \"components.MovieDetails.originallanguage\": \"Limbă Originală\",\n  \"components.MovieDetails.showmore\": \"Arată Mai Mult\",\n  \"components.MovieDetails.similar\": \"Titluri Similare\",\n  \"components.MovieDetails.physicalrelease\": \"Lansare Fizică\",\n  \"components.MovieDetails.managemovie\": \"Gestionați Filmul\",\n  \"components.MovieDetails.reportissue\": \"Raportează o Problemă\",\n  \"components.Login.password\": \"Parolă\",\n  \"components.Login.signin\": \"Autentificare\",\n  \"components.Login.signingin\": \"Se autentifică…\",\n  \"components.Login.signinheader\": \"Autentifică-te pentru a continua\",\n  \"components.Login.signinwithoverseerr\": \"Folosește contul tău pentru {applicationTitle}\",\n  \"components.Login.validationpasswordrequired\": \"Trebuie să furnizați o parolă\",\n  \"components.MovieDetails.markavailable\": \"Marcați ca Disponibil\",\n  \"components.MovieDetails.rtaudiencescore\": \"Scorul Publicului pe Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatometru pe Rotten Tomatoes\",\n  \"components.MovieDetails.tmdbuserscore\": \"Scor Utilizatori pe TMDB\",\n  \"components.ManageSlideOver.pastdays\": \"Acum {days, number} Zile\",\n  \"components.ManageSlideOver.opentautulli\": \"Deschide în Tautilli\",\n  \"components.ManageSlideOver.tvshow\": \"seriale\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Vezi Mai Mult\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Distribuție Completă\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Echipaj Complet\",\n  \"components.MovieDetails.budget\": \"Buget\",\n  \"components.MovieDetails.cast\": \"Distribuție\",\n  \"components.MovieDetails.mark4kavailable\": \"Marcați ca Disponibil în 4K\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Primiți notificări când problemele sunt redeschise de alți utilizatori.\",\n  \"components.MovieDetails.watchtrailer\": \"Vizionați Trailerul\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Primiți notificări când alți utilizatori comentează la probleme.\",\n  \"components.ManageSlideOver.downloadstatus\": \"Descărcări\",\n  \"components.ManageSlideOver.openarr4k\": \"Deschide în {arr} 4k\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Aceasta va elimina ireversibil toate datele pentru {mediaType}, inclusiv orice solicitare. Dacă acest articol există în biblioteca dvs. Plex, informațiile media vor fi recreate în timpul următoarei scanări.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Primiți notificări când problemele pe care le-ați raportat sunt redeschise.\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Acordați permisiunea de a modifica opțiunile avansate de solicitare media.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Trimiteți notificări atunci când utilizatorii trimit noi solicitări media care sunt aprobate automat.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Solicitare Disponibilă\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Trimiteți notificări când solicitările media devin disponibile.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Solicitare Aprobată\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Trimiteți notificări când solicitările media sunt aprobate manual.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Solicitare Refuzată\",\n  \"components.PermissionEdit.admin\": \"Admin\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Primiți notificări când solicitările dvs. media sunt aprobate.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Primiți notificări când solicitările dvs. media devin disponibile.\",\n  \"components.PermissionEdit.adminDescription\": \"Acces de administrator complet. Ocolește toate celelalte verificări ale permisiunilor.\",\n  \"components.PermissionEdit.advancedrequest\": \"Solicitări Avansate\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Solicitare Trimisă Automat\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Primiți notificări atunci când noi solicitări media sunt trimise automat pentru articole din Lista dvs. de Urmărire Plex.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Procesarea Solicitării Eșuată\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Trimiteți notificări atunci când solicitările media nu pot fi adăugate la Radarr sau Sonarr.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Solicitarea Așteptă Aprobare\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Trimiteți notificări atunci când utilizatorii trimit noi solicitări media care necesită aprobare.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Tipuri de Notificări\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Primiți notificări când problemele pe care le-ați raportat primesc comentarii noi.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Primiți notificări când alți utilizatori raportează probleme.\",\n  \"components.PermissionEdit.autoapprove\": \"Aprobare Automată\",\n  \"components.PermissionEdit.autoapprove4k\": \"Aprobare Automată 4K\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Acordați aprobare automată pentru toate solicitările media 4K.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Aprobare Automată a Filmelor 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Acordați aprobare automată pentru solicitările de filme 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Aprobare Automată a Serialelor 4K\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Acordați aprobare automată pentru toate solicitările media non-4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Aprobare Automată a Filmelor\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Trimiteți notificări atunci când solicitările media sunt refuzate.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Primiți notificări atunci când alți utilizatori trimit noi solicitări media care necesită aprobare.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Primiți notificări când solicitările media nu pot fi adăugate la Radarr sau Sonarr.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Acordați aprobare automată pentru solicitările de seriale non-4K.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Primiți notificări când alți utilizatori trimit solicitări media noi, care sunt aprobate automat.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Primiți notificări când solicitările dvs. media sunt refuzate.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Acordați aprobare automată pentru solicitările de seriale 4K.\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Acordați aprobare automată pentru solicitările de filme non-4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Aprobare Automată a Serialelor\",\n  \"components.PermissionEdit.autorequestDescription\": \"Acordați permisiunea de a trimite automat solicitări pentru conținut media non-4K prin Lista de Urmărire Plex.\",\n  \"components.PermissionEdit.autorequest\": \"Solicitare Automată\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Primiți notificări când problemele pe care le-ați raportat sunt rezolvate.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Solicitați Automat Filme\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Acordați permisiunea de a trimite automat solicitări pentru filme non-4K prin Lista de Urmărire Plex.\",\n  \"components.MovieDetails.productioncountries\": \"Producție {countryCount, plural, one {Țară} other {Țări}}\",\n  \"components.PermissionEdit.request\": \"Solicitați\",\n  \"components.PermissionEdit.request4kDescription\": \"Acordați permisiunea de a trimite solicitări pentru conținut media 4K.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Acordați permisiunea de a gestiona solicitările media. Toate solicitările făcute de un utilizator cu această permisiune vor fi aprobate automat.\",\n  \"components.PermissionEdit.request4k\": \"Solicitați 4K\",\n  \"components.PermissionEdit.request4kTv\": \"Solicitați Seria TV în 4K\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stabil\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Acordați permisiunea de a trimite solicitări pentru filme 4K.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Acordați permisiunea de a raporta probleme media.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Solicită Automat Seriale TV\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Acordați permisiunea de a trimite automat solicitări pentru seriale tv non-4K prin Lista de Urmărire Plex.\",\n  \"components.PermissionEdit.createissues\": \"Raportați Probleme\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Acordați permisiunea de a gestiona problemele media.\",\n  \"components.PermissionEdit.managerequests\": \"Gestionați Solicitările\",\n  \"components.PermissionEdit.request4kMovies\": \"Solicitați Filme 4K\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Dezvoltat\",\n  \"components.PermissionEdit.manageissues\": \"Gestionarea Problemelor\",\n  \"components.ManageSlideOver.playedby\": \"Rulat De\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {rulare} other {rulări}}\",\n  \"components.ManageSlideOver.alltime\": \"Dintotdeauna\",\n  \"components.Discover.CreateSlider.addSlider\": \"Adaugă Slider\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Crează Slider Personalizat\",\n  \"components.Discover.CreateSlider.addfail\": \"Nu s-a putut crea un nou slider.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"S-a creat un nou slider și s-au salvat setările de personalizare a descoperirii.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Modifică Slider\",\n  \"components.Discover.CreateSlider.editfail\": \"Nu s-a putut modifica sliderul.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Sliderul modificat și setările de personalizare pentru descoperire salvate.\",\n  \"components.Discover.CreateSlider.needresults\": \"Trebuie să aveți cel puțin 1 rezultat.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Fără rezultate.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Furnizați un ID de gen de la TMDB\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Furnizați un ID de cuvânt cheie de la TMDB\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Furnizați ID-ul rețelei TMDB\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Furnizați o interogare de căutare\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Furnizați un ID de studio de pe TMDB\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Căutați genuri…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Căutați cuvinte cheie…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Căutați studiouri…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Nume Slider\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Media adăugată la <PlexWatchlistSupportLink>Lista de urmărire Plex</PlexWatchlistSupportLink> va apărea aici.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Filme\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"Seriale care conțin {keywordTitle}\",\n  \"components.Discover.networks\": \"Rețele\",\n  \"components.Discover.resetfailed\": \"A apărut o eroare la resetarea setărilor de personalizare a descoperirii.\",\n  \"components.Discover.resetsuccess\": \"Resetat cu succes setările de personalizare a descoperirii.\",\n  \"components.Discover.resettodefault\": \"Resetare la valorile implicite\",\n  \"components.Discover.CreateSlider.starttyping\": \"Începe să tastezi pentru a căuta.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Trebuie să furnizați un titlu.\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Ștergeți Filtrele Active\",\n  \"components.Discover.FilterSlideover.genres\": \"Genuri\",\n  \"components.Discover.resetwarning\": \"Resetați toate sliderele la valoarea implicită. Acest lucru va șterge și orice slider personalizat!\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, un {# Active Filter} alte {# Active Filters}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filme\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularitate Crescătoare\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularitate Descrescătoare\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Data Lansării Crescător\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Data Lansării Descrescător\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Titlu (A-Z) Crescător\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Titlu (Z-A) Descrescător\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Evaluare TMDB Crescător\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Evaluare TMDB Descrescător\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Sliderul nu a fost șters.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Sliderul a fost șters.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Comutați Vizibilitatea\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Elimină\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, un {# Active Filter} alte {# Active Filters}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Seriale\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Prima Dată de Difuzare Ascendent\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Prima Dată de Difuzare Descendent\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularitate Crescătoare\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularitate Descrescătoare\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Titlu (A-Z) Crescător\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Titlu (Z-A) Descrescător\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Evaluare TMDB Crescător\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Evaluare TMDB Descrescător\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, un {# Active Filter} alte {# Active Filters}}\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtre\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Prima Dată de Difuzare\",\n  \"components.Discover.FilterSlideover.from\": \"De la\",\n  \"components.Discover.FilterSlideover.keywords\": \"Cuvinte Cheie\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Limbă Originală\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Evaluări între {minValue} și {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Dată Lansare\",\n  \"components.Discover.FilterSlideover.runtime\": \"Timp Rulare\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minute de rulare\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Scorul Utilizatorilor pe TMDB\",\n  \"components.Discover.customizediscover\": \"Personalizați Discoperirea\",\n  \"components.Discover.moviegenres\": \"Genuri Film\",\n  \"components.Discover.stopediting\": \"Opriți Modificarea\",\n  \"components.Discover.createnewslider\": \"Creați un Nou Slider\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Servicii de Streaming\",\n  \"components.Discover.FilterSlideover.to\": \"La\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Listă Urmărite pe Plex\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Recent Adăugate\",\n  \"components.Discover.studios\": \"Studiouri\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Trebuie să furnizați o valoare a datelor.\",\n  \"components.Layout.Sidebar.browsetv\": \"Seriale\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filme\",\n  \"components.Discover.tmdbmoviekeyword\": \"Cuvânt cheie al filmului de pe TMDB\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Numărul de voturi ale utilizatorilor pe TMDB\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Număr de voturi între {minValue} și {maxValue}\",\n  \"components.Discover.tmdbnetwork\": \"Rețea de pe TMDB\",\n  \"components.Discover.tmdbsearch\": \"Căutare pe TMDB\",\n  \"components.Discover.tmdbmoviegenre\": \"Gen Film de pe TMDB\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Servicii Streaming Filme de pe TMDB\",\n  \"components.Discover.tmdbtvgenre\": \"Gen Seriale de pe TMDB\",\n  \"components.Selector.searchStudios\": \"Caută studiouri…\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Rețea} other {Rețele}}\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Acest serial este un anime.\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Sezon {seasonNumber} Episod {episodeNumber}\",\n  \"components.Discover.tvgenres\": \"Genuri Seriale\",\n  \"components.Discover.tmdbtvkeyword\": \"Cuvânt Cheie Seriale de pe TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Servicii Streaming TV de pe TMDB\",\n  \"components.PermissionEdit.requestTv\": \"Solicită Seria\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Regiune Descoperire\",\n  \"components.Discover.updatefailed\": \"A apărut o eroare la actualizarea setărilor de personalizare a descoperirii.\",\n  \"components.Discover.updatesuccess\": \"Setări de personalizare a descoperirii actualizate.\",\n  \"components.Discover.tmdbstudio\": \"Studio de pe TMDB\",\n  \"components.PermissionEdit.requestDescription\": \"Acordați permisiunea de a face cereri pentru seriale non-4K.\",\n  \"components.MovieDetails.imdbuserscore\": \"Scor Utilizator IMDB - voturi: {formattedCount}\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Acordați permisiunea de a face cereri pentru seriale 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Solicită Filme\",\n  \"components.PermissionEdit.requestTvDescription\": \"Acordați permisiunea de a trimite solicitări pentru seriale non-4K.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Limbă Descoperire\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Limbă Descoperire\",\n  \"components.PermissionEdit.usersDescription\": \"Acordați permisiunea de a gestiona utilizatorii. Utilizatorii cu această permisiune nu pot modifica utilizatorii cu sau acorda privilegiul de administrator.\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} per {quotaDays} {days}</quotaUnits>\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, un {Season} alte {Seasons}}\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Acordați permisiunea de a trimite solicitări pentru filme non-4K.\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Acordați permisiunea de a vizualiza problemele media raportate de alți utilizatori.\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Acordați permisiunea de a vizualiza listele de urmărire Plex ale altor utilizatori.\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, un {season} alte {seasons}}\",\n  \"components.RequestBlock.requestoverrides\": \"Înlocuiri Solicitate\",\n  \"components.PersonDetails.ascharacter\": \"ca {character}\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Acordați permisiunea de a vizualiza lista cu conținut media adăugat recent.\",\n  \"components.PermissionEdit.viewrequests\": \"Vizualizați Solicitările\",\n  \"components.PermissionEdit.viewrecent\": \"Vezi Adăugate Recent\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Acordați permisiunea de a vizualiza solicitările media trimise de alți utilizatori.\",\n  \"components.RequestBlock.rootfolder\": \"Dosar Rădăcină\",\n  \"components.PermissionEdit.viewwatchlists\": \"Vizualizați Listele de Urmărire Plex\",\n  \"components.PersonDetails.appearsin\": \"Aparențe\",\n  \"components.PersonDetails.crewmember\": \"Echipa\",\n  \"components.PersonDetails.birthdate\": \"Născut {birthdate}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, un {movie} alte {movies}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.unlimited\": \"Nelimitat\",\n  \"components.RegionSelector.regionDefault\": \"Toate Regiunile\",\n  \"components.RequestBlock.languageprofile\": \"Limba de Profil\",\n  \"components.RequestBlock.server\": \"Server Destinatar\",\n  \"components.PermissionEdit.users\": \"Gestionare Utilizatori\",\n  \"components.PermissionEdit.viewissues\": \"Vedeți Problemele\",\n  \"components.QuotaSelector.days\": \"{count, plural, o {day} alte {days}}\",\n  \"components.PersonDetails.alsoknownas\": \"Cunoscut și ca: {names}\",\n  \"components.RegionSelector.regionServerDefault\": \"Mod Implicit ({region})\",\n  \"components.RequestBlock.delete\": \"Șterge Solicitarea\",\n  \"components.RequestBlock.edit\": \"Modifică Solicitarea\",\n  \"components.RequestBlock.approve\": \"Aprobă Solicitarea\",\n  \"components.RequestBlock.decline\": \"Respinge Solicitarea\",\n  \"components.RequestBlock.requestedby\": \"Solicitat de\",\n  \"components.RequestButton.approve4krequests\": \"Aprobă {requestCount, plural, o {4K Request} alte {{requestCount} 4K Requests}}\",\n  \"components.RequestBlock.lastmodifiedby\": \"Ultima Dată Modificat de\",\n  \"components.RequestBlock.profilechanged\": \"Profil Calitate\",\n  \"components.RequestBlock.requestdate\": \"Dată Solicitare\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Este necesara o adresa de email.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Este necesara o parola.\",\n  \"components.Login.credentialerror\": \"Numele de utilizator sau parola sunt incorecte.\",\n  \"components.Login.emailtooltip\": \"Nu este necesar ca adresa ta sa fie asociata cu instanta ta {mediaServerName} .\",\n  \"components.Login.save\": \"Adauga\",\n  \"components.Login.signinwithjellyfin\": \"Foloseste-ti contul de {mediaServerName}\",\n  \"components.Login.title\": \"Adauga email\",\n  \"components.Login.username\": \"Nume utilizator\",\n  \"components.Login.validationEmailFormat\": \"Adresa email invalida\",\n  \"components.Login.validationemailformat\": \"Necesar email valid\",\n  \"components.Login.validationhostformat\": \"Necesar URL valid\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL necesar\",\n  \"components.Login.validationusernamerequired\": \"Nume utilizator necesar\",\n  \"components.MovieDetails.downloadstatus\": \"Status descarcare\",\n  \"components.MovieDetails.openradarr\": \"Deschide film in Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"Deschide film in 4K Radarr\",\n  \"components.MovieDetails.play\": \"Ruleaza pe {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Ruleaza 4k pe {mediaServerName}\",\n  \"components.RequestButton.declinerequest\": \"Refuzați Solicitare\",\n  \"components.RequestButton.declinerequest4k\": \"Refuzați Solicitare 4k\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Adresa de email este invalida.\",\n  \"components.Login.description\": \"Deoarece este prima ta authentificare in {applicationName}, este necesara sa introduci o adresa de email valida.\",\n  \"components.Login.initialsigningin\": \"Se conecteaza…\",\n  \"components.Login.saving\": \"Se adauga…\",\n  \"components.RequestButton.approverequest\": \"Aproba cerere\",\n  \"components.RequestButton.approverequest4k\": \"Aproba cerere 4k\",\n  \"components.Login.initialsignin\": \"Conecteaza-te\",\n  \"components.ManageSlideOver.removearr4k\": \"Elimina din 4K {arr}\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Acesta va elimina ireversibil {mediaType} din {arr}, incluzand toate fisierele asociate.\",\n  \"components.Login.validationEmailRequired\": \"Trebuie sa introduci o adresa email\",\n  \"components.ManageSlideOver.removearr\": \"Elimina din {arr}\",\n  \"components.Login.invalidurlerror\": \"Conectarea la serverul {mediaServerName} nu a fost posibilă.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avansat\",\n  \"components.MovieDetails.removefromwatchlist\": \"Eliminați din lista de favorite\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Vi se permite să solicitați <strong>{limit}</strong> {type} la <strong>{days}</strong> zile.\",\n  \"components.RequestModal.approve\": \"Aprobați Solicitare\",\n  \"components.RequestModal.errorediting\": \"Ceva nu a funcționat în cursul editării solicitării.\",\n  \"components.RequestModal.selectseason\": \"Selectați Sezoane\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Trebuie să selectați cel puțin un tip de notificare\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Profil Limbă\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Trebuie să aveți cel puțin <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} rămase pentru a putea trimite o solicitare pentru această serie.\",\n  \"components.RequestModal.requestmovies\": \"Solicitați {count} {count, plural, one {Movie} alte {Movies}}\",\n  \"components.ResetPassword.confirmpassword\": \"Confirmați Parola\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Un link de resetare a parolei va fi trimis la adresa de e-mail furnizată dacă aceasta este asociată cu un utilizator valid.\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Parola este prea scurtă;ar trebui să aibă minim 8 caractere\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Setările de notificare Pushbullet nu au reușit să fie salvate.\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> Eliminat cu succes din lista de favorite!\",\n  \"components.RequestButton.decline4krequests\": \"Refuzați {requestCount, plural, one {4K Request} alte {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.declinerequests\": \"Refuzați {requestCount, plural, one {Request} alte {{requestCount} Requests}}\",\n  \"components.RequestList.RequestItem.failedretry\": \"Ceva nu a funcționat în cursul reintroducerii solicitării.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Nu am reușit să găsim automat un rezultat pentru aceast serial. Vă rugăm să selectați mai jos rezultatul corect.\",\n  \"components.RequestModal.edit\": \"Editați Solicitare\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Setările de notificare Gotify nu au reușit să fie salvate.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Puteți vizualiza un rezumat al limitelor de solicitare ale acestui utilizator pe pagina sa <ProfileLink>profile</ProfileLink>.\",\n  \"components.Selector.showmore\": \"Afișează mai mult\",\n  \"components.RequestCard.tmdbid\": \"ID TMDB\",\n  \"components.RequestCard.tvdbid\": \"ID TheTVDB\",\n  \"components.ResetPassword.email\": \"Adresă Email\",\n  \"components.Login.adminerror\": \"Trebuie să utilizați un cont de administrator pentru a vă conecta.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> adăugat cu succes la lista de favorite!\",\n  \"components.Login.back\": \"Înapoi\",\n  \"components.Login.enablessl\": \"Utilizați SSL\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.servertype\": \"Tip Server\",\n  \"components.Login.urlBase\": \"Bază URL\",\n  \"components.Login.validationPortRequired\": \"Trebuie să introduceți un număr de port valid\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"Baza URL trebuie să aibă la început o bară oblică\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"Baza URL nu trebuie să se termine cu o bară oblică\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL-ul nu trebuie să se termine cu o bară oblică\",\n  \"components.Login.validationservertyperequired\": \"Selectați un tip de server\",\n  \"components.MovieDetails.addtowatchlist\": \"Adăugați la lista de favorite\",\n  \"components.MovieDetails.watchlistError\": \"Ceva nu a funcționat. Încercați din nou.\",\n  \"components.RequestButton.approverequests\": \"Aprobați {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.requestmore\": \"Solicitați mai multe\",\n  \"components.RequestButton.requestmore4k\": \"Solicitați mai multe în 4K\",\n  \"components.RequestButton.viewrequest\": \"Vizualizați Solicitarea\",\n  \"components.RequestCard.approverequest\": \"Aprobați Solicitarea\",\n  \"components.RequestCard.cancelrequest\": \"Anulați Solicitarea\",\n  \"components.RequestCard.declinerequest\": \"Refuzați Solicitarea\",\n  \"components.RequestButton.viewrequest4k\": \"Vizualizați Solicitare 4k\",\n  \"components.RequestCard.deleterequest\": \"Ștergeți Solicitarea\",\n  \"components.RequestCard.editrequest\": \"Editați Solicitarea\",\n  \"components.RequestCard.failedretry\": \"Ceva nu a funcționat în cursul reintroducerii solicitării.\",\n  \"components.RequestCard.mediaerror\": \"Nu a fost găsit\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Season} alte {Seasons}}\",\n  \"components.RequestCard.unknowntitle\": \"Titlu Necunoscut\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Anulați Solicitarea\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Ștergeți Solicitarea\",\n  \"components.RequestList.RequestItem.editrequest\": \"Editați Solicitarea\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} Nu a fost găsit\",\n  \"components.RequestList.RequestItem.modified\": \"Modificat\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} de la {user}\",\n  \"components.RequestList.RequestItem.profileName\": \"Profil\",\n  \"components.RequestList.RequestItem.requested\": \"Solicitat\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Solicitat\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Season} alte {Seasons}}\",\n  \"components.RequestList.RequestItem.tmdbid\": \"ID TMDB\",\n  \"components.RequestList.RequestItem.tvdbid\": \"ID TheTVDB\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Titlu Necunoscut\",\n  \"components.RequestList.requests\": \"Solicitări\",\n  \"components.RequestList.showallrequests\": \"Afișează toate Solicitările\",\n  \"components.RequestList.sortAdded\": \"Recente\",\n  \"components.RequestList.sortModified\": \"Ultima Modificare\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Default)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Server de destinație\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Fără etichete.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Profil Calitate\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Solicitați ca\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Folder Root\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Selectați etichete\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Etichete\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Acest utilizator poate solicita <strong>{limit}</strong> {type} la <strong>{days}</strong> zile.\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {movie} alte {movies}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Nu au mai rămas suficiente solicitări de sezon\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Puteți vizualiza un rezumat al limitelor solicitărilor dvs. pe <ProfileLink>pagina de profil</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {No} alte {<strong>#</strong>}} {type} {remaining, plural, one {request} alte {requests}} rămase\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Acest utilizator trebuie să aibă cel puțin<strong>{seasons}</strong> {seasons, plural, one {season request} alte {season requests}}rămase pentru a putea trimite o solicitare pentru această serie.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"sezon\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {season} alte {seasons}}\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Nu am putut găsi un rezultat pentru aceast serial.\",\n  \"components.RequestModal.alreadyrequested\": \"Solicitat Deja\",\n  \"components.RequestModal.autoapproval\": \"Aprobare Automată\",\n  \"components.RequestModal.cancel\": \"Anulați Solicitare\",\n  \"components.RequestModal.numberofepisodes\": \"# de Episoade\",\n  \"components.RequestModal.pending4krequest\": \"Solicitare 4K în așteptare\",\n  \"components.RequestModal.pendingapproval\": \"Solicitarea dvs. este în curs de aprobare.\",\n  \"components.RequestModal.pendingrequest\": \"Solicitare în așteptare\",\n  \"components.RequestModal.requestApproved\": \"Solicitarea pentru <strong>{title}</strong> a fost aprobată!\",\n  \"components.RequestModal.requestCancel\": \"Solicitarea pentru <strong>{title}</strong> a fost anulată.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> a fost aprobat cu success!\",\n  \"components.RequestModal.requestadmin\": \"Această solicitare va fi aprobată automat.\",\n  \"components.RequestModal.requestcancelled\": \"Solicitarea pentru <strong>{title}</strong> anulată.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Solicitare Colecție în 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Solicitați Colecție\",\n  \"components.RequestModal.requestedited\": \"Solicitarea pentru <strong>{title}</strong> editată cu success!\",\n  \"components.RequestModal.requesterror\": \"Ceva nu a funcționat în cursul trimiterii solicitării.\",\n  \"components.RequestModal.requestfrom\": \"Solicitarea lui {username} este în curs de aprobare.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Solicitați Filmul în 4K\",\n  \"components.RequestModal.requestmovies4k\": \"Solicitati {count} {count, plural, one {Movie} late {Movies}} în 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Solicitați Film\",\n  \"components.RequestModal.requestseries4ktitle\": \"Solicitați Serial în 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Solicitați Serial\",\n  \"components.RequestModal.season\": \"Sezon\",\n  \"components.RequestModal.seasonnumber\": \"Sezonul {number}\",\n  \"components.RequestModal.selectmovies\": \"Selectați FIlm(e)\",\n  \"components.ResetPassword.emailresetlink\": \"Link Recuperare Email\",\n  \"components.ResetPassword.gobacklogin\": \"Reveniți la pagina de înscriere\",\n  \"components.ResetPassword.password\": \"Parola\",\n  \"components.ResetPassword.passwordreset\": \"Resetare Parolă\",\n  \"components.ResetPassword.resetpassword\": \"Resetați parola\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Parolă resetată cu success!\",\n  \"components.ResetPassword.validationemailrequired\": \"Trebuie să furnizați o adresă de e-mail validă\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Parolele trebuie să fie identice\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Trebuie să furnizați o parolă\",\n  \"components.Search.search\": \"Căutare\",\n  \"components.Search.searchresults\": \"Rezultate Căutare\",\n  \"components.Selector.canceled\": \"Anulat\",\n  \"components.Selector.ended\": \"Terminat\",\n  \"components.Selector.inProduction\": \"In Productie\",\n  \"components.Selector.nooptions\": \"Fără rezultate.\",\n  \"components.Selector.pilot\": \"Pilot\",\n  \"components.Selector.planned\": \"Planificat\",\n  \"components.Selector.returningSeries\": \"Serial care revine\",\n  \"components.Selector.searchGenres\": \"Selectați genurile…\",\n  \"components.Selector.searchKeywords\": \"Cautați cuvinte cheie…\",\n  \"components.Selector.searchStatus\": \"Selectați status...\",\n  \"components.Selector.showless\": \"Afișează mai puțin\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Activați Agentul\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Setările de notificare Gotify au fost salvate cu success!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Setările de notificare Gotify nu au reușit să fie trimise.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Trimitere test notificare Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Testul de notificare Gotify a fost trimis!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token Aplicație\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Server URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Trebuie să furnizați un token de aplicație\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Trebuie să furnizați un URL valid\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL-ul nu trebuie să se termine cu o bară oblică\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Token Acces\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Etichetă Canal\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Setările de notificare Pushbullet au fost salvate cu success!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Trimitere test notificare Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Activați Agentul\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Testul de notificare Pushbullet a fost trimis!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Trebuie să furnizați un token de acces\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Trebuie să selectați cel puțin un tip de notificare\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token API Aplicație\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Înregistrează o aplicație</ApplicationRegistrationLink> pentru a fi utilizată cu Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Activați Agentul\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Dispozitiv Implicit\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Setările de notificare Pushover nu au reușit să fie salvate.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Setările de notificare Pushover au fost salvate cu success!\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Sunet Notificare\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Trimitere test notificare Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Testul de notificare Pushover a fost trimis!\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Cheie Utilizator sau Group\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Trebuie să furnizați un token de acces valid\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Trebuie să selectați cel puțin un tip de notificare\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Trebuie să furnizați o cheie de user sau group validă\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Activați Agentul\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Setările de notificare Slack nu au reușit să fie salvate.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Setările de notificare Slack au fost salvate cu success!\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.RequestList.sortDirection\": \"Schimbă Sortare Direcție\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Seriale in curs de apariție\",\n  \"components.Login.noadminerror\": \"Nici un admin nu a fost găsit pe server.\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Descrie Problemă\",\n  \"components.RequestModal.requestseasons\": \"Solicită {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}\",\n  \"components.RequestModal.requestseasons4k\": \"Solicită {seasonCount} {seasonCount, plural, one {Season} other {Seasons}} în 4K\",\n  \"components.RequestList.RequestItem.removearr\": \"Elimina din {arr}\",\n  \"components.Login.loginwithapp\": \"Conecteazăte cu {appName}\",\n  \"components.Login.orsigninwith\": \"Sau creează cont cu\",\n  \"components.Discover.FilterSlideover.certification\": \"Rata Conținutului\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Exclude Cuvinte\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Alege un furnizor de metadata\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Nu s-au putut încărca certificatele\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Rating maxim\",\n  \"components.Selector.CertificationSelector.minRating\": \"Rating minim\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Nicio opțiune disponibilǎ\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Selectează un certificat\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Selectează o țară\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Începe să scrii pentru a căuta.\",\n  \"components.Selector.searchUsers\": \"Selectează utilizatori…\",\n  \"components.Selector.starttyping\": \"Începe să scrii pentru a căuta.\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Prioritate\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Trebuie sa setezi o prioritate\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Activează Agent\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Poster incorporat\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Setările pentru notificări Ntfy nu s-au putut salva.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Setările pentru notificări Ntfy au fost salvate cu succes!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Parolă\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Nu s-a putut transmite notificarea de test Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Se trimite notificarea de test Ntfy…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Testul de notificare Ntfy a fost trimis!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Autentificare cu token\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Topic\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Baza URL-ului server-ului\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Username\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Autentificare cu username + parolă\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Trebuie să completezi un topic\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Trebuie să furnizezi un URL valid\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Trebuie să selectezi cel puțin un tip de notificare\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Creează un token din <PushbulletSettingsLink>Setările Contului</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Testul de notificări Pushbullet nu s-a putut trimite.\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Poster incorporat\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Testul de notificare Pushover nu s-a trimis cu succes.\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"<UsersGroupsLink>identificatorul tău de utilizator sau grup de 30 de caractere</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Poster incorporat\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Testul de notificare către Slack nu s-a trimis cu succes.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Se trimite testul de notificare către Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Testul de notificare către Slack a fost trimis!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Trebuie să selectezi cel puțin un tip de notificare\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Trebuie să furnizezi un URL valid\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Creează o integrare <WebhookLink>Webhook</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Activează Agent\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Header Autorizare\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Payload JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Resetează\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"Payload-ul JSON a fost resetat cu succes!\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Suport pentru variabile in URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Variabilele disponibile sunt documentate in secțiunea de variabile pentru șabloane webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Ajutor pentru variabilele șablon\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Testul de notificare webhook nu s-a trimis cu succes.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Se trimite notificarea de test webhook…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Notificarea de test webhook a fost trimisă cu succes!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Trebuie să furnizezi un payload JSON valid\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Trebuie să selectezi cel puțin un tip de notificare\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Trebuie să furnizezi un URL valid\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"URL-ul pentru notificarea de test este setat la {testUrl} în loc de URL-ul de webhook.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Setările pentru notificarea webhook nu s-au putut salva.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Setările pentru notificarea webhook au fost salvate cu succes!\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Activează Agent\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Pentru a putea primi notificări push pe web, Seerr trebuie rulat pe HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Testul notificării push web nu s-a putut trimite cu succes.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Testul notificării de test push web se trimite…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Testul notificării push web a fost trimis!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Setările pentru notificarea push web nu s-au putut salva.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Setările pentru notificarea push web au fost salvate cu succes!\",\n  \"components.Settings.Notifications.agentenabled\": \"Activează Agent\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Permite Certificate Self-Signed\",\n  \"components.Settings.Notifications.authPass\": \"Parolă SMTP\",\n  \"components.Settings.Notifications.authUser\": \"Username SMTP\",\n  \"components.Settings.Notifications.botAPI\": \"Token Autorizare Bot\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Creează un bot</CreateBotLink>pentru a-l folosi cu Seerr\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL Avatar Bot\",\n  \"components.Settings.Notifications.botUsername\": \"Username Bot\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Permite utilizatorilor să deschidă o conversație cu botul tău și să își configureze propriile notificări\",\n  \"components.Settings.Notifications.chatId\": \"ID conversație\",\n  \"components.Settings.Notifications.chatIdTip\": \"\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"\",\n  \"components.Settings.Notifications.emailsender\": \"\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.enableMentions\": \"\",\n  \"components.Settings.Notifications.encryption\": \"\",\n  \"components.Settings.Notifications.encryptionDefault\": \"\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"\",\n  \"components.Settings.Notifications.encryptionNone\": \"\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"\",\n  \"components.Settings.Notifications.encryptionTip\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.pgpPassword\": \"\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"\",\n  \"components.Settings.Notifications.sendSilently\": \"\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"\",\n  \"components.Settings.Notifications.senderName\": \"Nume Expeditor\",\n  \"components.Settings.Notifications.smtpHost\": \"\",\n  \"components.Settings.Notifications.smtpPort\": \"Port SMTP\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Setările notificării Telegram nu au putut fi salvate.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Setările notificării Telegram au fost salvate cu succes!\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Testul notificării Discord nu s-a putut trimite cu succes.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Testul notificării Discord se trimite…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Testul notificării Discord a fost trimis cu succes!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Testul notificării pe email nu a putut fi trimis cu succes.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Testul notificării pe email se trimite…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Testul notificării pe email a fost trimis cu succes!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Testul notificării Telegram nu a putut fi trimis cu succes.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Testul notificării Telegram se trimite…\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Testul notificării Telegram a fost trimis cu succes!\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Cere email-ul utilizatorului\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Trebuie să furnizezi un token de autorizare pentru bot\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Trebuie să furnizezi un ID de conversație valid\",\n  \"components.Settings.Notifications.validationEmail\": \"Trebuie să furnizezi o adresă de email validă\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Trebuie să furnizezi o parolă PGP\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Trebuie să furnizezi o cheie privată PGP validă\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Trebuie să furnizezi un hostname sau o adresă IP validă\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Trebuie să furnizezi un port valid\",\n  \"components.Settings.Notifications.validationTypes\": \"\",\n  \"components.Settings.Notifications.validationUrl\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"ID rol notificare\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"ID-ul rolului de menționat in mesajul webhook. Lasă gol pentru a dezactiva mențiunile\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL webhook\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Creează o <DiscordWebhookLink>integrare webhook</DiscordWebhookLink> în serverul tău\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Condiții\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Adaugă condiții înainte de a aplica schimbările parametrilor. Fiecare câmp trebuie să fie validat pentru ca regulile să se aplice (operația AND). Un câmp este considerat verificat atunci când oricare dintre proprietățile sale corespund (operația OR).\",\n  \"components.Settings.OverrideRuleModal.create\": \"Creează regulă\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Regulă de suprascriere nouă\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Editează regulă de suprascriere\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Genuri\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Cuvinte cheie\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Limbi\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Nici un tag.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Profil de calitate\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Folder root\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Regulă de suprascriere creată cu succes!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Regulă de suprascriere actualizată cu succes!\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Selectează profil de calitate\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Selectează folder root\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Selectează serviciu\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Selectează taguri\",\n  \"components.Settings.OverrideRuleModal.service\": \"Serviciu\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Aplică această regulă la serviciul selectat.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Setări\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Specifică ce setări vor fi modificate când condițiile de mai sus sunt îndeplinite.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Taguri\",\n  \"components.Settings.OverrideRuleModal.users\": \"Utilizatori\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Condiții\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Gen\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Cuvinte cheie\",\n  \"components.Settings.OverrideRuleTile.language\": \"Limbă\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Profil de calitate\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Folder root\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Setări\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Taguri\",\n  \"components.Settings.OverrideRuleTile.users\": \"Utilizatori\",\n  \"components.Settings.RadarrModal.add\": \"Adaugă server\",\n  \"components.Settings.RadarrModal.announced\": \"Anunțate\",\n  \"components.Settings.RadarrModal.apiKey\": \"Cheie API\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Baza URL-ului\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Adaugă server Radarr 4K nou\",\n  \"components.Settings.RadarrModal.createradarr\": \"Adaugă server Radarr nou\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Server 4k implicit\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Server implicit\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Modifică server Radarr 4k\",\n  \"components.Settings.RadarrModal.editradarr\": \"Modifică server Radarr\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Activează Căutarea Automată\",\n  \"components.Settings.RadarrModal.externalUrl\": \"URL extern\",\n  \"components.Settings.RadarrModal.hostname\": \"Hostname sau Adresă IP\",\n  \"components.Settings.RadarrModal.inCinemas\": \"În Cinema-uri\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Tagurile se încarcă…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Profilurile de calitate se încarcă…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Folderele root se încarcă…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Disponibilitate minimă\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Niciun tag.\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Profil de calitate\",\n  \"components.Settings.RadarrModal.released\": \"Lansat\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Folder root\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Selectează disponibilitatea minimă\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Selectează profilul de calitate\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Selectează folderul root\",\n  \"components.Settings.RadarrModal.selecttags\": \"Selectează tagurile\",\n  \"components.Settings.RadarrModal.server4k\": \"Server 4K\",\n  \"components.Settings.RadarrModal.servername\": \"Numele serverului\",\n  \"components.Settings.RadarrModal.ssl\": \"Folosește SSL\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Activează scanarea\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Cereri de taguri\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Adaugă automat un tag aditional cu identificatorul de utilizator și numele solicitantului\",\n  \"components.Settings.RadarrModal.tags\": \"Taguri\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Testează conexiunea pentru a încărca profilele de calitate\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Testează conexiunea pentru a încărca folderele root\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Testează conexiunea pentru a încărca tagurile\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Conexiunea cu Radarr nu s-a putut efectua.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Conexiunea cu Radarr a fost efectuată cu succes!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Trebuie să furnizezi o cheie de API\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Trebuie sa furnizezi un URL valid\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL-ul nu trebuie să se termine cu slash\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Baza URL-ului trebuie sa aibă un slash\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Baza URL-ului nu trebuie să se termine cu un slash\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Trebuie să furnizezi un hostname sau o adresă IP valide\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Trebuie să setezi o disponibilitate minimă\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Trebuie să completezi numele serverului\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Trebuie să furnizezi un port valid\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Trebuie să selectezi un profil de calitate\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Trebuie să selectezi un folder root\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Curentă\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Changelog\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Vizualizează Changelog\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Vizualizează pe GitHub\",\n  \"components.Settings.SettingsAbout.about\": \"Despre\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Directorul de date\",\n  \"components.Settings.SettingsAbout.documentation\": \"Documentație\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Obține ajutor\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Discuții GitHub\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Vechi\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Rulezi branch-ul de <code>develop</code> de Seerr, ceea ce este recomandat doar pentru cei ce contribuie la dezvoltare sau la testare.\",\n  \"components.Settings.SettingsAbout.timezone\": \"Fus orar\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Total materiale\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Total cereri\",\n  \"components.Settings.SettingsAbout.uptodate\": \"La zi\",\n  \"components.Settings.SettingsAbout.version\": \"Versiune\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Sincronizare disponibilitate materiale\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr cache-uieste request-urile catre endpoint-urile externe pentru a optimiza performanța și pentru a evita apelurile inutile.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Cache-ul {cachename} a fost flushed.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Accesări\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Total chei\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Dimensiunea cheii\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Ratări\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Numele cache-ului\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Dimensiunea valorii\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Anulează job-ul\",\n  \"components.Settings.SettingsJobsCache.command\": \"Comandă\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"Cache DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr stochează în cache căutările DNS pentru a optimiza performanța și pentru a evita apelurile inutile.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Statistici globale cache DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Aceste statistici sunt agregate pentru toate intrările din cache-ul DNS.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Adresă activă\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Vechime\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"Cache-ul DNS pentru {hostname} a fost flushed.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Accesări\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Ratări\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Hostname\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Sincronizare descărcări\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Resetare sincronizare download-uri\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modifică job\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Frecvență curentă\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Frecvență nouă\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"La fiecare {jobScheduleDays, plural, o {day} alte {{jobScheduleDays} days}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"La fiecare {jobScheduleHours, plural, o {hour} alte {{jobScheduleHours} hours}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"La fiecare {jobScheduleMinutes, plural, un {minute} alte {{jobScheduleMinutes} minutes}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"La fiecare {jobScheduleSeconds, plural, o {second} alte {{jobScheduleSeconds} seconds}}\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Eșecuri\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Golește cache\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Golește cache-ul DNS\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Rate de succes\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Accesări\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Curățare cache imagini\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Cache imagini\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Când este activat în setări, Seerr va acționa ca un proxy și va stoca în cache imaginile din sursele externe pre-configurate. Imaginile stocate în cache sunt salvate în folderul de configurare. Poți găsi fișierele în <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Imagini stocate în cache\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Dimensiunea totală a cache-ului\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"Fallback-uri IPv4\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Scanare completă librărie Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.process\": \"\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"\",\n  \"components.Settings.SettingsLogs.extraData\": \"\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"\",\n  \"components.Settings.SettingsLogs.filterError\": \"\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"\",\n  \"components.Settings.SettingsLogs.label\": \"\",\n  \"components.Settings.SettingsLogs.level\": \"\",\n  \"components.Settings.SettingsLogs.logDetails\": \"\",\n  \"components.Settings.SettingsLogs.logs\": \"\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"\",\n  \"components.Settings.SettingsLogs.message\": \"\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"\",\n  \"components.Settings.SettingsLogs.showall\": \"\",\n  \"components.Settings.SettingsLogs.time\": \"\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"\",\n  \"components.Settings.SettingsMain.apikey\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"\",\n  \"components.Settings.SettingsMain.applicationurl\": \"\",\n  \"components.Settings.SettingsMain.cacheImages\": \"\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.general\": \"\",\n  \"components.Settings.SettingsMain.generalsettings\": \"\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"\",\n  \"components.Settings.SettingsUsers.localLogin\": \"\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.userSettings\": \"\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"\",\n  \"components.Settings.SettingsUsers.users\": \"\",\n  \"components.Settings.SonarrModal.add\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.animeTags\": \"\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"\",\n  \"components.Settings.SonarrModal.apiKey\": \"\",\n  \"components.Settings.SonarrModal.baseUrl\": \"\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.createsonarr\": \"\",\n  \"components.Settings.SonarrModal.default4kserver\": \"\",\n  \"components.Settings.SonarrModal.defaultserver\": \"\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.editsonarr\": \"\",\n  \"components.Settings.SonarrModal.enableSearch\": \"\",\n  \"components.Settings.SonarrModal.externalUrl\": \"\",\n  \"components.Settings.SonarrModal.hostname\": \"\",\n  \"components.Settings.SonarrModal.languageprofile\": \"\",\n  \"components.Settings.SonarrModal.loadingTags\": \"\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"\",\n  \"components.Settings.SonarrModal.notagoptions\": \"\",\n  \"components.Settings.SonarrModal.port\": \"\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"\",\n  \"components.Settings.SonarrModal.rootfolder\": \"\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"\",\n  \"components.Settings.SonarrModal.selecttags\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.server4k\": \"\",\n  \"components.Settings.SonarrModal.servername\": \"\",\n  \"components.Settings.SonarrModal.ssl\": \"\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SonarrModal.tags\": \"\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.activeProfile\": \"\",\n  \"components.Settings.addradarr\": \"\",\n  \"components.Settings.address\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.addsonarr\": \"\",\n  \"components.Settings.advancedTooltip\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.cancelscan\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.currentlibrary\": \"\",\n  \"components.Settings.default\": \"\",\n  \"components.Settings.default4k\": \"\",\n  \"components.Settings.deleteServer\": \"\",\n  \"components.Settings.deleteserverconfirm\": \"\",\n  \"components.Settings.email\": \"\",\n  \"components.Settings.enablessl\": \"\",\n  \"components.Settings.experimentalTooltip\": \"\",\n  \"components.Settings.externalUrl\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.hostname\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.is4k\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.librariesRemaining\": \"\",\n  \"components.Settings.manualscan\": \"\",\n  \"components.Settings.manualscanDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.mediaTypeMovie\": \"\",\n  \"components.Settings.mediaTypeSeries\": \"\",\n  \"components.Settings.menuAbout\": \"\",\n  \"components.Settings.menuGeneralSettings\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuJobs\": \"\",\n  \"components.Settings.menuLogs\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.menuNotifications\": \"\",\n  \"components.Settings.menuPlexSettings\": \"\",\n  \"components.Settings.menuServices\": \"\",\n  \"components.Settings.menuUsers\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noDefault4kServer\": \"\",\n  \"components.Settings.noDefaultNon4kServer\": \"\",\n  \"components.Settings.noDefaultServer\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"\",\n  \"components.Settings.notifications\": \"\",\n  \"components.Settings.notificationsettings\": \"\",\n  \"components.Settings.notrunning\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.plex\": \"\",\n  \"components.Settings.plexlibraries\": \"\",\n  \"components.Settings.plexlibrariesDescription\": \"\",\n  \"components.Settings.plexsettings\": \"\",\n  \"components.Settings.plexsettingsDescription\": \"\",\n  \"components.Settings.port\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.radarrsettings\": \"\",\n  \"components.Settings.restartrequiredTooltip\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scan\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.scanning\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.serverLocal\": \"\",\n  \"components.Settings.serverRemote\": \"\",\n  \"components.Settings.serverSecure\": \"\",\n  \"components.Settings.serverpreset\": \"\",\n  \"components.Settings.serverpresetLoad\": \"\",\n  \"components.Settings.serverpresetManualMessage\": \"\",\n  \"components.Settings.serverpresetRefreshing\": \"\",\n  \"components.Settings.serviceSettingsDescription\": \"\",\n  \"components.Settings.services\": \"\",\n  \"components.Settings.settingUpPlexDescription\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.sonarrsettings\": \"\",\n  \"components.Settings.ssl\": \"\",\n  \"components.Settings.startscan\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.tautulliApiKey\": \"\",\n  \"components.Settings.tautulliSettings\": \"\",\n  \"components.Settings.tautulliSettingsDescription\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.toastPlexConnecting\": \"\",\n  \"components.Settings.toastPlexConnectingFailure\": \"\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"\",\n  \"components.Settings.toastPlexRefresh\": \"\",\n  \"components.Settings.toastPlexRefreshFailure\": \"\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.urlBase\": \"\",\n  \"components.Settings.validationApiKey\": \"\",\n  \"components.Settings.validationHostnameRequired\": \"\",\n  \"components.Settings.validationPortRequired\": \"\",\n  \"components.Settings.validationUrl\": \"\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Settings.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.webAppUrl\": \"\",\n  \"components.Settings.webAppUrlTip\": \"\",\n  \"components.Settings.webhook\": \"\",\n  \"components.Settings.webpush\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.configureservices\": \"\",\n  \"components.Setup.continue\": \"\",\n  \"components.Setup.finish\": \"\",\n  \"components.Setup.finishing\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.setup\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinMessage\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.Setup.welcome\": \"\",\n  \"components.StatusBadge.managemedia\": \"\",\n  \"components.StatusBadge.openinarr\": \"\",\n  \"components.StatusBadge.playonplex\": \"\",\n  \"components.StatusBadge.seasonepisodenumber\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.StatusBadge.status\": \"\",\n  \"components.StatusBadge.status4k\": \"\",\n  \"components.StatusChecker.appUpdated\": \"\",\n  \"components.StatusChecker.appUpdatedDescription\": \"\",\n  \"components.StatusChecker.reloadApp\": \"\",\n  \"components.StatusChecker.restartRequired\": \"\",\n  \"components.StatusChecker.restartRequiredDescription\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.cleardata\": \"\",\n  \"components.TitleCard.mediaerror\": \"\",\n  \"components.TitleCard.tmdbid\": \"\",\n  \"components.TitleCard.tvdbid\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.Season.noepisodes\": \"\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.anime\": \"\",\n  \"components.TvDetails.cast\": \"\",\n  \"components.TvDetails.episodeCount\": \"\",\n  \"components.TvDetails.episodeRuntime\": \"\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"\",\n  \"components.TvDetails.firstAirDate\": \"\",\n  \"components.TvDetails.manageseries\": \"\",\n  \"components.TvDetails.nextAirDate\": \"\",\n  \"components.TvDetails.originallanguage\": \"\",\n  \"components.TvDetails.originaltitle\": \"\",\n  \"components.TvDetails.overview\": \"\",\n  \"components.TvDetails.overviewunavailable\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.productioncountries\": \"\",\n  \"components.TvDetails.recommendations\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.reportissue\": \"\",\n  \"components.TvDetails.rtaudiencescore\": \"\",\n  \"components.TvDetails.rtcriticsscore\": \"\",\n  \"components.TvDetails.seasonnumber\": \"\",\n  \"components.TvDetails.seasons\": \"\",\n  \"components.TvDetails.seasonstitle\": \"\",\n  \"components.TvDetails.showtype\": \"\",\n  \"components.TvDetails.similar\": \"\",\n  \"components.TvDetails.status4k\": \"\",\n  \"components.TvDetails.streamingproviders\": \"\",\n  \"components.TvDetails.tmdbuserscore\": \"\",\n  \"components.TvDetails.viewfullcrew\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.TvDetails.watchtrailer\": \"\",\n  \"components.UserList.admin\": \"\",\n  \"components.UserList.autogeneratepassword\": \"\",\n  \"components.UserList.autogeneratepasswordTip\": \"\",\n  \"components.UserList.bulkedit\": \"\",\n  \"components.UserList.create\": \"\",\n  \"components.UserList.created\": \"\",\n  \"components.UserList.createlocaluser\": \"\",\n  \"components.UserList.creating\": \"\",\n  \"components.UserList.deleteconfirm\": \"\",\n  \"components.UserList.deleteuser\": \"\",\n  \"components.UserList.edituser\": \"\",\n  \"components.UserList.email\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importedfromplex\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.importfromplex\": \"\",\n  \"components.UserList.importfromplexerror\": \"\",\n  \"components.UserList.localLoginDisabled\": \"\",\n  \"components.UserList.localuser\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.newplexsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.nouserstoimport\": \"\",\n  \"components.UserList.owner\": \"\",\n  \"components.UserList.password\": \"\",\n  \"components.UserList.passwordinfodescription\": \"\",\n  \"components.UserList.plexuser\": \"\",\n  \"components.UserList.role\": \"\",\n  \"components.UserList.sortCreated\": \"\",\n  \"components.UserList.sortDisplayName\": \"\",\n  \"components.UserList.sortRequests\": \"\",\n  \"components.UserList.totalrequests\": \"\",\n  \"components.UserList.user\": \"\",\n  \"components.UserList.usercreatedfailed\": \"\",\n  \"components.UserList.usercreatedfailedexisting\": \"\",\n  \"components.UserList.usercreatedsuccess\": \"\",\n  \"components.UserList.userdeleted\": \"\",\n  \"components.UserList.userdeleteerror\": \"\",\n  \"components.UserList.userfail\": \"\",\n  \"components.UserList.userlist\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.users\": \"\",\n  \"components.UserList.userssaved\": \"\",\n  \"components.UserList.validationEmail\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserList.validationpasswordminchars\": \"\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"\",\n  \"components.UserProfile.ProfileHeader.profile\": \"\",\n  \"components.UserProfile.ProfileHeader.settings\": \"\",\n  \"components.UserProfile.ProfileHeader.userid\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Confirmă parola\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Parolă curentă\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Parolă nouă\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Acest utilizator nu are o parolă setată. Configurează o parolă mai jos pentru a permite conectarea ca \\\"utilizator local\\\".\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Contul tău nu are setată o parolă. Configurează o parolă mai jos pentru a permite conectarea ca \\\"utilizator local\\\" folosind adresa ta de email.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Nu ai permisiuni pentru a modifica parola acestui utilizator.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Parolă\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Ceva nu a funcționat la salvarea parolei.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Ceva nu a funcționat la salvarea parolei. Ai introdus corect parola curentă?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Parolă salvată cu succes!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Trebuie să îți confirmi noua parolă\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Parolele trebuie să se potrivească\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Trebuie sa completezi parola curentă\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Trebuie să furnizezi o parolă nouă\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Parola este prea scurtă; ar trebui să fie compusă din minim 8 caractere\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Permisiuni\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Ceva nu a funcționat la salvarea setărilor.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Permisiunile au fost salvate cu succes!\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Nu îți poți modifica propriile permisiuni.\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Parolă\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Generale\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Conturi conectate\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notificări\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Permisiuni\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Nu ai permisiuni pentru a modifica setările acestui utilizator.\",\n  \"components.UserProfile.emptywatchlist\": \"Materialele adăugate în <PlexWatchlistSupportLink>Watchlist-ul tău Plex</PlexWatchlistSupportLink> vor apărea aici.\",\n  \"components.UserProfile.limit\": \"{remaining} din {limit}\",\n  \"components.UserProfile.localWatchlist\": \"Watchlist-ul lui {username}\",\n  \"components.UserProfile.movierequests\": \"Cereri de filme\",\n  \"components.UserProfile.pastdays\": \"{type} (ultimele {days} zile)\",\n  \"components.UserProfile.plexwatchlist\": \"Watchlist-ul Plex\",\n  \"components.UserProfile.recentlywatched\": \"Văzute recent\",\n  \"components.UserProfile.recentrequests\": \"Cereri recente\",\n  \"components.UserProfile.requestsperdays\": \"{limit} rămase\",\n  \"components.UserProfile.seriesrequest\": \"\",\n  \"components.UserProfile.totalrequests\": \"\",\n  \"components.UserProfile.unlimited\": \"\",\n  \"i18n.advanced\": \"\",\n  \"i18n.all\": \"\",\n  \"i18n.approve\": \"\",\n  \"i18n.approved\": \"\",\n  \"i18n.areyousure\": \"\",\n  \"i18n.available\": \"\",\n  \"i18n.back\": \"\",\n  \"i18n.cancel\": \"\",\n  \"i18n.canceling\": \"\",\n  \"i18n.close\": \"\",\n  \"i18n.collection\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.decline\": \"\",\n  \"i18n.declined\": \"\",\n  \"i18n.delete\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.deleting\": \"\",\n  \"i18n.delimitedlist\": \"\",\n  \"i18n.edit\": \"\",\n  \"i18n.experimental\": \"\",\n  \"i18n.failed\": \"\",\n  \"i18n.import\": \"\",\n  \"i18n.importing\": \"\",\n  \"i18n.loading\": \"\",\n  \"i18n.movie\": \"\",\n  \"i18n.movies\": \"\",\n  \"i18n.next\": \"\",\n  \"i18n.notrequested\": \"Necerut\",\n  \"i18n.open\": \"Deschis\",\n  \"i18n.partiallyavailable\": \"Disponibil parțial\",\n  \"i18n.pending\": \"În curs\",\n  \"i18n.previous\": \"Precedent\",\n  \"i18n.processing\": \"Se procesează\",\n  \"i18n.request\": \"Cere\",\n  \"i18n.request4k\": \"Cere în 4K\",\n  \"i18n.requested\": \"Cerut\",\n  \"i18n.requesting\": \"Se trimite cererea…\",\n  \"i18n.resolved\": \"Rezolvată\",\n  \"i18n.restartRequired\": \"Restart necesar\",\n  \"i18n.resultsperpage\": \"Afișează {pageSize} rezultate per pagină\",\n  \"i18n.retry\": \"Reîncearcă\",\n  \"i18n.retrying\": \"Se reîncearcă…\",\n  \"i18n.save\": \"Salvează modificări\",\n  \"i18n.saving\": \"Se salvează…\",\n  \"i18n.settings\": \"Setări\",\n  \"i18n.showingresults\": \"Se afișează de la <strong>{from}</strong> la<strong>{to}</strong> din <strong>{total}</strong> rezultate\",\n  \"i18n.specials\": \"Speciale\",\n  \"i18n.status\": \"Stare\",\n  \"i18n.test\": \"Testează\",\n  \"i18n.testing\": \"Se testează…\",\n  \"i18n.tvshow\": \"Seriale\",\n  \"i18n.tvshows\": \"Seriale\",\n  \"i18n.unavailable\": \"Indisponibil\",\n  \"i18n.usersettings\": \"Setări utilizator\",\n  \"i18n.view\": \"Vizualizează\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"Internal Server Error\",\n  \"pages.oops\": \"Oops\",\n  \"pages.pagenotfound\": \"Pagina nu a fost găsită\",\n  \"pages.returnHome\": \"Întoarce-te acasă\",\n  \"pages.serviceunavailable\": \"\",\n  \"pages.somethingwentwrong\": \"\",\n  \"i18n.noresults\": \"Nici un rezultat.\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Ultima\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Nu sunt disponibile informații despre release.\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Release-uri\",\n  \"components.Settings.SettingsMain.locale\": \"\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"\",\n  \"components.UserList.accounttype\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Despre Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Fă o contribuție\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Susține Seerr\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\",\n  \"component.BlocklistBlock.blocklistdate\": \"Data blocării\",\n  \"component.BlocklistBlock.blocklistedby\": \"Blocat de\",\n  \"component.BlocklistModal.blocklisting\": \"În curs de blocare\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> nu este blocat.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Gestionează materialele blocate.\",\n  \"components.Blocklist.blocklistdate\": \"dată\",\n  \"components.Blocklist.blocklistedby\": \"{date} de {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Setările listei de materiale blocate\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Tag-urile listei de materiale blocate\",\n  \"components.Blocklist.filterManual\": \"Manual\",\n  \"components.Blocklist.mediaName\": \"Nume\",\n  \"components.Blocklist.mediaTmdbId\": \"ID TMDB\",\n  \"components.Blocklist.mediaType\": \"Tip\",\n  \"components.Blocklist.showAllBlocklisted\": \"Arată toate materialele blocate din listă\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Conexiunea cu {services} a eșuat. Unele informații ar putea deveni indisponibile.\",\n  \"components.Layout.Sidebar.blocklist\": \"Blocate\",\n  \"components.PermissionEdit.blocklistedItems\": \"Materiale blocate.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Acordă permisiuni pentru a bloca materiale.\",\n  \"components.PermissionEdit.manageblocklist\": \"Gestionează lista de materiale blocate\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Acordă permisiuni pentru a gestiona materialele blocate.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Vizualizează materialele blocate.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Acordă permisiuni pentru a vizualiza materialele blocate.\",\n  \"components.RequestList.unableToConnect\": \"Conexiunena cu {services} a eșuat. Unele informații ar putea deveni indisponibile.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Nici o căutare DNS nu a fost stocată în cache încă.\",\n  \"i18n.removefromBlocklist\": \"Elimină din lista de materiale blocate\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong>a fost eliminat cu succes din lista de materiale blocate.\"\n}\n"
  },
  {
    "path": "src/i18n/locale/ru.json",
    "content": "{\n  \"components.Discover.popularmovies\": \"Популярные фильмы\",\n  \"components.Discover.populartv\": \"Популярные сериалы\",\n  \"components.Discover.recentlyAdded\": \"Недавно добавлено\",\n  \"components.Discover.recentrequests\": \"Последние запросы\",\n  \"components.Discover.trending\": \"В трендах\",\n  \"components.Discover.upcoming\": \"Предстоящие фильмы\",\n  \"components.Discover.upcomingmovies\": \"Предстоящие фильмы\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Поиск фильмов и сериалов\",\n  \"components.Layout.Sidebar.dashboard\": \"Найти что-то новое\",\n  \"components.Layout.Sidebar.requests\": \"Запросы\",\n  \"components.Layout.Sidebar.settings\": \"Настройки\",\n  \"components.Layout.Sidebar.users\": \"Пользователи\",\n  \"components.Layout.UserDropdown.signout\": \"Выход\",\n  \"components.MovieDetails.budget\": \"Бюджет\",\n  \"components.MovieDetails.cast\": \"В ролях\",\n  \"components.MovieDetails.originallanguage\": \"Язык оригинала\",\n  \"components.MovieDetails.overview\": \"Обзор\",\n  \"components.MovieDetails.overviewunavailable\": \"Обзор недоступен.\",\n  \"components.MovieDetails.recommendations\": \"Рекомендации\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Дата релиза} other {Даты релиза}}\",\n  \"components.MovieDetails.revenue\": \"Доход\",\n  \"components.MovieDetails.runtime\": \"{minutes} минут\",\n  \"components.MovieDetails.similar\": \"Похожие фильмы\",\n  \"components.PersonDetails.appearsin\": \"Появления в фильмах и сериалах\",\n  \"components.PersonDetails.ascharacter\": \"в роли {character}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезоны}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезоны}}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезоны}}\",\n  \"components.RequestList.requests\": \"Запросы\",\n  \"components.RequestModal.cancel\": \"Отменить запрос\",\n  \"components.RequestModal.numberofepisodes\": \"# эпизодов\",\n  \"components.RequestModal.pendingrequest\": \"Ожидающий запрос\",\n  \"components.RequestModal.requestCancel\": \"Запрос на <strong>{title}</strong> отменён.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> успешно запрошен!\",\n  \"components.RequestModal.requestadmin\": \"Этот запрос будет одобрен автоматически.\",\n  \"components.RequestModal.requestfrom\": \"Запрос пользователя {username} ожидает одобрения.\",\n  \"components.RequestModal.requestseasons\": \"Запросить {seasonCount} {seasonCount, plural, one {сезон} other {сезона(ов)}}\",\n  \"components.RequestModal.season\": \"Сезон\",\n  \"components.RequestModal.seasonnumber\": \"Сезон {number}\",\n  \"components.RequestModal.selectseason\": \"Выберите сезон(ы)\",\n  \"components.Search.searchresults\": \"Результаты поиска\",\n  \"components.Settings.Notifications.agentenabled\": \"Активировать службу\",\n  \"components.Settings.Notifications.authPass\": \"Пароль SMTP\",\n  \"components.Settings.Notifications.authUser\": \"Имя пользователя SMTP\",\n  \"components.Settings.Notifications.emailsender\": \"Адрес отправителя\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP-хост\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP порт\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Вы должны указать действительное имя хоста или IP-адрес\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Вы должны указать действительный номер порта\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL веб-перехватчика\",\n  \"components.Settings.RadarrModal.add\": \"Добавить сервер\",\n  \"components.Settings.RadarrModal.apiKey\": \"Ключ API\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Базовый URL\",\n  \"components.Settings.RadarrModal.createradarr\": \"Добавить новый сервер Radarr\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Сервер по умолчанию\",\n  \"components.Settings.RadarrModal.editradarr\": \"Редактировать сервер Radarr\",\n  \"components.Settings.RadarrModal.hostname\": \"Имя хоста или IP-адрес\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Минимальная доступность\",\n  \"components.Settings.RadarrModal.port\": \"Порт\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Профиль качества\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Корневой каталог\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Выберите минимальную доступность\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Выберите профиль качества\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Выберите корневой каталог\",\n  \"components.Settings.RadarrModal.server4k\": \"4К сервер\",\n  \"components.Settings.RadarrModal.servername\": \"Название сервера\",\n  \"components.Settings.RadarrModal.ssl\": \"Использовать SSL\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Не удалось подключиться к Radarr.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Соединение с Radarr установлено успешно!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Вы должны предоставить ключ API\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Вы должны указать действительное имя хоста или IP-адрес\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Вы должны указать действительный номер порта\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Вы должны выбрать профиль качества\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Вы должны выбрать корневой каталог\",\n  \"components.Settings.SonarrModal.add\": \"Добавить сервер\",\n  \"components.Settings.SonarrModal.apiKey\": \"Ключ API\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Базовый URL\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Добавить новый сервер Sonarr\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Сервер по умолчанию\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Редактировать сервер Sonarr\",\n  \"components.Settings.SonarrModal.hostname\": \"Имя хоста или IP-адрес\",\n  \"components.Settings.SonarrModal.port\": \"Порт\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Профиль качества\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Корневой каталог\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Папки для сезонов\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Выберите профиль качества\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Выберите корневой каталог\",\n  \"components.Settings.SonarrModal.server4k\": \"4К сервер\",\n  \"components.Settings.SonarrModal.servername\": \"Название сервера\",\n  \"components.Settings.SonarrModal.ssl\": \"Использовать SSL\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Вы должны предоставить ключ API\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Вы должны указать действительное имя хоста или IP-адрес\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Вы должны указать действительный номер порта\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Вы должны выбрать профиль качества\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Вы должны выбрать корневой каталог\",\n  \"components.Settings.activeProfile\": \"Активный профиль\",\n  \"components.Settings.addradarr\": \"Добавить сервер Radarr\",\n  \"components.Settings.address\": \"Адрес\",\n  \"components.Settings.addsonarr\": \"Добавить сервер Sonarr\",\n  \"components.Settings.cancelscan\": \"Отменить сканирование\",\n  \"components.Settings.currentlibrary\": \"Текущая библиотека: {name}\",\n  \"components.Settings.default\": \"По умолчанию\",\n  \"components.Settings.default4k\": \"4К по умолчанию\",\n  \"components.Settings.deleteserverconfirm\": \"Вы уверены, что хотите удалить этот сервер?\",\n  \"components.Settings.hostname\": \"Имя хоста или IP-адрес\",\n  \"components.Settings.librariesRemaining\": \"Осталось библиотек: {count}\",\n  \"components.Settings.manualscan\": \"Сканировать библиотеки вручную\",\n  \"components.Settings.manualscanDescription\": \"Обычно выполняется раз в 24 часа. Seerr выполнит более агрессивную проверку вашего сервера Plex на предмет недавно добавленных мультимедиа. Если вы впервые настраиваете Plex, рекомендуется выполнить однократное полное сканирование библиотек вручную!\",\n  \"components.Settings.menuAbout\": \"О проекте\",\n  \"components.Settings.menuGeneralSettings\": \"Общее\",\n  \"components.Settings.menuJobs\": \"Задания и кэш\",\n  \"components.Settings.menuLogs\": \"Логи\",\n  \"components.Settings.menuNotifications\": \"Уведомления\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Службы\",\n  \"components.Settings.notificationsettings\": \"Настройки уведомлений\",\n  \"components.Settings.notrunning\": \"Не работает\",\n  \"components.Settings.plexlibraries\": \"Библиотеки Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"Библиотеки, которые Seerr сканирует на предмет наличия мультимедиа. Настройте и сохраните параметры подключения Plex, затем нажмите кнопку ниже, если список библиотек пуст.\",\n  \"components.Settings.plexsettings\": \"Настройки Plex\",\n  \"components.Settings.plexsettingsDescription\": \"Настройте параметры вашего сервера Plex. Seerr сканирует ваши библиотеки Plex, чтобы определить доступность контента.\",\n  \"components.Settings.port\": \"Порт\",\n  \"components.Settings.radarrsettings\": \"Настройки Radarr\",\n  \"components.Settings.sonarrsettings\": \"Настройки Sonarr\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Начать сканирование\",\n  \"components.Setup.configureservices\": \"Настройте службы\",\n  \"components.Setup.continue\": \"Продолжить\",\n  \"components.Setup.finish\": \"Завершить настройку\",\n  \"components.Setup.finishing\": \"Завершение…\",\n  \"components.Setup.signinMessage\": \"Начните со входа в систему\",\n  \"components.Setup.welcome\": \"Добро пожаловать в Seerr\",\n  \"components.TvDetails.cast\": \"В ролях\",\n  \"components.TvDetails.originallanguage\": \"Язык оригинала\",\n  \"components.TvDetails.overview\": \"Обзор\",\n  \"components.TvDetails.overviewunavailable\": \"Обзор недоступен.\",\n  \"components.TvDetails.recommendations\": \"Рекомендации\",\n  \"components.TvDetails.similar\": \"Похожие сериалы\",\n  \"components.UserList.admin\": \"Администратор\",\n  \"components.UserList.created\": \"Присоединился\",\n  \"components.UserList.plexuser\": \"Пользователь Plex\",\n  \"components.UserList.role\": \"Роль\",\n  \"components.UserList.totalrequests\": \"Запросов\",\n  \"components.UserList.user\": \"Пользователь\",\n  \"components.UserList.userlist\": \"Список пользователей\",\n  \"i18n.approve\": \"Одобрить\",\n  \"i18n.approved\": \"Одобрен\",\n  \"i18n.available\": \"Доступен\",\n  \"i18n.cancel\": \"Отмена\",\n  \"i18n.decline\": \"Отклонить\",\n  \"i18n.declined\": \"Отклонён\",\n  \"i18n.delete\": \"Удалить\",\n  \"i18n.movies\": \"Фильмы\",\n  \"i18n.partiallyavailable\": \"Доступен частично\",\n  \"i18n.pending\": \"В ожидании\",\n  \"i18n.processing\": \"В обработке\",\n  \"i18n.tvshows\": \"Сериалы\",\n  \"i18n.unavailable\": \"Недоступен\",\n  \"pages.oops\": \"Упс\",\n  \"pages.returnHome\": \"Вернуться домой\",\n  \"components.CollectionDetails.overview\": \"Обзор\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} фильмов\",\n  \"components.CollectionDetails.requestcollection\": \"Запросить Коллекцию\",\n  \"components.Login.email\": \"Адрес электронной почты\",\n  \"components.UserList.users\": \"Пользователи\",\n  \"components.UserList.userdeleted\": \"Пользователь успешно удален!\",\n  \"components.UserList.usercreatedsuccess\": \"Пользователь успешно создан!\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Всего запросов\",\n  \"components.UserList.sortRequests\": \"Количество запросов\",\n  \"components.UserList.sortCreated\": \"Дата присоединения\",\n  \"components.Login.password\": \"Пароль\",\n  \"components.UserList.password\": \"Пароль\",\n  \"components.UserList.localuser\": \"Локальный пользователь\",\n  \"i18n.edit\": \"Редактировать\",\n  \"components.UserList.deleteuser\": \"Удалить пользователя\",\n  \"components.UserList.creating\": \"Создание…\",\n  \"components.UserList.createlocaluser\": \"Создать локального пользователя\",\n  \"components.UserList.create\": \"Создать\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Телеканал} other {Телеканалы}}\",\n  \"components.TvDetails.anime\": \"Аниме\",\n  \"components.Settings.serverpresetManualMessage\": \"Ручная настройка\",\n  \"components.Settings.serverpreset\": \"Сервер\",\n  \"i18n.deleting\": \"Удаление…\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Последняя\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Текущая\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Включить сканирование\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Включить сканирование\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Отправлять уведомления без звука\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Настройки уведомлений Telegram успешно сохранены!\",\n  \"components.Settings.Notifications.senderName\": \"Имя отправителя\",\n  \"components.Settings.Notifications.botAPI\": \"Токен авторизации бота\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Активировать службу\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Активировать службу\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Активировать службу\",\n  \"components.Search.search\": \"Поиск\",\n  \"components.ResetPassword.resetpassword\": \"Сброс пароля\",\n  \"components.ResetPassword.password\": \"Пароль\",\n  \"components.ResetPassword.confirmpassword\": \"Подтвердить пароль\",\n  \"components.RequestModal.requesterror\": \"Что-то пошло не так при отправке запроса.\",\n  \"components.RequestModal.requestedited\": \"Запрос на <strong>{title}</strong> успешно отредактирован!\",\n  \"components.RequestModal.requestcancelled\": \"Запрос на <strong>{title}</strong> отменён.\",\n  \"components.RequestModal.errorediting\": \"Что-то пошло не так при редактировании запроса.\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Корневой каталог\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Запросить как\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Профиль качества\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (по умолчанию)\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Расширенные настройки\",\n  \"components.RequestList.sortModified\": \"Последнее изменение\",\n  \"components.RequestList.sortAdded\": \"По дате\",\n  \"components.RequestList.showallrequests\": \"Показать все запросы\",\n  \"components.RequestButton.viewrequest\": \"Посмотреть запрос\",\n  \"i18n.retry\": \"Повторить\",\n  \"i18n.requested\": \"Запрошен\",\n  \"components.PermissionEdit.request4k\": \"Запросы 4K\",\n  \"components.PermissionEdit.request\": \"Запросы\",\n  \"i18n.request\": \"Запросить\",\n  \"i18n.failed\": \"Ошибка\",\n  \"i18n.experimental\": \"Экспериментальный параметр\",\n  \"i18n.close\": \"Закрыть\",\n  \"i18n.advanced\": \"Для продвинутых пользователей\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Внешний URL-адрес\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Внешний URL-адрес\",\n  \"components.Settings.Notifications.sendSilently\": \"Отправлять без звука\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Сбросить к настройкам по умолчанию\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Вы должны указать действительный URL-адрес\",\n  \"components.Settings.Notifications.validationUrl\": \"Вы должны указать действительный URL-адрес\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Вы должны указать действительный URL-адрес\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Вы должны указать действительный URL-адрес\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Вы должны указать действительный URL-адрес\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Ключ пользователя или группы\",\n  \"components.UserList.email\": \"Адрес электронной почты\",\n  \"components.ResetPassword.email\": \"Адрес электронной почты\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Языковой профиль\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Языковой профиль\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Этот сериал - аниме.\",\n  \"components.RequestList.RequestItem.requested\": \"Запрошен\",\n  \"components.RequestBlock.rootfolder\": \"Корневой каталог\",\n  \"components.RegionSelector.regionServerDefault\": \"По умолчанию ({region})\",\n  \"components.RegionSelector.regionDefault\": \"Все регионы\",\n  \"components.PermissionEdit.viewrequests\": \"Просмотр запросов\",\n  \"components.PermissionEdit.users\": \"Управление пользователями\",\n  \"components.PermissionEdit.managerequests\": \"Управление запросами\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Администратор\",\n  \"components.PermissionEdit.admin\": \"Администратор\",\n  \"components.RequestBlock.profilechanged\": \"Профиль качества\",\n  \"components.UserProfile.recentrequests\": \"Последние запросы\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Разрешения\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Разрешения\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Уведомления\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Общее\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Пароль\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Локальный пользователь\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Общие настройки\",\n  \"components.UserList.sortDisplayName\": \"Отображаемое имя\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Отображаемое имя\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Вы должны указать свой текущий пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Вы должны подтвердить новый пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Пароль успешно сохранён!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Новый пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Текущий пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Подтвердите пароль\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Настройки успешно сохранены!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Разрешения успешно сохранены!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Что-то пошло не так при сохранении настроек.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Что-то пошло не так при сохранении настроек.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Отправлять уведомления без звука\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Пользователь Plex\",\n  \"components.UserList.owner\": \"Владелец\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Владелец\",\n  \"components.MovieDetails.markavailable\": \"Пометить как доступный\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Токен доступа\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Пароль сброшен успешно!\",\n  \"components.ResetPassword.passwordreset\": \"Сбросить пароль\",\n  \"components.RequestModal.edit\": \"Редактировать запрос\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"фильм\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Теги\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Выбрать теги\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Тегов нет.\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Запрошен\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} пользователем {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Изменено\",\n  \"components.RequestList.RequestItem.editrequest\": \"Редактировать запрос\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Удалить запрос\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Отменить запрос\",\n  \"components.RequestCard.deleterequest\": \"Удалить запрос\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.alsoknownas\": \"Также известен(а) как: {names}\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Типы уведомлений\",\n  \"components.MovieDetails.watchtrailer\": \"Смотреть трейлер\",\n  \"components.MovieDetails.originaltitle\": \"Название оригинала\",\n  \"components.Login.signinwithplex\": \"Используйте ваш аккаунт Plex\",\n  \"components.Login.signinheader\": \"Войдите, чтобы продолжить\",\n  \"components.Login.signin\": \"Войти\",\n  \"components.Login.forgotpassword\": \"Забыли пароль?\",\n  \"components.Layout.UserDropdown.settings\": \"Настройки\",\n  \"components.Layout.UserDropdown.myprofile\": \"Профиль\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Все языки\",\n  \"components.LanguageSelector.languageServerDefault\": \"По умолчанию ({language})\",\n  \"components.Discover.StudioSlider.studios\": \"Студии\",\n  \"components.Discover.NetworkSlider.networks\": \"Телеканалы\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Фильмы {studio}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Фильмы на языке \\\"{language}\\\"\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Фильмы в жанре \\\"{genre}\\\"\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Обсуждения на GitHub\",\n  \"components.Settings.enablessl\": \"Использовать SSL\",\n  \"components.Settings.is4k\": \"4К\",\n  \"components.Settings.mediaTypeMovie\": \"фильм\",\n  \"components.Settings.SonarrModal.tags\": \"Теги\",\n  \"components.Settings.RadarrModal.tags\": \"Теги\",\n  \"i18n.testing\": \"Тестирование…\",\n  \"i18n.test\": \"Протестировать\",\n  \"i18n.status\": \"Статус\",\n  \"i18n.saving\": \"Сохранение…\",\n  \"i18n.previous\": \"Предыдущая\",\n  \"i18n.next\": \"Следующая\",\n  \"i18n.movie\": \"Фильм\",\n  \"i18n.canceling\": \"Отмена…\",\n  \"i18n.back\": \"Назад\",\n  \"i18n.all\": \"Все\",\n  \"i18n.settings\": \"Настройки\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Уведомления\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Уведомления\",\n  \"components.Settings.SettingsUsers.users\": \"Пользователи\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Возобновить\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Приостановить\",\n  \"components.Settings.SettingsLogs.message\": \"Сообщение\",\n  \"components.Settings.SettingsLogs.label\": \"Метка\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Предупреждения\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Информационные\",\n  \"components.Settings.SettingsLogs.filterError\": \"Ошибка\",\n  \"components.Settings.menuUsers\": \"Пользователи\",\n  \"components.Settings.scanning\": \"Синхронизация…\",\n  \"i18n.loading\": \"Загрузка…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Пользователь\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Роль\",\n  \"components.Settings.webhook\": \"Веб-перехватчик\",\n  \"components.Setup.setup\": \"Первоначальная настройка\",\n  \"components.Settings.SettingsJobsCache.process\": \"Процесс\",\n  \"components.Settings.SettingsJobsCache.command\": \"Команда\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Тип\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Кэш\",\n  \"components.Settings.SettingsAbout.documentation\": \"Документация\",\n  \"components.PersonDetails.crewmember\": \"В составе съёмочной группы\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Релизы\",\n  \"components.Settings.SettingsAbout.version\": \"Версия\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Посмотреть профиль\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Название кэша\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Размер ключей\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Всего ключей\",\n  \"components.UserList.bulkedit\": \"Массовое редактирование\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Посмотреть больше\",\n  \"components.TvDetails.watchtrailer\": \"Смотреть трейлер\",\n  \"components.Settings.SettingsAbout.timezone\": \"Часовой пояс\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Получать уведомления, когда другие пользователи отправляют новые медиа-запросы, которые одобряются автоматически.\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Отправлять уведомления, когда пользователи отправляют новые медиа-запросы, требующие одобрения.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Запросы медиафайлов\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Отправлять уведомления, когда медиа-запросы не удаётся добавить в Radarr или Sonarr.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Ошибки при добавлении медиа-запросов\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Отправлять уведомления, когда медиа-запросы отклоняются.\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Отправлять уведомления, когда пользователи отправляют новые медиа-запросы, которые одобряются автоматически.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Автоматическое одобрение медиа-запросов\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Одобрение медиа-запросов\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Отправлять уведомления, когда медиа-запросы одобряются вручную.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Отклонение медиа-запросов\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Отправлять уведомления, когда запрошенные медиафайлы становятся доступны.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Доступны новые медиафайлы\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Полная съёмочная группа\",\n  \"components.MovieDetails.viewfullcrew\": \"Посмотреть полную cъёмочную группу\",\n  \"components.MovieDetails.showmore\": \"Развернуть\",\n  \"components.MovieDetails.showless\": \"Свернуть\",\n  \"components.MovieDetails.mark4kavailable\": \"Пометить как доступный в 4К\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Полный актёрский состав\",\n  \"components.Login.validationpasswordrequired\": \"Вы должны предоставить пароль\",\n  \"components.Login.validationemailrequired\": \"Вы должны указать действительный адрес электронной почты\",\n  \"components.Login.signinwithoverseerr\": \"Используйте ваш аккаунт {applicationTitle}\",\n  \"components.Login.signingin\": \"Выполняется вход…\",\n  \"components.Login.loginerror\": \"Что-то пошло не так при попытке выполнить вход.\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Язык интерфейса\",\n  \"components.DownloadBlock.estimatedtime\": \"Приблизительно {time}\",\n  \"components.Discover.upcomingtv\": \"Предстоящие сериалы\",\n  \"components.Discover.discover\": \"Найти что-то новое\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Сериалы по жанрам\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Сериалы по жанрам\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Фильмы по жанрам\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Фильмы по жанрам\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Сериалы на языке \\\"{language}\\\"\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Сериалы в жанре \\\"{genre}\\\"\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Сериалы {network}\",\n  \"components.CollectionDetails.requestcollection4k\": \"Запросить Коллекцию в 4К\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {фильм} other {фильмы}}\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {фильм} other {фильмы}}\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Этому пользователю разрешено запрашивать <strong>{limit}</strong> {type} каждые <strong>{days}</strong> дней.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Вам разрешено запрашивать <strong>{limit}</strong> {type} каждые <strong>{days}</strong> дней.\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Протестировать соединение для загрузки корневых каталогов\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Загрузка корневых каталогов…\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Корневой каталог для аниме\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Протестировать подключение для загрузки корневых каталогов\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Загрузка корневых каталогов…\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Сервер-получатель\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} не найдено\",\n  \"components.RequestList.RequestItem.failedretry\": \"Что-то пошло не так при попытке повторить запрос.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} не найдено\",\n  \"components.RequestCard.failedretry\": \"Что-то пошло не так при попытке повторить запрос.\",\n  \"components.RequestButton.viewrequest4k\": \"Посмотреть 4К запрос\",\n  \"components.RequestButton.requestmore4k\": \"Запросить больше в 4К\",\n  \"components.RequestButton.requestmore\": \"Запросить больше\",\n  \"components.RequestButton.declinerequests\": \"Отклонить {requestCount, plural, one {запрос} other {{requestCount} запроса(ов)}}\",\n  \"components.RequestButton.declinerequest4k\": \"Отклонить 4К запрос\",\n  \"components.RequestButton.declinerequest\": \"Отклонить запрос\",\n  \"components.RequestButton.approve4krequests\": \"Одобрить {requestCount, plural, one {4К запрос} other {{requestCount} 4К запроса(ов)}}\",\n  \"components.RequestButton.decline4krequests\": \"Отклонить {requestCount, plural, one {4К запрос} other {{requestCount} 4К запроса(ов)}}\",\n  \"components.RequestButton.approverequests\": \"Одобрить {requestCount, plural, one {запрос} other {{requestCount} запроса(ов)}}\",\n  \"components.RequestButton.approverequest4k\": \"Одобрить 4К запрос\",\n  \"components.RequestButton.approverequest\": \"Одобрить запрос\",\n  \"components.RequestBlock.server\": \"Сервер-получатель\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{сезонов} за {quotaDays} {дней}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {сезон} other {сезоны}}\",\n  \"components.RequestBlock.requestoverrides\": \"Переопределение запроса\",\n  \"components.QuotaSelector.unlimited\": \"Неограниченно\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{фильмов} за {quotaDays} {дней}</quotaUnits>\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {день} other {дней}}\",\n  \"components.PersonDetails.birthdate\": \"Рожден(а) {birthdate}\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Предоставить разрешение на просмотр медиа-запросов, отправленных другими пользователями.\",\n  \"components.PermissionEdit.usersDescription\": \"Предоставить разрешение на управление пользователями. Пользователи с этим разрешением не могут предоставлять права администратора и редактировать пользователей, являющихся администраторами.\",\n  \"components.PermissionEdit.requestTvDescription\": \"Предоставить разрешение на отправку запросов всех сериалов, отличных от 4К.\",\n  \"components.PermissionEdit.requestTv\": \"Запросы сериалов\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Предоставить разрешение на отправку запросов всех фильмов, отличных от 4К.\",\n  \"components.PermissionEdit.requestMovies\": \"Запросы фильмов\",\n  \"components.PermissionEdit.requestDescription\": \"Предоставить разрешение на отправку запросов всех медиафайлов, отличных от 4К.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Предоставить разрешение на отправку запросов сериалов в 4К.\",\n  \"components.PermissionEdit.request4kTv\": \"Запросы сериалов в 4К\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Предоставить разрешение на отправку запросов фильмов в 4К.\",\n  \"components.PermissionEdit.request4kMovies\": \"Запросы фильмов в 4К\",\n  \"components.PermissionEdit.request4kDescription\": \"Предоставить разрешение на отправку запросов медиафайлов в 4К.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Предоставить разрешение на управление медиа-запросами. Все запросы пользователя, имеющего данное разрешение, будут одобряться автоматически.\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Предоставить разрешение на автоматическое одобрение всех сериалов, отличных от 4К.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Автоматическое одобрение сериалов\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Предоставить разрешение на автоматическое одобрение 4К фильмов.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Автоматическое одобрение 4К фильмов\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Автоматическое одобрение 4К сериалов\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Предоставить разрешение на автоматическое одобрение 4К сериалов.\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Предоставить разрешение на автоматическое одобрение всех фильмов, отличных от 4К.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Автоматическое одобрение фильмов\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Предоставить разрешение на автоматическое одобрение всех 4К медиа-запросов.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Предоставить разрешение на автоматическое одобрение всех медиа-запросов, отличных от 4К.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Автоматическое одобрение 4К\",\n  \"components.PermissionEdit.autoapprove\": \"Автоматическое одобрение\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Предоставить разрешение на изменение дополнительных параметров запроса.\",\n  \"components.PermissionEdit.advancedrequest\": \"Расширенные запросы\",\n  \"components.PermissionEdit.adminDescription\": \"Администратор имеет полный доступ. Игнорирует все другие настройки разрешений.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Получать уведомления, когда другие пользователи отправляют новые медиа-запросы, требующие одобрения.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Получать уведомления, когда медиа-запросы не удаётся добавить в Radarr или Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Получать уведомления, когда ваши медиа-запросы отклоняются.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Получать уведомления, когда запрошенные вами медиафайлы становятся доступны.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Получать уведомления, когда ваши медиа-запросы получают одобрение.\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {коммит} other {коммитов}} позади\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Студия} other {Студии}}\",\n  \"components.Layout.VersionStatus.streamstable\": \"Стабильная версия Seerr\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Версия Seerr для разработки\",\n  \"components.Layout.VersionStatus.outofdate\": \"Устарела\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Подключение тома <code>{appDataPath}</code> настроено неправильно. Все данные будут удалены при остановке или перезапуске контейнера.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {запросов {type} не осталось} other {осталось <strong>#</strong> запроса(ов) {type}}}\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Вы можете посмотреть сводку ограничений на количество запросов этого пользователя на <ProfileLink>странице его профиля</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Вы можете посмотреть сводку ваших ограничений на количество запросов на <ProfileLink>странице вашего профиля</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Осталось недостаточно запросов на сезоны\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Отправка тестового уведомления веб-перехватчику…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Не удалось отправить тестовое уведомление веб-перехватчику.\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Помощь по переменным шаблона\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"Полезная нагрузка JSON успешно сброшена к настройкам по умолчанию!\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Полезная нагрузка JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Заголовок авторизации\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Настройки веб-push-уведомлений успешно сохранены!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Не удалось сохранить настройки веб-push-уведомлений.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Тестовое веб-push-уведомление отправлено!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Отправка тестового веб-push-уведомления…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Не удалось отправить тестовое веб-push-уведомление.\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Чтобы получать push-уведомления, Seerr должен работать через протокол HTTPS.\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Создайте интеграцию <WebhookLink>входящего веб-перехватчика</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL веб-перехватчика\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Тестовое уведомление отправлено в Slack!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Отправка тестового уведомления в Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Не удалось отправить тестовое уведомление в Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Настройки уведомлений Slack успешно сохранены!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Не удалось сохранить настройки уведомлений Slack.\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Вы должны предоставить действительный ключ пользователя или группы\",\n  \"components.Settings.Notifications.validationTypes\": \"Вы должны выбрать хотя бы один тип уведомлений\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Вы должны выбрать хотя бы один тип уведомлений\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Вы должны выбрать хотя бы один тип уведомлений\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Вы должны выбрать хотя бы один тип уведомлений\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Вы должны выбрать хотя бы один тип уведомлений\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Вы должны предоставить действительный токен приложения\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Ваш тридцатизначный <UsersGroupsLink>идентификатор пользователя или группы</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Тестовое уведомление отправлено в Pushover!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Отправка тестового уведомления в Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Не удалось отправить тестовое уведомление в Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Настройки уведомлений Pushover успешно сохранены!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Не удалось сохранить настройки уведомлений Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Зарегистрируйте приложение</ApplicationRegistrationLink> для использования с Seerr\",\n  \"i18n.view\": \"Посмотреть\",\n  \"i18n.notrequested\": \"Не запрошен\",\n  \"i18n.noresults\": \"Нет результатов.\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Токен API приложения\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Вы должны предоставить токен доступа\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Тестовое уведомление отправлено в Pushbullet!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Отправка тестового уведомления в Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Не удалось отправить тестовое уведомление в Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Настройки уведомлений Pushbullet успешно сохранены!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Не удалось сохранить настройки уведомлений Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Создайте токен в <PushbulletSettingsLink>настройках учётной записи</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Активировать службу\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Активировать службу\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Настройте и активируйте службы уведомлений.\",\n  \"components.ResetPassword.emailresetlink\": \"Отправить ссылку для восстановления по электронной почте\",\n  \"pages.somethingwentwrong\": \"Что-то пошло не так\",\n  \"pages.serviceunavailable\": \"Сервис недоступен\",\n  \"pages.pagenotfound\": \"Страница не найдена\",\n  \"pages.internalservererror\": \"Внутренняя ошибка сервера\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Вы должны предоставить пароль\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Пароль слишком короткий: он должен содержать не менее 8 символов\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Пароли должны совпадать\",\n  \"components.ResetPassword.validationemailrequired\": \"Вы должны указать действительный адрес электронной почты\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Ссылка для сброса пароля будет отправлена на указанный адрес электронной почты, если он связан с действительным пользователем.\",\n  \"components.ResetPassword.gobacklogin\": \"Вернуться на страницу входа\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Языки для поиска фильмов и сериалов\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# сезон} other {# сезонов}}\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Этому пользователю необходимо иметь по крайней мере <strong>{seasons}</strong> {seasons, plural, one {запрос на сезоны} other {запроса(ов) на сезоны}} для того, чтобы отправить запрос на этот сериал.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Вам необходимо иметь по крайней мере <strong>{seasons}</strong> {seasons, plural, one {запрос на сезоны} other {запроса(ов) на сезоны}} для того, чтобы отправить запрос на этот сериал.\",\n  \"components.RequestModal.pending4krequest\": \"Ожидающий 4K запрос\",\n  \"components.RequestModal.autoapproval\": \"Автоматическое одобрение\",\n  \"i18n.usersettings\": \"Настройки пользователя\",\n  \"i18n.showingresults\": \"Показываются результаты с <strong>{from}</strong> по <strong>{to}</strong> из <strong>{total}</strong>\",\n  \"i18n.save\": \"Сохранить изменения\",\n  \"i18n.retrying\": \"Повтор…\",\n  \"i18n.resultsperpage\": \"Отобразить {pageSize} результатов на странице\",\n  \"i18n.requesting\": \"Запрос…\",\n  \"i18n.request4k\": \"Запросить в 4К\",\n  \"i18n.areyousure\": \"Вы уверены?\",\n  \"components.RequestModal.alreadyrequested\": \"Уже запрошен\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Мы не смогли автоматически выполнить ваш запрос. Пожалуйста, выберите правильное совпадение из списка ниже.\",\n  \"components.TvDetails.originaltitle\": \"Название оригинала\",\n  \"i18n.tvshow\": \"Сериал\",\n  \"components.Settings.mediaTypeSeries\": \"сериал\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Регион для поиска фильмов и сериалов\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {сезон} other {сезоны}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"сезон\",\n  \"components.RequestModal.pendingapproval\": \"Ваш запрос ожидает одобрения.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Настройки уведомлений по электронной почте успешно сохранены!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Не удалось сохранить настройки уведомлений по электронной почте.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Язык интерфейса\",\n  \"components.UserList.validationpasswordminchars\": \"Пароль слишком короткий: он должен содержать не менее 8 символов\",\n  \"components.UserList.nouserstoimport\": \"Нет новых пользователей для импорта из Plex.\",\n  \"components.UserList.autogeneratepasswordTip\": \"Отправить пользователю пароль, сгенерированный сервером, по электронной почте\",\n  \"components.TvDetails.viewfullcrew\": \"Посмотреть полную cъёмочную группу\",\n  \"components.TvDetails.showtype\": \"Тип сериала\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Полная съёмочная группа сериала\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Полный актёрский состав сериала\",\n  \"components.Settings.noDefaultNon4kServer\": \"Если вы используете один сервер {serverType} для контента, в том числе и для 4К, или если вы загружаете только контент 4K, ваш сервер {serverType} <strong>НЕ</strong> должен быть помечен как 4К сервер.\",\n  \"components.UserList.localLoginDisabled\": \"Параметр <strong>Включить локальный вход</strong> в настоящее время отключен.\",\n  \"components.Settings.SettingsLogs.showall\": \"Показать все логи\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Ограничение количества запросов на сериалы\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Фильтровать контент по региональной доступности\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Ограничение количества запросов на фильмы\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Переопределить глобальные ограничения\",\n  \"components.Settings.noDefaultServer\": \"По крайней мере один сервер {serverType} должен быть помечен как сервер по умолчанию для обработки запросов на {mediaType}ы.\",\n  \"components.Settings.noDefault4kServer\": \"4K сервер {serverType} должен быть помечен как сервер по умолчанию, чтобы пользователи могли отправлять запросы на 4K {mediaType}ы.\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Вы должны выбрать языковой профиль\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Базовый URL-адрес должен иметь косую черту в начале\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Базовый URL-адрес должен иметь косую черту в начале\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Протестировать подключение для загрузки языковых профилей\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Загрузка тегов…\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Включить автоматический поиск\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Редактировать 4К сервер Sonarr\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Профиль качества для аниме\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Языковой профиль для аниме\",\n  \"components.Settings.SonarrModal.animeTags\": \"Теги для аниме\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Настройки пользователей\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Общее ограничение на количество запросов сериалов\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Настройки пользователей успешно сохранены!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Что-то пошло не так при сохранении настроек.\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Разрешить пользователям {mediaServerName} входить в систему без предварительного импорта\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Включить вход через {mediaServerName} для новых пользователей\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Общее ограничение на количество запросов фильмов\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Разрешить пользователям входить в систему, используя свой адрес электронной почты и пароль\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Включить локальный вход\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Начальные разрешения, присваемые новым пользователям\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Разрешения по умолчанию\",\n  \"components.Settings.SettingsLogs.time\": \"Время\",\n  \"components.Settings.SettingsLogs.level\": \"Важность\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Отладочные\",\n  \"components.Settings.SettingsLogs.extraData\": \"Дополнительная информация\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Скопировать в буфер обмена\",\n  \"components.Settings.serverpresetRefreshing\": \"Получение списка серверов…\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"Задание \\\"{jobname}\\\" запущено.\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Неизвестное задание\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Сканирование Sonarr\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Выполнить сейчас\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Сканирование Radarr\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Сканирование недавно добавленных медиафайлов в Plex\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Полное сканирование библиотек Plex\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Следующее выполнение\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Задания и кэш\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Задания\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Название задания\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"Задание \\\"{jobname}\\\" отменено.\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Отменить задание\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr выполняет определенные задачи по обслуживанию в виде регулярно запланированных заданий, но они также могут быть запущены вручную ниже. Выполнение задания вручную не изменит его расписание.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Очистить кэш\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Сбросить синхронизацию загрузок\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Синхронизировать загрузки\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Удачных обращений\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Неудачных обращений\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Размер значений\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Актуальная\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Изменения в версии {version}\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} кэш сброшен.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr кэширует запросы к внешним API, чтобы оптимизировать производительность и избежать ненужных запросов к API.\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Всего мультимедиа\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Устарела\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Получить поддержку\",\n  \"components.Settings.SettingsAbout.about\": \"О проекте\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Посмотреть на GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Посмотреть список изменений\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Данные о релизе в настоящее время недоступны.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Вы должны ввести новый пароль\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Вы должны предоставить действительный ID чата\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Вы должны предоставить действительный открытый ключ PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Вы должны предоставить действительный ID пользователя\",\n  \"components.UserList.validationEmail\": \"Email обязателен\",\n  \"components.UserList.usercreatedfailedexisting\": \"Указанный адрес электронной почты уже используется другим пользователем.\",\n  \"components.TvDetails.streamingproviders\": \"Сейчас транслируется\",\n  \"components.Settings.validationPortRequired\": \"Вы должны указать действительный номер порта\",\n  \"components.Settings.validationHostnameRequired\": \"Вы должны указать действительное имя хоста или IP-адрес\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Вы должны указать имя сервера\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Вы должны указать имя сервера\",\n  \"components.Settings.Notifications.validationEmail\": \"Вы должны указать действительный адрес электронной почты\",\n  \"components.MovieDetails.streamingproviders\": \"Сейчас транслируется\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Базовый URL-адрес не должен заканчиваться косой чертой\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Вы должны выбрать минимальную доступность\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Базовый URL-адрес не должен заканчиваться косой чертой\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL-адрес не должен заканчиваться косой чертой\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Протестировать подключение для загрузки тегов\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Протестировать подключение для загрузки профилей качества\",\n  \"components.Settings.RadarrModal.selecttags\": \"Выберите теги\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Тегов нет.\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Загрузка профилей качества…\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Загрузка тегов…\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Включить автоматический поиск\",\n  \"components.Settings.RadarrModal.default4kserver\": \"4К сервер по умолчанию\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Создайте <DiscordWebhookLink>интеграцию веб-перехватчика</DiscordWebhookLink> на своём сервере\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Настройки уведомлений веб-перехватчика успешно сохранены!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Не удалось сохранить настройки уведомлений веб-перехватчика.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Тестовое уведомление веб-перехватчику отправлено!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL веб-перехватчика\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Вы должны предоставить действительный закрытый ключ PGP\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Вы должны предоставить пароль PGP\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Вы должны предоставить действительный ID чата\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Вы должны предоставить токен авторизации бота\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Не удалось сохранить настройки уведомлений Telegram.\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Подписывать зашифрованные сообщения электронной почты с помощью <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Закрытый ключ PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Подписывать зашифрованные сообщения электронной почты с помощью <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPassword\": \"Пароль PGP\",\n  \"components.Settings.Notifications.encryptionTip\": \"В большинстве случаев неявный TLS использует порт 465, а STARTTLS – порт 587\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Всегда использовать STARTTLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"Без шифрования\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Использовать неявный TLS\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Использовать STARTTLS, если доступно\",\n  \"components.Settings.Notifications.encryption\": \"Метод шифрования\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Настройки уведомлений по электронной почте успешно сохранены!\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Не удалось сохранить настройки уведомлений по электронной почте.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Настройки уведомлений Discord успешно сохранены!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Не удалось сохранить настройки уведомлений Discord.\",\n  \"components.Settings.Notifications.chatIdTip\": \"Начните чат со своим ботом, добавьте <GetIdBotLink>@get_id_bot</GetIdBotLink> и выполните команду <code>/my_id</code>\",\n  \"components.Settings.Notifications.chatId\": \"ID чата\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Разрешить пользователям начинать чат с вашим ботом и настраивать свои собственные уведомления\",\n  \"components.Settings.Notifications.botUsername\": \"Имя бота\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL аватара бота\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Создайте бота</CreateBotLink> для использования с Seerr\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Разрешить самозаверенные сертификаты\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Вы должны предоставить допустимую полезную нагрузку JSON\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Тестовое уведомление отправлено в Telegram!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Отправка тестового уведомления в Telegram…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Тестовое уведомление отправлено в Discord!\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Отправка тестового уведомления в Discord…\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Не удалось отправить тестовое уведомление в Discord.\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Не удалось отправить тестовое уведомление в Telegram.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Тестовое уведомление отправлено по электронной почте!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Отправка тестового уведомления по электронной почте…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Не удалось отправить тестовое уведомление по электронной почте.\",\n  \"components.UserProfile.unlimited\": \"Неограниченно\",\n  \"components.UserProfile.totalrequests\": \"Всего запросов\",\n  \"components.UserProfile.requestsperdays\": \"осталось {limit}\",\n  \"components.UserProfile.pastdays\": \"{type} (за {days} день(ей))\",\n  \"components.UserProfile.seriesrequest\": \"Запросов сериалов\",\n  \"components.UserProfile.movierequests\": \"Запросов фильмов\",\n  \"components.UserProfile.limit\": \"{remaining} из {limit}\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"У вас нет разрешения на изменение настроек этого пользователя.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"У вас нет разрешения на изменение пароля этого пользователя.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Пароли должны совпадать\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Что-то пошло не так при сохранении пароля. Правильно ли введен ваш текущий пароль?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Что-то пошло не так при сохранении пароля.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"В настоящее время для этой учётной записи не установлен пароль. Установите пароль ниже, чтобы с этой учётной записью можно было войти в систему как \\\"локальный пользователь\\\".\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"В настоящее время для вашей учётной записи не установлен пароль. Установите пароль ниже, чтобы иметь возможность войти в систему как \\\"локальный пользователь\\\", используя свой адрес электронной почты.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Веб-push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Настройки уведомлений Telegram успешно сохранены!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Не удалось сохранить настройки уведомлений Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Начните чат</TelegramBotLink>, добавьте <GetIdBotLink>@get_id_bot</GetIdBotLink> и выполните команду <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID чата\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Отправлять без звука\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Шифровать сообщения электронной почты с помощью <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Открытый ключ PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Настройки уведомлений\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Электронная почта\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Настройки уведомлений Discord успешно сохранены!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Не удалось сохранить настройки уведомлений Discord.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"<FindDiscordIdLink>ID</FindDiscordIdLink> вашей учётной записи\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID пользователя\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Тип учётной записи\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID пользователя: {userid}\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Редактировать настройки\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Присоединился {joindate}\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Пароль слишком короткий: он должен содержать не менее 8 символов\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Вы не можете изменять собственные разрешения.\",\n  \"components.UserList.userssaved\": \"Разрешения пользователя успешно сохранены!\",\n  \"components.UserList.userfail\": \"Что-то пошло не так при сохранении разрешений пользователя.\",\n  \"components.UserList.userdeleteerror\": \"Что-то пошло не так при удалении пользователя.\",\n  \"components.UserList.usercreatedfailed\": \"Что-то пошло не так при создании пользователя.\",\n  \"components.UserList.passwordinfodescription\": \"Настройте URL-адрес приложения и включите уведомления по электронной почте, чтобы обеспечить возможность автоматической генерации пароля.\",\n  \"components.UserList.importfromplexerror\": \"Что-то пошло не так при импорте пользователей из Plex.\",\n  \"components.UserList.importfrommediaserver\": \"Импортировать пользователей из {mediaServerName}\",\n  \"components.UserList.importfromplex\": \"Импортировать пользователей из Plex\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> {userCount, plural, one {# новый пользователь} other {# новых пользователя(ей)}} успешно импортированы из Plex!\",\n  \"components.UserList.edituser\": \"Изменить разрешения пользователя\",\n  \"components.UserList.deleteconfirm\": \"Вы уверены, что хотите удалить этого пользователя? Все данные о его запросах будут удалены без возможности восстановления.\",\n  \"components.UserList.autogeneratepassword\": \"Сгенерировать пароль автоматически\",\n  \"components.UserList.accounttype\": \"Тип\",\n  \"components.TvDetails.nextAirDate\": \"Следующая дата выхода в эфир\",\n  \"components.TvDetails.firstAirDate\": \"Дата выхода в эфир\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} минут\",\n  \"components.TvDetails.episodeRuntime\": \"Продолжительность эпизода\",\n  \"components.Settings.webpush\": \"Веб-push\",\n  \"components.Settings.webAppUrlTip\": \"При необходимости направляйте пользователей в веб-приложение на вашем сервере вместо размещённого на plex.tv\",\n  \"components.Settings.webAppUrl\": \"URL <WebAppLink>веб-приложения</WebAppLink>\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Список серверов Plex успешно получен!\",\n  \"components.Settings.toastPlexRefresh\": \"Получение списка серверов Plex…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Не удалось получить список серверов Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"Попытка подключения к Plex…\",\n  \"components.Settings.settingUpPlexDescription\": \"Чтобы настроить Plex, вы можете либо ввести данные вручную, либо выбрать сервер, полученный со страницы <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Нажмите кнопку справа от выпадающего списка, чтобы получить список доступных серверов.\",\n  \"components.Settings.services\": \"Службы\",\n  \"components.Settings.serviceSettingsDescription\": \"Настройте сервер(ы) {serverType} ниже. Вы можете подключить несколько серверов {serverType}, но только два из них могут быть помечены как серверы по умолчанию (один не 4К и один 4К). Администраторы могут переопределить сервер для обработки новых запросов до их одобрения.\",\n  \"components.Settings.serverpresetLoad\": \"Нажмите кнопку, чтобы загрузить список доступных серверов\",\n  \"components.Settings.serverSecure\": \"защищённый\",\n  \"components.Settings.serverRemote\": \"удалённый\",\n  \"components.Settings.serverLocal\": \"локальный\",\n  \"components.Settings.scan\": \"Синхронизировать библиотеки\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Вы также можете просматривать эти логи напрямую через <code>stdout</code> или в <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.logs\": \"Логи\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Подробные сведения о логе\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Сообщение лога скопировано в буфер обмена.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Контент фильтруется по языку оригинала\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"По умолчанию ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Общее\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Настройте глобальные параметры и параметры по умолчанию для пользователей.\",\n  \"components.Settings.email\": \"Электронная почта\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL-адрес не должен заканчиваться косой чертой\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Соединение с Plex установлено успешно!\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Соединение с Sonarr установлено успешно!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Не удалось подключиться к Plex.\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Не удалось подключиться к Sonarr.\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Протестировать подключение для загрузки тегов\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Протестировать подключение для загрузки профилей качества\",\n  \"components.Settings.SonarrModal.selecttags\": \"Выберите теги\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Выберите языковой профиль\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Тегов нет.\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Загрузка профилей качества…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Загрузка языковых профилей…\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Добавить новый 4К сервер Sonarr\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Редактировать 4К сервер Radarr\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Добавить новый 4К сервер Radarr\",\n  \"components.Settings.SonarrModal.default4kserver\": \"4К сервер по умолчанию\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Изменить задание\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Частота\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Задание успешно отредактировано!\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Вы используете ветку <code>develop</code> проекта Seerr, которая рекомендуется только для тех, кто вносит вклад в разработку или помогает в тестировании.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Что-то пошло не так при сохранении задания.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Каждый {jobScheduleHours, plural, one {час} other {{jobScheduleHours} часа(ов)}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Каждую {jobScheduleMinutes, plural, one {минуту} other {{jobScheduleMinutes} минут(ы)}}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Вы уверены, что хотите удалить этот комментарий?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Удалить комментарий\",\n  \"components.IssueDetails.IssueComment.edit\": \"Редактировать комментарий\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Опубликовано {relativeTime} пользователем {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Опубликовано {relativeTime} пользователем {username} (изменено)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Вы должны ввести сообщение\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Удалить проблему\",\n  \"components.IssueDetails.IssueDescription.description\": \"Описание\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Редактировать описание\",\n  \"components.IssueDetails.allseasons\": \"Все сезоны\",\n  \"components.IssueDetails.allepisodes\": \"Все эпизоды\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Очистить данные\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Это приведёт к необратимому удалению всех данных для этого {mediaType}а, включая любые запросы. Если этот элемент существует в вашей библиотеке {mediaServerName}, мультимедийная информация о нём будет воссоздана во время следующего сканирования.\",\n  \"components.IssueDetails.problemepisode\": \"Затронутый эпизод\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Запросы\",\n  \"components.IssueDetails.closeissue\": \"Закрыть проблему\",\n  \"components.IssueDetails.closeissueandcomment\": \"Закрыть с комментарием\",\n  \"components.IssueDetails.comments\": \"Комментарии\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Вы уверены, что хотите удалить эту проблему?\",\n  \"components.IssueDetails.episode\": \"Эпизод {episodeNumber}\",\n  \"components.IssueDetails.lastupdated\": \"Последнее обновление\",\n  \"components.IssueDetails.openinarr\": \"Открыть в {arr}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Что-то пошло не так при редактировании описания проблемы.\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Что-то пошло не так при удалении проблемы.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Что-то пошло не так при обновлении статуса проблемы.\",\n  \"components.IssueDetails.unknownissuetype\": \"Неизвестный\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Эпизод {episodeNumber}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Пометить как доступный в 4К\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Дополнительно\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Затронутый сезон\",\n  \"components.ManageSlideOver.downloadstatus\": \"Загрузки\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Открытые проблемы\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Запросов нет.\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Управление {mediaType}ом\",\n  \"components.ManageSlideOver.markavailable\": \"Пометить как доступный\",\n  \"components.ManageSlideOver.movie\": \"фильм\",\n  \"components.ManageSlideOver.openarr\": \"Открыть в {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Открыть в 4К {arr}\",\n  \"components.ManageSlideOver.tvshow\": \"сериал\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Получать уведомления, когда проблемы, о которых вы сообщили, получают решение.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Комментарий к проблеме\",\n  \"components.PermissionEdit.createissuesDescription\": \"Предоставить разрешение на сообщения о проблемах с медиафайлами.\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Предоставить разрешение на управление проблемами с медиафайлами.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Получать уведомления, когда другие пользователи сообщают о проблемах.\",\n  \"components.PermissionEdit.createissues\": \"Сообщения о проблемах\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Настройки уведомлений Pushover успешно сохранены!\",\n  \"components.PermissionEdit.viewissues\": \"Просмотр проблем\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Предоставить разрешение на просмотр проблем с медиафайлами, о которых сообщили другие пользователи.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Вы должны предоставить действительный ключ пользователя или группы\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Токен доступа\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Токен API приложения\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Создайте токен на странице <PushbulletSettingsLink>настроек вашей учётной записи</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Вы должны предоставить действительный токен приложения\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Ваш 30-значный <UsersGroupsLink>идентификатор пользователя или группы</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Не удалось сохранить настройки уведомлений Pushbullet.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Настройки уведомлений Pushbullet успешно сохранены!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Зарегистрируйте приложение</ApplicationRegistrationLink> для использования с {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Ключ пользователя или группы\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Не удалось сохранить настройки уведомлений Pushover.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Вы должны предоставить токен доступа\",\n  \"i18n.resolved\": \"Решённые\",\n  \"components.IssueDetails.openedby\": \"#{issueId} открыта {relativeTime} пользователем {username}\",\n  \"components.IssueDetails.openin4karr\": \"Открыть в 4К {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Воспроизвести в {mediaServerName} в 4К\",\n  \"components.IssueDetails.problemseason\": \"Затронутый сезон\",\n  \"components.IssueDetails.reopenissue\": \"Снова открыть проблему\",\n  \"components.IssueDetails.season\": \"Сезон {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Описание проблемы успешно отредактировано!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Проблема успешно удалена!\",\n  \"components.IssueDetails.toaststatusupdated\": \"Статус проблемы успешно обновлен!\",\n  \"components.IssueList.IssueItem.issuetype\": \"Тип\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Все сезоны\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Затронутый эпизод\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Что-то пошло не так при отправке проблемы.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Отчёт о проблеме для <strong>{title}</strong> успешно отправлен!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Просмотреть проблему\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Вы должны предоставить описание\",\n  \"components.IssueModal.issueAudio\": \"Аудио\",\n  \"components.IssueModal.issueOther\": \"Другое\",\n  \"components.IssueModal.issueSubtitles\": \"Субтитры\",\n  \"components.IssueModal.issueVideo\": \"Видео\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Сообщить о проблеме\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Получать уведомления, когда другие пользователи остовляют комментарии к проблемам.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Получать уведомления, когда к проблемам, о которых вы сообщили, появляются новые комментарии.\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Отправлять уведомления, когда к проблемам появляются новые комментарии.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Проблема опубликована\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Проблема решена\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Отправлять уведомления, когда проблемы получают решение.\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Отправлять уведомления, когда появляются сообщения о проблемах.\",\n  \"components.PermissionEdit.manageissues\": \"Управление проблемами\",\n  \"i18n.open\": \"Открыть\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Затронутый эпизод\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Неизвестный\",\n  \"components.IssueList.issues\": \"Проблемы\",\n  \"components.IssueList.IssueItem.opened\": \"Открыта\",\n  \"components.IssueDetails.nocomments\": \"Комментариев нет.\",\n  \"components.IssueDetails.issuepagetitle\": \"Проблема\",\n  \"components.IssueDetails.deleteissue\": \"Удалить проблему\",\n  \"components.IssueDetails.issuetype\": \"Тип\",\n  \"components.IssueDetails.leavecomment\": \"Комментарий\",\n  \"components.IssueDetails.playonplex\": \"Воспроизвести в {mediaServerName}\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Снова открыть с комментарием\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Статус\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезоны}}\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Эпизод} other {Эпизоды}}\",\n  \"components.IssueList.IssueItem.viewissue\": \"Просмотреть проблему\",\n  \"components.IssueList.showallissues\": \"Показать все проблемы\",\n  \"components.IssueList.sortModified\": \"По дате изменения\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Все эпизоды\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} пользователем {user}\",\n  \"components.IssueList.sortAdded\": \"По дате добавления\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Сезон {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Отправить проблему\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Пожалуйста, предоставьте подробное описание проблемы, с которой вы столкнулись.\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Что не так?\",\n  \"components.Layout.Sidebar.issues\": \"Проблемы\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Отправлять уведомления, когда проблемы открыты заново.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Получать уведомления, когда проблемы о которых вы сообщили будут открыты заново.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Получать уведомления, когда проблемы открыты заново другими пользователями.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Проблема открыта заново\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Получать уведомления, когда проблемы решены другими пользователями.\",\n  \"components.RequestModal.requestseasons4k\": \"Запрос {seasonCount} {seasonCount, plural, one {сезона} other {сезонов}} в 4К\",\n  \"components.TvDetails.productioncountries\": \"{countryCount, plural, one {Страна} other {Страны}} производства\",\n  \"components.IssueDetails.commentplaceholder\": \"Добавить комментарий…\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {Страна} other {Страны}} производства\",\n  \"components.RequestModal.selectmovies\": \"Выберите фильм(ы)\",\n  \"components.RequestModal.approve\": \"Одобрить запрос\",\n  \"components.RequestModal.requestmovies\": \"Запрос {count} {count, plural, one {фильма} other {фильмов}}\",\n  \"components.RequestModal.requestmovies4k\": \"Запрос {count} {count, plural, one {фильма} other {фильмов}} в 4К\",\n  \"components.Settings.RadarrModal.inCinemas\": \"В кино\",\n  \"components.Settings.RadarrModal.released\": \"Выпущен\",\n  \"components.RequestModal.requestApproved\": \"Запрос на <strong>{title}</strong> одобрен!\",\n  \"components.Settings.RadarrModal.announced\": \"Анонсирован\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Медиа\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4К медиа\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Отметить все сезоны как \\\"Доступные\\\" (4K)\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Отметить все сезоны как \\\"Доступные\\\"\",\n  \"components.ManageSlideOver.opentautulli\": \"Открыть в Tautulli\",\n  \"components.MovieDetails.managemovie\": \"Управление фильмом\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Запрос отправлен автоматически\",\n  \"components.PermissionEdit.autorequestMovies\": \"Авто запрос фильмов\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Предоставить разрешение на автоматическое одобрение медиа-запросов фильмов, отличных от 4К, через список просмотра Plex.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Ваш список просмотра\",\n  \"components.Discover.moviegenres\": \"Жанры фильма\",\n  \"components.Discover.studios\": \"Студии\",\n  \"components.Discover.networks\": \"Телеканалы\",\n  \"components.Discover.tmdbmoviekeyword\": \"Ключевое слово TMDB\",\n  \"components.MovieDetails.reportissue\": \"Сообщить о проблеме\",\n  \"components.PermissionEdit.autorequestSeries\": \"Авто запрос сериалов\",\n  \"components.PermissionEdit.autorequest\": \"Авто запрос\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Предоставить разрешение на просмотр списка недавно добавленных медиафайлов.\",\n  \"components.PermissionEdit.viewrecent\": \"Просмотр недавно добавленного\",\n  \"components.PermissionEdit.viewwatchlists\": \"Просмотр списков просмотра Plex\",\n  \"components.Discover.plexwatchlist\": \"Ваш список просмотра\",\n  \"components.Discover.CreateSlider.editSlider\": \"Редактировать слайдер\",\n  \"components.Discover.CreateSlider.addSlider\": \"Добавить слайдер\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Создать слайдер\",\n  \"components.Discover.CreateSlider.nooptions\": \"Нет результатов.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Введите TMDB ID жанра\",\n  \"components.Discover.CreateSlider.needresults\": \"Должен быть хотя-бы 1 результат.\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Введите TMDB ID ключевого слова\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Введите TMDB ID сети\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Введите поисковой запрос\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Введите TMDB ID студии\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Поиск жанров…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Ключевые слова для поиска…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Поиск студий…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Название слайдера\",\n  \"components.Discover.CreateSlider.starttyping\": \"Начните ввод для поиска.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Вы должны ввести дату.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Вы должны ввести заголовок.\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"Фильмы по ключевому слову \\\"{keywordTitle}\\\"\",\n  \"components.Discover.CreateSlider.editfail\": \"Ошибка редактирования слайдера.\",\n  \"components.Discover.CreateSlider.addfail\": \"Ошибка создания слайдера.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Слайдер отредактирован и настройки кастомизации сохранены.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Новый слайдер создан и настройки кастомизации сохранены.\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Список просмотра Plex\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Здесь будут отображаться медиаданные, добавленные в ваш <PlexWatchlistSupportLink>список просмотра Plex</PlexWatchlistSupportLink>.\",\n  \"components.Layout.Sidebar.browsetv\": \"Сериалы\",\n  \"components.Discover.tvgenres\": \"Жанры сериалов\",\n  \"components.Layout.UserDropdown.requests\": \"Запросы\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Дополнительно\",\n  \"components.ManageSlideOver.pastdays\": \"Прошло {days, number} дней\",\n  \"components.PermissionEdit.autorequestDescription\": \"Предоставить разрешение на автоматическое одобрение всех медиа-запросов, отличных от 4К, через список просмотра Plex.\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Получайте уведомления, когда новые запросы автоматически отправляются для элементов в вашем списке просмотра Plex.\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Предоставить разрешение на автоматическое одобрение запросов сериалов, отличных от 4К, через список просмотра Plex.\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Активный фильтр} other {# Активные фильтры}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Фильмы\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Популярность по возрастанию\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Популярность по убыванию\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Дата выпуска по возрастанию\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Дата выпуска по убыванию\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Название (A-Z) по возрастанию\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Название (Z-A) По убыванию\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Рейтинг TMDB по возрастанию\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Рейтинг TMDB по убыванию\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Ошибка удаления слайдера.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Слайдер успешно удален.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Изменить видимость\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Удалить\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Активный фильтр} other {# Активные фильтры}}\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Сериалы\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Популярность по возрастанию\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Популярность по убыванию\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Название (A-Z) по возрастанию\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Название (Z-A) По убыванию\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Рейтинг TMDB по возрастанию\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Рейтинг TMDB по убыванию\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"Сериалы по ключевому слову \\\"{keywordTitle}\\\"\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Ваш список просмотра\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Активный фильтр} other {# Активные фильтры}}\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Очистить все активные фильтры\",\n  \"components.Discover.FilterSlideover.filters\": \"Фильтры\",\n  \"components.Discover.FilterSlideover.genres\": \"Жанры\",\n  \"components.Discover.FilterSlideover.keywords\": \"Ключевые слова\",\n  \"components.Discover.FilterSlideover.from\": \"От\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Язык оригинала\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Рейтинг с {minValue} до {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Дата релиза\",\n  \"components.Discover.FilterSlideover.runtime\": \"Длительность\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"длительность {minValue}-{maxValue} минут\",\n  \"components.Discover.FilterSlideover.studio\": \"Студия\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Рейтинг пользователей TMDB\",\n  \"components.Discover.resettodefault\": \"По умолчанию\",\n  \"components.Discover.resetwarning\": \"Сброс всех настроек слайдеров. Это действие так же удалит все пользовательские слайдеры!\",\n  \"components.Discover.tmdbnetwork\": \"Телеканал TMDB\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Запросы фильмов\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Сезон {seasonNumber} Эпизод {episodeNumber}\",\n  \"components.Discover.emptywatchlist\": \"Здесь будут отображаться медиаданные, добавленные в ваш <PlexWatchlistSupportLink>список просмотра Plex</PlexWatchlistSupportLink>.\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Стриминговые сервисы\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Недавно добавлено\",\n  \"components.Discover.createnewslider\": \"Создать новый слайдер\",\n  \"components.Discover.FilterSlideover.to\": \"До\",\n  \"components.Discover.stopediting\": \"Закончить редактирование\",\n  \"components.Discover.tmdbmoviegenre\": \"Жанр фильма TMDB\",\n  \"components.Discover.tmdbsearch\": \"Поиск TMDB\",\n  \"components.Discover.tmdbstudio\": \"Студия TMDB\",\n  \"components.Discover.tmdbtvgenre\": \"Жанр сериала TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Ключевое слово сериала TMDB\",\n  \"components.Layout.Sidebar.browsemovies\": \"Фильмы\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Запросы сериалов\",\n  \"components.MovieDetails.rtaudiencescore\": \"Рейтинг Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Рейтинг Rotten Tomatoes\",\n  \"components.MovieDetails.tmdbuserscore\": \"Рейтинг пользователей TMDB\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Текущая частота\",\n  \"i18n.import\": \"Импортировать\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Тег канала\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Каждую {jobScheduleSeconds, plural, one {секунду} other {{jobScheduleSeconds} секунд}}\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Пожалуйста, перезапустите сервер, чтобы применить обновленные настройки.\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Эпизод} other {# Эпизодов}}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID пользователя Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Вы должны предоставить действительный идентификатор пользователя Discord\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Предоставьте разрешение на просмотр списков просмотра Plex других пользователей.\",\n  \"components.UserList.newplexsigninenabled\": \"Параметр <strong>Включить новый вход в Plex</strong> в настоящее время включен. Пользователей Plex с доступом к библиотеке не нужно импортировать для входа.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Автоматический запрос фильмов\",\n  \"components.MovieDetails.digitalrelease\": \"Цифровой релиз\",\n  \"components.MovieDetails.physicalrelease\": \"Физический релиз\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Что-то пошло не так при сохранении настроек.\",\n  \"components.Settings.experimentalTooltip\": \"Включение этого параметра может привести к неожиданному поведению приложения\",\n  \"components.Settings.advancedTooltip\": \"Неправильная настройка этого параметра может привести к нарушению функциональности\",\n  \"components.Settings.externalUrl\": \"Внешний URL-адрес\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL приложения\",\n  \"components.Settings.urlBase\": \"Базовый URL-адрес\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} обновлено\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.Settings.validationApiKey\": \"Вы должны предоставить ключ API\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} не найдено\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.Settings.restartrequiredTooltip\": \"Чтобы изменения этого параметра вступили в силу, необходимо перезапустить Seerr\",\n  \"components.ManageSlideOver.alltime\": \"Все время\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {просмотр} other {просмотров}}\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Включить агент\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Настройки уведомлений Gotify успешно сохранены!\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Просмотреть детали\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Автоматически запрашивать серии в вашем <PlexWatchlistSupportLink>списке просмотра Plex</PlexWatchlistSupportLink>\",\n  \"i18n.restartRequired\": \"Требуется перезагрузка\",\n  \"components.ManageSlideOver.playedby\": \"Просмотрен\",\n  \"components.RequestBlock.approve\": \"Одобрить запрос\",\n  \"components.RequestBlock.lastmodifiedby\": \"Последнее изменение\",\n  \"components.RequestCard.declinerequest\": \"Отклонить запрос\",\n  \"components.RequestCard.cancelrequest\": \"Отменить запрос\",\n  \"components.Settings.SettingsMain.apikey\": \"Ключ API\",\n  \"components.Settings.SettingsMain.general\": \"Общие\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Фильтровать контент по исходному языку\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Вы должны указать действительный URL\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL не должен заканчиваться косой чертой\",\n  \"components.StatusChecker.reloadApp\": \"Перезагрузить {applicationTitle}\",\n  \"components.TvDetails.manageseries\": \"Управление сериалом\",\n  \"components.TvDetails.reportissue\": \"Сообщить о проблеме\",\n  \"components.TvDetails.tmdbuserscore\": \"Рейтинг пользователей TMDB\",\n  \"components.UserProfile.emptywatchlist\": \"Здесь будут отображаться медиаданные, добавленные в ваш <PlexWatchlistSupportLink>список просмотра Plex</PlexWatchlistSupportLink>.\",\n  \"components.UserProfile.recentlywatched\": \"Недавно просмотренные\",\n  \"i18n.importing\": \"Импорт…\",\n  \"components.StatusBadge.managemedia\": \"Управлять {mediaType}\",\n  \"components.StatusBadge.playonplex\": \"Играть в Plex\",\n  \"components.StatusChecker.restartRequired\": \"Требуется перезагрузка сервера\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Пожалуйста, нажмите кнопку ниже, чтобы перезагрузить приложение.\",\n  \"components.Settings.Notifications.enableMentions\": \"Включить упоминания\",\n  \"components.AirDateBadge.airedrelative\": \"В эфире {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Трансляция {relativeTime}\",\n  \"components.TvDetails.seasonnumber\": \"Сезон {seasonNumber}\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Ошибка отправки тестового уведомления Gotify.\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Очистка кэша изображения\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Изображений кэшированно\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Синхронизация списка просмотра Plex\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Название приложения\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Кэшировать изображения из внешних источников (требуется значительный объем дискового пространства)\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Разрешить запрашивать сериалы частично\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Новый ключ API успешно сгенерирован!\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Настройки успешно сохранены!\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Вы должны указать название приложения\",\n  \"components.Settings.deleteServer\": \"Удалить сервер {serverType}\",\n  \"components.Settings.tautulliApiKey\": \"Ключ API\",\n  \"components.Settings.validationUrl\": \"Вы должны указать действительный URL\",\n  \"components.TitleCard.cleardata\": \"Очистить данные\",\n  \"components.TvDetails.Season.noepisodes\": \"Список эпизодов недоступен.\",\n  \"components.TvDetails.seasonstitle\": \"Сезоны\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Папка конфигурации\",\n  \"components.RequestCard.editrequest\": \"Редактировать запрос\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Дата выхода в эфир по возрастанию\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Дата первого выхода в эфир по убыванию\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Дата выхода в эфир\",\n  \"components.Discover.updatesuccess\": \"Настройки обнаружения успешно обновлены.\",\n  \"components.RequestBlock.decline\": \"Отклонить запрос\",\n  \"components.RequestBlock.delete\": \"Удалить запрос\",\n  \"components.RequestBlock.edit\": \"Редактировать запрос\",\n  \"components.RequestBlock.languageprofile\": \"Языковой профиль\",\n  \"components.RequestBlock.requestdate\": \"Дата запроса\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Неизвестный заголовок\",\n  \"components.RequestModal.requestcollectiontitle\": \"Запросить Коллекцию\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Запросить фильм в 4К\",\n  \"components.RequestModal.requestmovietitle\": \"Запросить фильм\",\n  \"components.RequestModal.requestseriestitle\": \"Запросить сериал\",\n  \"components.RequestModal.requestseries4ktitle\": \"Запросить сериал в 4К\",\n  \"components.Selector.nooptions\": \"Нет результатов.\",\n  \"components.Selector.searchGenres\": \"Выберите жанры…\",\n  \"components.Selector.searchKeywords\": \"Ключевые слова для поиска…\",\n  \"components.Selector.starttyping\": \"Начните ввод для поиска.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Ошибка сохранения настроек Gotify.\",\n  \"components.Selector.searchStudios\": \"Поиск студий…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Тестовое уведомление Gotify отправлено!\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL сервера\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Отправка тестового уведомления Gotify…\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Включить кэширование изображений\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Общие настройки\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Настройте глобальные параметры и параметры по умолчанию для Seerr.\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Скрыть доступные медиа\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Что-то пошло не так при создании нового ключа API.\",\n  \"components.Settings.SettingsMain.locale\": \"Язык приложения\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Языки для поиска фильмов и сериалов\",\n  \"components.Settings.tautulliSettingsDescription\": \"При желании настройте параметры для вашего сервера Tautulli. Seerr получает историю просмотров Plex из Tautulli.\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Что-то пошло не так при сохранении настроек Tautulli.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Настройки Tautulli успешно сохранены!\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"База URL не должна заканчиваться косой чертой\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL не должен заканчиваться косой чертой\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Что-то пошло не так при получении данных о сериале.\",\n  \"components.TvDetails.rtaudiencescore\": \"Рейтинг пользователей Rotten Tomatoes\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes томатометр\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"<FindDiscordIdLink>Многозначный идентификационный номер</FindDiscordIdLink>, связанный с вашей учетной записью пользователя Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Автоматически запрашивать фильмы из вашего <PlexWatchlistSupportLink>списка просмотра Plex</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Автоматический запрос сериалов\",\n  \"components.UserProfile.plexwatchlist\": \"Список просмотра Plex\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Кэш изображений\",\n  \"components.StatusBadge.openinarr\": \"Открыть в {arr}\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Нам не удалось найти совпадение для этого сериала.\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Токен приложения\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Вы должны указать токен приложения\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Вы должны выбрать как минимум один тип уведомления\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Вы должны указать действующий URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL не должен заканчиваться слешем\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Если включено, Seerr будет проксировать и кэшировать изображения из предварительно настроенных внешних источников. Кэшированные изображения сохраняются в папку конфигурации. Вы можете найти файлы в <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.tautulliSettings\": \"Настройки Tautulli\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Discover.customizediscover\": \"Настроить Обнаружение\",\n  \"components.Discover.resetfailed\": \"Что-то пошло не так при сбросе настроек настройки обнаружения.\",\n  \"components.Discover.resetsuccess\": \"Настройки обнаружения успешно сброшены.\",\n  \"components.Discover.updatefailed\": \"Что-то пошло не так при обновлении настроек обнаружения.\",\n  \"components.MovieDetails.theatricalrelease\": \"Релиз в театре\",\n  \"components.RequestBlock.requestedby\": \"Запрос от\",\n  \"components.RequestCard.approverequest\": \"Одобрить запрос\",\n  \"components.RequestCard.unknowntitle\": \"Неизвестный заголовок\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Запросить Коллекцию в 4К\",\n  \"components.Selector.showless\": \"Показать меньше\",\n  \"components.Selector.showmore\": \"Показать больше\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Размер кэша\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Базовый URL должен начинаться с косой черты\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Требуется указать email адрес.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Требуется указать пароль.\",\n  \"components.Login.emailtooltip\": \"Адрес не обязательно должен быть связан с вашим {mediaServerName} сервером.\",\n  \"components.Login.initialsignin\": \"Подключиться\",\n  \"components.Login.initialsigningin\": \"Подключение…\",\n  \"components.Login.save\": \"Добавить\",\n  \"components.Login.saving\": \"Добавление…\",\n  \"components.Login.signinwithjellyfin\": \"Используйте свой {mediaServerName} аккаунт\",\n  \"components.Login.username\": \"Имя пользователя\",\n  \"components.Login.validationEmailFormat\": \"Неверный email\",\n  \"components.Login.validationemailformat\": \"Необходим корректный email\",\n  \"components.Login.validationhostformat\": \"Необходим корректный URL\",\n  \"components.Login.validationhostrequired\": \"Необходим {mediaServerName} URL\",\n  \"components.Login.validationusernamerequired\": \"Необходимо имя пользователя\",\n  \"components.ManageSlideOver.removearr\": \"Удалить из {arr}\",\n  \"components.ManageSlideOver.removearr4k\": \"Удалить из 4К {arr}\",\n  \"components.MovieDetails.imdbuserscore\": \"Оценка пользователей IMDB - голосов: {formattedCount}\",\n  \"components.MovieDetails.openradarr\": \"Открыть фильм в Radarr\",\n  \"components.MovieDetails.play\": \"Запустить на {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Запустить 4К на {mediaServerName}\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Тег запросов\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Неверный email адрес.\",\n  \"components.Settings.SonarrModal.seriesType\": \"Тип сериала\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Количество голосов от {minValue} до {maxValue}\",\n  \"components.Login.validationEmailRequired\": \"Вы должны указать адрес электронной почты\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Требуется email пользователя\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Сканировать недавно добавленное в Jellyfin\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Сервисы потоковой передачи фильмов TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Сервисы потоковой передачи сериалов TMDB\",\n  \"components.Login.description\": \"Поскольку вы впервые входите в систему {ApplicationName}, вам необходимо добавить адрес электронной почты.\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Звук уведомлений\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Автодобавление тега с именем и ID пользователя, отправившего запрос\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Тип аниме\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Количество голосов от пользователей TMDB\",\n  \"components.Login.credentialerror\": \"Введено неверное имя пользователя или пароль.\",\n  \"components.Login.title\": \"Добавить email\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Это приведет к необратимому удалению {MediaType} из {arr}, включая все файлы.\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Тег запросов\",\n  \"components.MovieDetails.downloadstatus\": \"Статус загрузки\",\n  \"components.MovieDetails.openradarr4k\": \"Открыть фильм в 4К Radarr\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Устройство по умолчанию\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Сканировать всю библиотеку Jellyfin\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Синхронизировать доступность медиа\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Что-то пошло не так во время сохранения настроек {mediaServerName}.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"Настройки {mediaServerName} успешно сохранены!\",\n  \"components.Settings.jellyfinlibraries\": \"Библиотеки {mediaServerName}\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"Библиотеки {mediaServerName} проверяются на наличие заголовков. Нажмите кнопку ниже, если в списке не хватает библиотек.\",\n  \"components.Settings.jellyfinsettings\": \"Настройки {mediaServerName}\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Автодобавление тега с именем и ID пользователя, отправившего запрос\",\n  \"components.Settings.jellyfinSettings\": \"Настройки {mediaServerName}\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Необязательно настраивать внутреннюю и внешнюю конечные точки для вашего сервера {mediaServerName}. В большинстве случаев внешний URL-адрес отличается от внутреннего. Пользовательский URL-адрес для сброса пароля также может быть задан для входа в систему {mediaServerName}, на случай, если вы хотите перенаправить на другую страницу для сброса пароля. Вы также можете изменить API-ключ от Jellyfin, который был автоматически сгенерирован ранее.\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Настройте свой {mediaServerName} сервер. {mediaServerName} отсканирует ваши библиотеки, чтобы увидеть, какие библиотеки доступны.\",\n  \"components.Settings.manualscanJellyfin\": \"Сканировать библиотеки вручную\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.syncJellyfin\": \"Синхронизировать библиотеки\",\n  \"components.Settings.syncing\": \"Синхронизация\",\n  \"components.Settings.timeout\": \"Время ожидания\",\n  \"components.Setup.signin\": \"Войти\",\n  \"components.Setup.signinWithPlex\": \"Введите данные своего Plex\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> успешно удален из списка наблюдения!\",\n  \"components.TitleCard.watchlistError\": \"Что-то пошло не так. Пожалуйста, попробуйте еще раз.\",\n  \"components.TvDetails.play\": \"Запустить в {mediaServerName}\",\n  \"components.TvDetails.play4k\": \"Запустить 4К в {mediaServerName}\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {userCount, plural, one {# новый пользователь} other {# новых пользователя(ей)}} успешно импортированы из {mediaServerName}!\",\n  \"components.UserList.importfromJellyfin\": \"Добавить пользователей из {mediaServerName}\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Нет пользователей {mediaServerName} для импорта.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Пользователь {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Сохранение…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Звук уведомлений\",\n  \"i18n.collection\": \"Коллекция\",\n  \"components.Setup.configuremediaserver\": \"Настроить медиасервер\",\n  \"components.UserList.importfromJellyfinerror\": \"Что-то пошло не так при импорте пользователей из {mediaServerName}.\",\n  \"components.UserList.newJellyfinsigninenabled\": \"Параметр <strong>Включить новый вход в {mediaServerName}</strong> в настоящее время включен. Пользователей {mediaServerName} с доступом к библиотеке не нужно импортировать для входа.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"Электронная почта\",\n  \"components.UserProfile.localWatchlist\": \"Список наблюдения {username}\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Обычно это выполняется только раз в 24 часа. Seerr будет более настойчиво проверять недавно добавленный сервер {mediaServerName}. Если вы впервые настраиваете Seerr, то рекомендуем однократное полное сканирование библиотеки!\",\n  \"components.TitleCard.watchlistCancel\": \"наблюдение за <strong>{title}</strong> отменено.\",\n  \"components.Settings.saving\": \"Сохранение…\",\n  \"components.TitleCard.addToWatchList\": \"Добавить в список наблюдения\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> успешно добавлен в список наблюдения!\",\n  \"components.Settings.save\": \"Сохранить изменения\",\n  \"components.Setup.signinWithJellyfin\": \"Введите данные своего Jellyfin\",\n  \"components.UserList.mediaServerUser\": \"Пользователь {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Сохранить изменения\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Устройство по умолчанию\",\n  \"components.Login.invalidurlerror\": \"Не удалось подключиться к {mediaServerName} серверу.\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"Базовый URL должен начинаться на слэш\",\n  \"components.MovieDetails.addtowatchlist\": \"Добавить в список просмотра\",\n  \"components.MovieDetails.removefromwatchlist\": \"Удалить из списка просмотра\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> Удален из списка просмотра успешно!\",\n  \"components.TvDetails.addtowatchlist\": \"Добавить в список просмотра\",\n  \"components.RequestList.RequestItem.profileName\": \"Профиль\",\n  \"components.Discover.FilterSlideover.status\": \"Статус\",\n  \"components.Login.adminerror\": \"Вы должны использовать аккаунт администратора чтобы войти.\",\n  \"components.Login.enablessl\": \"Использовать SSL\",\n  \"components.Login.back\": \"Вернуться\",\n  \"components.Login.port\": \"Порт\",\n  \"components.Login.servertype\": \"Тип сервера\",\n  \"components.Login.urlBase\": \"Базовый URL\",\n  \"components.Login.validationPortRequired\": \"Вы должны указать корректный порт\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"Базовый URL не может оканчиваться слэшем\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL не может оканчиваться слэшем\",\n  \"components.Login.validationservertyperequired\": \"Пожалуйста, выберите тип сервера\",\n  \"components.MovieDetails.watchlistError\": \"Что-то пошло не так. Пожалуйста, попробуйте еще раз.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> успешно добавлен с список просмотра!\",\n  \"components.Selector.canceled\": \"Отменён\",\n  \"components.Selector.ended\": \"Окончен\",\n  \"components.Selector.inProduction\": \"В производстве\",\n  \"components.Selector.pilot\": \"Пилот\",\n  \"components.Selector.planned\": \"Запланирован\",\n  \"components.Selector.returningSeries\": \"Возвращение сериала\",\n  \"components.Selector.searchStatus\": \"Выберите статус...\",\n  \"components.Setup.back\": \"Вернуться\",\n  \"components.Setup.configemby\": \"Настроить Emby\",\n  \"components.Setup.configjellyfin\": \"Настроить Jellyfin\",\n  \"components.Setup.configplex\": \"Настроить Plex\",\n  \"components.Setup.servertype\": \"Выберите тип сервера\",\n  \"components.Setup.signinWithEmby\": \"Введите данные своего Emby\",\n  \"components.Setup.subtitle\": \"Начните с выбора своего медиа сервера\",\n  \"components.TvDetails.removefromwatchlist\": \"Удалить из списка просмотра\",\n  \"components.Settings.invalidurlerror\": \"Не удалось подключиться к {mediaServerName} серверу.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Забыли пароль URL\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Что-то пошло не так при синхронизации библиотек\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Библиотеки не найдены\",\n  \"components.Login.hostname\": \"Адрес {mediaServerName}\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Предстоящие сериалы\",\n  \"components.Login.loginwithapp\": \"Войти по {appName}\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"Идентификатор темы/топика должен быть положительным целым числом\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Если в вашем чате включены темы, укажите идентификатор здесь\",\n  \"components.RequestList.sortDirection\": \"Изменить порядок сортировки\",\n  \"components.RequestList.RequestItem.removearr\": \"Удалить с {arr}\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Необходимо указать действительный ID роли Discord\",\n  \"components.Selector.searchUsers\": \"Выбрать пользователей…\",\n  \"components.Settings.Notifications.messageThreadId\": \"Идентификатор темы\",\n  \"components.Login.noadminerror\": \"На сервере отсутствует администратор.\",\n  \"components.Login.orsigninwith\": \"Или войдите с\",\n  \"components.Settings.apiKey\": \"API-ключ\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Правило переопределения успешно создано!\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Фильтровать контент по региональной доступности\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Разрешить запрашивать спец. эпизоды\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Включить CSRF защиту\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Используйте ',' в качестве разделителя. '*.' - для указания всех поддоменов\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> успешно удалён из списка просмотра!\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Указывает условия для применения изменений параметров. Для применения каждое поле должно быть проверено с помощью правил (операция И). Поле считается проверенным, если подходит любой из его параметров (операция ИЛИ).\",\n  \"components.TvDetails.watchlistError\": \"Что-то пошло не так. Пожалуйста, попробуйте еще раз.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> успешно добавлен с список просмотра!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Регион трансляции\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Эти внешние аккаунты привязаны к вашему аккаунту {applicationName}.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"У вас нет ни одного привязанного внешнего аккаунта.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"У вас нет прав менять привязанные аккаунты этого пользователя.\",\n  \"components.Setup.librarieserror\": \"Валидация не пройдена. Пожалуйста, выберите библиотеки повторно для продолжения.\",\n  \"components.Settings.OverrideRuleModal.service\": \"Служба\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Нужно выбрать хотя бы один метод аутентификации.\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Позволить пользователям входить с помощью аккаунта {mediaServerName}\",\n  \"components.Settings.addrule\": \"Новое правило переопределения\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Другой пользователь уже использует это имя пользователя. Вам нужно указать email\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"ID треда/топика\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Связанные аккаунты\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Без тегов.\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Указывает изменяемые настройки при выполнении вышеуказанных условий.\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Токен обновления Plex\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Устанавливает доступ к внешнему API в режим только для чтения (требуется HTTPS)\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Вместо этих настроек нужно использовать сетевые параметры из вашего контейнера/системы. Для дополнительной информации прочитайте {docs}.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Введите ваши данные от {mediaServerName}, чтобы связать аккаунт с {applicationName}.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Не удалось подключиться к {mediaServerName} с использованием ваших данных\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Регион поиска\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Если ваш групповой чат использует топики, вы можете указать здесь ID треда/топика\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Аватары пользователей\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Что-то пошло не так при сохранении настроек.\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"НЕ включайте эту настройку, если не знаете, для чего она нужна!\",\n  \"components.Settings.SettingsNetwork.docs\": \"документация\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Принудительно использовать сначала IPv4\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Seerr будет принудительно использовать сначала IPv4 адреса вместо IPv6\",\n  \"components.Settings.SettingsNetwork.network\": \"Сеть\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Сетевые настройки\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Установите сетевые настройки для вашего экземпляра Seerr.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Адреса, игнорируемые прокси\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Не использовать прокси для локальных адресов\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) прокси\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Имя хоста прокси\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Пароль от прокси\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Порт прокси\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Использовать SSL для прокси\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Имя пользователя от прокси\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Настройки успешно сохранены!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Включить поддержку прокси\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Позволяет Seerr корректно определять IP адреса клиентов за прокси\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Нужно указать корректный порт\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Методы входа\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Настройте методы входа для пользователей.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Включить вход с помощью {mediaServerName}\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Пользовательская аутентификация с автоматической группировкой библиотек не поддерживается\",\n  \"components.Settings.menuNetwork\": \"Сеть\",\n  \"components.Settings.overrideRules\": \"Правила переопределения\",\n  \"components.Settings.overrideRulesDescription\": \"Правила переопределения позволяют вам указать параметры для изменения, если запрос походит под правило.\",\n  \"components.Settings.scanbackground\": \"Сканирование будет выполнено в фоновом режиме. Сейчас вы можете продолжить процесс настройки.\",\n  \"components.Settings.tip\": \"Подсказка\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.UserList.validationUsername\": \"Вам нужно указать имя пользователя\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Этот аккаунт уже связан с пользователем {applicationName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Произошла неизвестная ошибка\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Пароль\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Вам нужно указать пароль\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Связать\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Добавление…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Привязать аккаунт {mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Имя пользователя\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Вам нужно указать имя пользователя\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Показывать сайты трансляций по региональной доступности\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Необходим корректный email\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Email обязателен\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Не удалость удалить связанный аккаунт.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Произошла неизвестная ошибка\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Связанные аккаунты\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Этот аккаунт уже привязан к пользователю Plex\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Не удалось соединиться с Plex с использованием ваших данных\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"ID треда/топика должно быть целым положительным числом\",\n  \"i18n.specials\": \"Спец. эпизоды\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Языки\",\n  \"components.Settings.Notifications.webhookRoleId\": \"ID роли уведомления\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"ID роли для упоминания в теле webhook запроса. Оставьте пустым для отключения упоминания\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Условия\",\n  \"components.Settings.OverrideRuleModal.create\": \"Создать правило\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Новое правило переопределения\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Изменить правило переопределения\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Жанры\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Ключевые слова\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Профиль качества\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Корневая папка\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Правило переопределения успешно изменено!\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Выберите профиль качества\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Выберите корневую папку\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Выберите теги\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Применить это правило к выбранному сервису.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Настройки\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Выберите службу\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Теги\",\n  \"components.Settings.OverrideRuleModal.users\": \"Пользователи\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Условия\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Жанр\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Ключевые слова\",\n  \"components.Settings.OverrideRuleTile.language\": \"Язык\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Профиль качества\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Корневая папка\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Настройки\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Теги\",\n  \"components.Settings.OverrideRuleTile.users\": \"Пользователи\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Этот email уже занят!\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Регион поиска\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Регион трансляции\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Показывать сайты трансляций по региональной доступности\",\n  \"components.UserList.username\": \"Имя пользователя\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Фильтровать контент по региональной доступности\",\n  \"components.Discover.FilterSlideover.certification\": \"Возрастной рейтинг\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Исключаемые ключевые слова\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Описание проблемы\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Выберите провайдера метаданных\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Не удалось загрузить возрастной рейтинг\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Максимальный рейтинг\",\n  \"components.Selector.CertificationSelector.minRating\": \"Минимальный рейтинг\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Нет доступных вариантов\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Выберите возрастной рейтинг\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Выберите страну\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Начните печатать для поиска.\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Приоритет\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Необходимо ввести числовой приоритет\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Включить агента\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Добавлять постер­\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Не удалось сохранить настройки Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Настройки Ntfy успешно сохранены!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Пароль\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Не удалось отправить тестовое уведомление Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Отправка тестового уведомления Ntfy…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Тестовое уведомление Ntfy отправлено!\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Токен\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Аутентификация по токену\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Топик\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"URL сервера\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Имя пользователя\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Аутентификация по имени пользователя и паролю\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Необходимо заполнить топик\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Необходимо ввести корректный URL\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Необходимо выбрать хотя бы один тип уведомления\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Добавлять постер\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Добавлять постер\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Включить поддержку переменных в URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Список доступных переменных описан в секции \\\"Template variables\\\"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"URL для тестового уведомления изменён на {testUrl} вместо реального URL.\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Добавлять постер\",\n  \"components.Settings.Notifications.embedPoster\": \"Добавлять постер\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"Кеш DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr кеширует DNS запросы, чтобы оптимизировать производительность и избежать ненужных запросов к API.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Глобальная статистика кеша DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Эта статистика агрегируется из всех элементов кеша DNS.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Активный адрес\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Возраст\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"Кеш DNS для {hostname} сброшен.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Попаданий\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Промахов\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Имя хоста\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"{jobScheduleDays, plural, one {Каждый день} few {Каждые {jobScheduleDays} дня} other {Каждые {jobScheduleDays} дней}}\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Ошибки\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Сбросить кеш DNS\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Процент попаданий\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Попаданий\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"Переходов на IPv4\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Промахов\",\n  \"components.Settings.SettingsJobsCache.size\": \"Размер\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"API-ключ скопирован в буфер.\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Скрывает доступный контент со страниц \\\"Найти что-то новое\\\", но не из результатов поиска\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Требуется ввести корректный URL\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URL не должен оканчиваться на слеш\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"URL YouTube\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"Базовый URL для YouTube видео, если вы используете свой экземпляр YouTube.\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"Кеш DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"Максимальный TTL кеша DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"Минимальный TTL кеша DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"Не включайте, если испытываете проблемы с DNS запросами\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Включает кеширование DNS запросов, чтобы оптимизировать производительность и избежать ненужных вызовов API\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Все выбранные провайдеры метаданных функционируют корректно\",\n  \"components.Settings.animeMetadataProvider\": \"Провайдер метаданных для аниме\",\n  \"components.Settings.chooseProvider\": \"Выберите провайдеров метаданных для различных типов контента\",\n  \"components.Settings.clickTest\": \"Нажмите \\\"Протестировать\\\" для проверки соединения с провайдерами метаданных\",\n  \"components.Settings.connectionTestFailed\": \"Тест соединения не успешен\",\n  \"components.Settings.failed\": \"Не сработало\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Не удалось сохранить настройки провайдера метаданных\",\n  \"components.Settings.general\": \"Общее\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} не является ключевым словом TMDB.\",\n  \"components.Settings.menuMetadataProviders\": \"Провайдеры метаданных\",\n  \"components.Settings.metadataProviderSelection\": \"Выбор провайдера метаданных\",\n  \"components.Settings.metadataProviderSettings\": \"Провайдеры метаданных\",\n  \"components.Settings.metadataSettings\": \"Настройки провайдера метаданных\",\n  \"components.Settings.metadataSettingsSaved\": \"Настройки провайдера метаданных сохранены\",\n  \"components.Settings.no\": \"Нет\",\n  \"components.Settings.noSpecialCharacters\": \"Конфигурация должна быть списком идентификаторов ключевых слов TMDB, разделённых запятой, и не должно начинаться или заканчиваться запятой.\",\n  \"components.Settings.nooptions\": \"Нет результатов.\",\n  \"components.Settings.notTested\": \"Не тестировалось\",\n  \"components.Settings.operational\": \"Работает корректно\",\n  \"components.Settings.providerStatus\": \"Статус провайдера метаданных\",\n  \"components.Settings.searchKeywords\": \"Слова для поиска…\",\n  \"components.Settings.seriesMetadataProvider\": \"Провайдер метаданных для сериалов\",\n  \"components.Settings.settings\": \"Настройки\",\n  \"components.Settings.starttyping\": \"Начните печатать для поиска.\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"Провайдер TMDB не работает, пожалуйста, выберите другого провайдера метаданных\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"Провайдер TVDB не работает, пожалуйста, выберите другого провайдера метаданных\",\n  \"components.Settings.valueRequired\": \"Необходимо указать значение.\",\n  \"components.Settings.yes\": \"Да\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Браузер\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Создано\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Удалить подписку\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Устройство\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Отключить веб-пуш\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Что-то пошло не так при отключении веб-пушей.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Включи веб-пуш\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Что-то пошло не так при включении веб-пушей.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Движок\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Управление устройствами\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"У вас нет активных подписок на веб-пуши.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Операционная система\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Подписка удалена.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Что-то пошло не так при удалении подписки пользователя.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"тип\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Неизвестно\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Веб-пуш деактивирован.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Веб-пуш активирован.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Не удалось сохранить настройки уведомлений через веб-пуш.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Настройки уведомлений через веб-пуш успешно сохранены!\",\n  \"i18n.completed\": \"Завершено\",\n  \"i18n.deleted\": \"Удалено\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"О Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Внести вклад в разработку\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Поддержать Seerr\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Необходимо ввести корректный максимальный TTL\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Необходимо ввести корректный минимальный TTL\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Активная подписка\",\n  \"component.BlocklistBlock.blocklistdate\": \"Дата блокировки\",\n  \"component.BlocklistBlock.blocklistedby\": \"Автор блокировки\",\n  \"component.BlocklistModal.blocklisting\": \"Блокировка\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> не заблокирован.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Управление заблокированным контентом.\",\n  \"components.Blocklist.blocklistdate\": \"дата\",\n  \"components.Blocklist.blocklistedby\": \"{date} пользователем {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Настройки блокировок\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Заблокированные теги\",\n  \"components.Blocklist.filterManual\": \"Вручную\",\n  \"components.Blocklist.mediaName\": \"Название\",\n  \"components.Blocklist.mediaTmdbId\": \"TMDB ID\",\n  \"components.Blocklist.mediaType\": \"Тип\",\n  \"components.Blocklist.showAllBlocklisted\": \"Показать весь заблокированный контент\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Не удалось соединиться с {services}. Может быть доступна не вся информация.\",\n  \"components.Layout.Sidebar.blocklist\": \"Список блокировки\",\n  \"components.PermissionEdit.blocklistedItems\": \"Блокировка контента.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Выдаёт право блокировать контент.\",\n  \"components.PermissionEdit.manageblocklist\": \"Управление списком блокировок\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Выдаёт право управлять заблокированным контентом.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Просмотр заблокированного контента.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Выдаёт право просматривать заблокированный контент.\",\n  \"components.RequestList.unableToConnect\": \"Не удалось соединиться с {services}. Может быть доступна не вся информация.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Пока ни один DNS запрос не был кеширован.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Обработать заблокированные теги\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Блокировать контент с тегами\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Ограничение блокируемого контента на тег\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"Задание \\\"Обработать заблокированные теги\\\" будет блокировать такое количество страниц за каждую сортировку. Более высокие значения будут выдавать более точные результаты, но использовать больше памяти.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Автоматически добавляет контент с тегами в список блокировок, используя задание \\\"Обработать заблокированные теги\\\"\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Скрывать заблокированный контент\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Скрывает заблокированный контент со страниц \\\"Найти что-то новое\\\" для всех пользователей с правом \\\"Управление списком блокировок\\\"\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"Таймаут API запроса\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Максимальное время (в секундах) ожидания ответа от внешних сервисов, таких как Radarr/Sonarr. Установите в 0 для отключения.\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Отправляет ВСЕ исходящие HTTP/HTTPS запросы через прокси-сервер (host/port). НЕ ВКЛЮЧАЕТ HTTP, SSL или конфигурацию сертификатов.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Необходимо ввести корректное значение таймаута\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Отслеживать новые сезоны\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Вставьте конифгурацию блокируемого тега ниже.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Импорт конфигурации блокируемого тега\",\n  \"components.Settings.blocklistedTagsText\": \"Заблокированные теги\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Вы уверены, что хотите очистить заблокированные теги?\",\n  \"components.Settings.copyBlocklistedTags\": \"Заблокированные теги скопированы в буфер.\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Нечего копировать\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Копировать конфигурацию заблокированного тега\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Импоритровать конфигурацию заблокированного тега\",\n  \"i18n.addToBlocklist\": \"Добавить в список блокировок\",\n  \"i18n.blocklist\": \"Список блокировок\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> уже заблокирован.\",\n  \"i18n.blocklistError\": \"Что-то пошло не так. Попробуйте снова.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> успешно заблокирован.\",\n  \"i18n.blocklisted\": \"Заблокированное\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> успешно удалён из списка блокировок.\",\n  \"i18n.removefromBlocklist\": \"Удалить из списка блокировок\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Приоритет\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"Необходимо ввести значение от 1 до 5\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Заголовки запроса\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Добавить заголовок\",\n  \"components.Discover.timeWindowDay\": \"Ежедневные\",\n  \"components.Discover.timeWindowWeek\": \"Еженедельные\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Нельзя одновременно использовать Заголовок для авторизации и заголовок Authorization. Пожалуйста, удалите один из них.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Все заголовки должны иметь название и значение\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Название заголовка\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Удалить\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Добавляйте пользовательские HTTP заголовки к вебхук запросам\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Значение заголовка\"\n}\n"
  },
  {
    "path": "src/i18n/locale/sk.json",
    "content": "{}\n"
  },
  {
    "path": "src/i18n/locale/sl.json",
    "content": "{\n  \"components.Discover.CreateSlider.editsuccess\": \"Urejen drsnik in shranjene nastavitve prilagajanja odkrivanja.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} film/ov\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Ime drsnika\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Premiera ↓\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Pripenjanje nosilca <code>{appDataPath}</code> ni bilo pravilno konfigurirano. Vsi podatki bodo izbrisani, ko se vsebnik zaustavi ali znova zažene.\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Priljubljenost ↑\",\n  \"components.AirDateBadge.airsrelative\": \"Predvajanje {relativeTime}\",\n  \"components.CollectionDetails.overview\": \"Pregled\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Active Filter} drugo {# Active Filters}}\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Ocena TMDB ↓\",\n  \"components.AirDateBadge.airedrelative\": \"Predvajano {relativeTime}\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Iskanje studiev …\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Datum izdaje ↑\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Navedite ID omrežja TMDB\",\n  \"components.Discover.CreateSlider.addfail\": \"Novega drsnika ni bilo mogoče ustvariti.\",\n  \"components.CollectionDetails.requestcollection\": \"Zahtevaj zbirko\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Filmi: {genre}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Filmi: {language}\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Active Filter} other {# Active Filters}}\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Priljubljenost ↓\",\n  \"components.Discover.CreateSlider.needresults\": \"Imeti morate vsaj 1 rezultat.\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Ustvari drsnik po meri\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Priljubljenost ↓\",\n  \"components.Discover.CreateSlider.editSlider\": \"Uredi drsnik\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Naslov (a-ž) ↓\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Navesti morate vrednost podatkov.\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Premiera ↑\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Serije\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Drsnika ni bilo mogoče izbrisati.\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Navedite ID studia v TMDB\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Naslov (a-ž) ↑\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} filmi\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Priljubljenost ↑\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Išči žanre …\",\n  \"components.Discover.CreateSlider.editfail\": \"Drsnika ni bilo mogoče urediti.\",\n  \"components.Discover.CreateSlider.starttyping\": \"Tipkajte za iskanje.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Preklopi vidnost\",\n  \"components.Discover.CreateSlider.addSlider\": \"Dodaj drsnik\",\n  \"components.CollectionDetails.requestcollection4k\": \"Zahtevaj zbirko 4K\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Vnesite iskalno poizvedbo\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} serije\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Navedite ID ključne besede TMDB\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"Filmi: {keywordTitle}\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Navesti morate naslov.\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Datum izdaje ↓\",\n  \"components.Discover.CreateSlider.nooptions\": \"Ni zadetkov.\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Ocena TMDB ↑\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Iskanje po ključnih besedah …\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Ustvarjen nov drsnik in shranjene nastavitve prilagajanja odkrivanja.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Drsnik je bil uspešno izbrisan.\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmi\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Naslov (a-ž) ↓\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Navedite ID žanra TMDB\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Naslov (a-ž) ↑\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Odstrani\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Ocena TMDB ↓\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Series\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"\",\n  \"components.Discover.FilterSlideover.activefilters\": \"\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.filters\": \"\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"\",\n  \"components.Discover.FilterSlideover.from\": \"\",\n  \"components.Discover.FilterSlideover.genres\": \"\",\n  \"components.Discover.FilterSlideover.keywords\": \"\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"\",\n  \"components.Discover.FilterSlideover.ratingText\": \"\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"\",\n  \"components.Discover.FilterSlideover.runtime\": \"\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"\",\n  \"components.Discover.FilterSlideover.studio\": \"\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"\",\n  \"components.Discover.FilterSlideover.to\": \"\",\n  \"components.Discover.FilterSlideover.voteCount\": \"\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"\",\n  \"components.Discover.NetworkSlider.networks\": \"\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"\",\n  \"components.Discover.StudioSlider.studios\": \"\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.Discover.createnewslider\": \"\",\n  \"components.Discover.customizediscover\": \"\",\n  \"components.Discover.discover\": \"\",\n  \"components.Discover.emptywatchlist\": \"\",\n  \"components.Discover.moviegenres\": \"\",\n  \"components.Discover.networks\": \"\",\n  \"components.Discover.plexwatchlist\": \"\",\n  \"components.Discover.popularmovies\": \"\",\n  \"components.Discover.populartv\": \"\",\n  \"components.Discover.recentlyAdded\": \"\",\n  \"components.Discover.recentrequests\": \"\",\n  \"components.Discover.resetfailed\": \"\",\n  \"components.Discover.resetsuccess\": \"\",\n  \"components.Discover.resettodefault\": \"\",\n  \"components.Discover.resetwarning\": \"\",\n  \"components.Discover.stopediting\": \"\",\n  \"components.Discover.studios\": \"\",\n  \"components.Discover.tmdbmoviegenre\": \"\",\n  \"components.Discover.tmdbmoviekeyword\": \"\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"\",\n  \"components.Discover.tmdbnetwork\": \"\",\n  \"components.Discover.tmdbsearch\": \"\",\n  \"components.Discover.tmdbstudio\": \"\",\n  \"components.Discover.tmdbtvgenre\": \"\",\n  \"components.Discover.tmdbtvkeyword\": \"\",\n  \"components.Discover.tmdbtvstreamingservices\": \"\",\n  \"components.Discover.tvgenres\": \"\",\n  \"components.Discover.upcoming\": \"\",\n  \"components.Discover.upcomingmovies\": \"\",\n  \"components.Discover.upcomingtv\": \"\",\n  \"components.Discover.updatefailed\": \"\",\n  \"components.Discover.updatesuccess\": \"\",\n  \"components.DownloadBlock.estimatedtime\": \"\",\n  \"components.DownloadBlock.formattedTitle\": \"\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"\",\n  \"components.IssueDetails.IssueComment.delete\": \"\",\n  \"components.IssueDetails.IssueComment.edit\": \"\",\n  \"components.IssueDetails.IssueComment.postedby\": \"\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"\",\n  \"components.IssueDetails.IssueDescription.description\": \"\",\n  \"components.IssueDetails.IssueDescription.edit\": \"\",\n  \"components.IssueDetails.allepisodes\": \"\",\n  \"components.IssueDetails.allseasons\": \"\",\n  \"components.IssueDetails.closeissue\": \"\",\n  \"components.IssueDetails.closeissueandcomment\": \"\",\n  \"components.IssueDetails.commentplaceholder\": \"\",\n  \"components.IssueDetails.comments\": \"\",\n  \"components.IssueDetails.deleteissue\": \"\",\n  \"components.IssueDetails.deleteissueconfirm\": \"\",\n  \"components.IssueDetails.episode\": \"\",\n  \"components.IssueDetails.issuepagetitle\": \"\",\n  \"components.IssueDetails.issuetype\": \"\",\n  \"components.IssueDetails.lastupdated\": \"\",\n  \"components.IssueDetails.leavecomment\": \"\",\n  \"components.IssueDetails.nocomments\": \"\",\n  \"components.IssueDetails.openedby\": \"\",\n  \"components.IssueDetails.openin4karr\": \"\",\n  \"components.IssueDetails.openinarr\": \"\",\n  \"components.IssueDetails.play4konplex\": \"\",\n  \"components.IssueDetails.playonplex\": \"\",\n  \"components.IssueDetails.problemepisode\": \"\",\n  \"components.IssueDetails.problemseason\": \"\",\n  \"components.IssueDetails.reopenissue\": \"\",\n  \"components.IssueDetails.reopenissueandcomment\": \"\",\n  \"components.IssueDetails.season\": \"\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"\",\n  \"components.IssueDetails.toastissuedeleted\": \"\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"\",\n  \"components.IssueDetails.toaststatusupdated\": \"\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"\",\n  \"components.IssueDetails.unknownissuetype\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.IssueList.IssueItem.episodes\": \"\",\n  \"components.IssueList.IssueItem.issuestatus\": \"\",\n  \"components.IssueList.IssueItem.issuetype\": \"\",\n  \"components.IssueList.IssueItem.opened\": \"\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"\",\n  \"components.IssueList.IssueItem.problemepisode\": \"\",\n  \"components.IssueList.IssueItem.seasons\": \"\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"\",\n  \"components.IssueList.IssueItem.viewissue\": \"\",\n  \"components.IssueList.issues\": \"\",\n  \"components.IssueList.showallissues\": \"\",\n  \"components.IssueList.sortAdded\": \"\",\n  \"components.IssueList.sortModified\": \"\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"\",\n  \"components.IssueModal.CreateIssueModal.season\": \"\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"\",\n  \"components.IssueModal.issueAudio\": \"\",\n  \"components.IssueModal.issueOther\": \"\",\n  \"components.IssueModal.issueSubtitles\": \"\",\n  \"components.IssueModal.issueVideo\": \"\",\n  \"components.LanguageSelector.languageServerDefault\": \"\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"\",\n  \"components.Layout.Sidebar.browsemovies\": \"\",\n  \"components.Layout.Sidebar.browsetv\": \"\",\n  \"components.Layout.Sidebar.dashboard\": \"\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"\",\n  \"components.Layout.UserDropdown.myprofile\": \"\",\n  \"components.Layout.UserDropdown.requests\": \"\",\n  \"components.Layout.UserDropdown.settings\": \"\",\n  \"components.Layout.UserDropdown.signout\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"\",\n  \"components.Layout.VersionStatus.outofdate\": \"\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"\",\n  \"components.Layout.VersionStatus.streamstable\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.email\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.forgotpassword\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.password\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signin\": \"\",\n  \"components.Login.signingin\": \"\",\n  \"components.Login.signinheader\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.signinwithoverseerr\": \"\",\n  \"components.Login.signinwithplex\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationemailrequired\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationpasswordrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.alltime\": \"\",\n  \"components.ManageSlideOver.downloadstatus\": \"\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"\",\n  \"components.ManageSlideOver.manageModalIssues\": \"\",\n  \"components.ManageSlideOver.manageModalMedia\": \"\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.manageModalRequests\": \"\",\n  \"components.ManageSlideOver.manageModalTitle\": \"\",\n  \"components.ManageSlideOver.mark4kavailable\": \"\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"\",\n  \"components.ManageSlideOver.markavailable\": \"\",\n  \"components.ManageSlideOver.movie\": \"\",\n  \"components.ManageSlideOver.openarr\": \"\",\n  \"components.ManageSlideOver.openarr4k\": \"\",\n  \"components.ManageSlideOver.opentautulli\": \"\",\n  \"components.ManageSlideOver.pastdays\": \"\",\n  \"components.ManageSlideOver.playedby\": \"\",\n  \"components.ManageSlideOver.plays\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.ManageSlideOver.tvshow\": \"\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.budget\": \"\",\n  \"components.MovieDetails.cast\": \"\",\n  \"components.MovieDetails.digitalrelease\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.imdbuserscore\": \"\",\n  \"components.MovieDetails.managemovie\": \"\",\n  \"components.MovieDetails.mark4kavailable\": \"\",\n  \"components.MovieDetails.markavailable\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.originallanguage\": \"\",\n  \"components.MovieDetails.originaltitle\": \"\",\n  \"components.MovieDetails.overview\": \"\",\n  \"components.MovieDetails.overviewunavailable\": \"\",\n  \"components.MovieDetails.physicalrelease\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.productioncountries\": \"\",\n  \"components.MovieDetails.recommendations\": \"\",\n  \"components.MovieDetails.releasedate\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.reportissue\": \"\",\n  \"components.MovieDetails.revenue\": \"\",\n  \"components.MovieDetails.rtaudiencescore\": \"\",\n  \"components.MovieDetails.rtcriticsscore\": \"\",\n  \"components.MovieDetails.runtime\": \"\",\n  \"components.MovieDetails.showless\": \"\",\n  \"components.MovieDetails.showmore\": \"\",\n  \"components.MovieDetails.similar\": \"\",\n  \"components.MovieDetails.streamingproviders\": \"\",\n  \"components.MovieDetails.studio\": \"\",\n  \"components.MovieDetails.theatricalrelease\": \"\",\n  \"components.MovieDetails.tmdbuserscore\": \"\",\n  \"components.MovieDetails.viewfullcrew\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.MovieDetails.watchtrailer\": \"\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.issuecomment\": \"\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.issuecreated\": \"\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"\",\n  \"components.NotificationTypeSelector.issuereopened\": \"\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.issueresolved\": \"\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediafailed\": \"\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediarequested\": \"\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"\",\n  \"components.PermissionEdit.admin\": \"\",\n  \"components.PermissionEdit.adminDescription\": \"\",\n  \"components.PermissionEdit.advancedrequest\": \"\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"\",\n  \"components.PermissionEdit.autoapprove\": \"\",\n  \"components.PermissionEdit.autoapprove4k\": \"\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"\",\n  \"components.PermissionEdit.autoapproveDescription\": \"\",\n  \"components.PermissionEdit.autoapproveMovies\": \"\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"\",\n  \"components.PermissionEdit.autoapproveSeries\": \"\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"\",\n  \"components.PermissionEdit.autorequest\": \"\",\n  \"components.PermissionEdit.autorequestDescription\": \"\",\n  \"components.PermissionEdit.autorequestMovies\": \"\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"\",\n  \"components.PermissionEdit.autorequestSeries\": \"\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"\",\n  \"components.PermissionEdit.createissues\": \"\",\n  \"components.PermissionEdit.createissuesDescription\": \"\",\n  \"components.PermissionEdit.manageissues\": \"\",\n  \"components.PermissionEdit.manageissuesDescription\": \"\",\n  \"components.PermissionEdit.managerequests\": \"\",\n  \"components.PermissionEdit.managerequestsDescription\": \"\",\n  \"components.PermissionEdit.request\": \"\",\n  \"components.PermissionEdit.request4k\": \"\",\n  \"components.PermissionEdit.request4kDescription\": \"\",\n  \"components.PermissionEdit.request4kMovies\": \"\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"\",\n  \"components.PermissionEdit.request4kTv\": \"\",\n  \"components.PermissionEdit.request4kTvDescription\": \"\",\n  \"components.PermissionEdit.requestDescription\": \"\",\n  \"components.PermissionEdit.requestMovies\": \"\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"\",\n  \"components.PermissionEdit.requestTv\": \"\",\n  \"components.PermissionEdit.requestTvDescription\": \"\",\n  \"components.PermissionEdit.users\": \"\",\n  \"components.PermissionEdit.usersDescription\": \"\",\n  \"components.PermissionEdit.viewissues\": \"\",\n  \"components.PermissionEdit.viewissuesDescription\": \"\",\n  \"components.PermissionEdit.viewrecent\": \"\",\n  \"components.PermissionEdit.viewrecentDescription\": \"\",\n  \"components.PermissionEdit.viewrequests\": \"\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"\",\n  \"components.PermissionEdit.viewwatchlists\": \"\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"\",\n  \"components.PersonDetails.alsoknownas\": \"\",\n  \"components.PersonDetails.appearsin\": \"\",\n  \"components.PersonDetails.ascharacter\": \"\",\n  \"components.PersonDetails.birthdate\": \"\",\n  \"components.PersonDetails.crewmember\": \"\",\n  \"components.PersonDetails.lifespan\": \"\",\n  \"components.QuotaSelector.days\": \"\",\n  \"components.QuotaSelector.movieRequests\": \"\",\n  \"components.QuotaSelector.movies\": \"\",\n  \"components.QuotaSelector.seasons\": \"\",\n  \"components.QuotaSelector.tvRequests\": \"\",\n  \"components.QuotaSelector.unlimited\": \"\",\n  \"components.RegionSelector.regionDefault\": \"\",\n  \"components.RegionSelector.regionServerDefault\": \"\",\n  \"components.RequestBlock.approve\": \"\",\n  \"components.RequestBlock.decline\": \"\",\n  \"components.RequestBlock.delete\": \"\",\n  \"components.RequestBlock.edit\": \"\",\n  \"components.RequestBlock.languageprofile\": \"\",\n  \"components.RequestBlock.lastmodifiedby\": \"\",\n  \"components.RequestBlock.profilechanged\": \"\",\n  \"components.RequestBlock.requestdate\": \"\",\n  \"components.RequestBlock.requestedby\": \"\",\n  \"components.RequestBlock.requestoverrides\": \"\",\n  \"components.RequestBlock.rootfolder\": \"\",\n  \"components.RequestBlock.seasons\": \"\",\n  \"components.RequestBlock.server\": \"\",\n  \"components.RequestButton.approve4krequests\": \"\",\n  \"components.RequestButton.approverequest\": \"\",\n  \"components.RequestButton.approverequest4k\": \"\",\n  \"components.RequestButton.approverequests\": \"\",\n  \"components.RequestButton.decline4krequests\": \"\",\n  \"components.RequestButton.declinerequest\": \"\",\n  \"components.RequestButton.declinerequest4k\": \"\",\n  \"components.RequestButton.declinerequests\": \"\",\n  \"components.RequestButton.requestmore\": \"\",\n  \"components.RequestButton.requestmore4k\": \"\",\n  \"components.RequestButton.viewrequest\": \"\",\n  \"components.RequestButton.viewrequest4k\": \"\",\n  \"components.RequestCard.approverequest\": \"\",\n  \"components.RequestCard.cancelrequest\": \"\",\n  \"components.RequestCard.declinerequest\": \"\",\n  \"components.RequestCard.deleterequest\": \"\",\n  \"components.RequestCard.editrequest\": \"\",\n  \"components.RequestCard.failedretry\": \"\",\n  \"components.RequestCard.mediaerror\": \"\",\n  \"components.RequestCard.seasons\": \"\",\n  \"components.RequestCard.tmdbid\": \"\",\n  \"components.RequestCard.tvdbid\": \"\",\n  \"components.RequestCard.unknowntitle\": \"\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"\",\n  \"components.RequestList.RequestItem.deleterequest\": \"\",\n  \"components.RequestList.RequestItem.editrequest\": \"\",\n  \"components.RequestList.RequestItem.failedretry\": \"\",\n  \"components.RequestList.RequestItem.mediaerror\": \"\",\n  \"components.RequestList.RequestItem.modified\": \"\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.RequestItem.requested\": \"\",\n  \"components.RequestList.RequestItem.requesteddate\": \"\",\n  \"components.RequestList.RequestItem.seasons\": \"\",\n  \"components.RequestList.RequestItem.tmdbid\": \"\",\n  \"components.RequestList.RequestItem.tvdbid\": \"\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"\",\n  \"components.RequestList.requests\": \"\",\n  \"components.RequestList.showallrequests\": \"\",\n  \"components.RequestList.sortAdded\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.RequestList.sortModified\": \"\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"\",\n  \"components.RequestModal.AdvancedRequester.default\": \"\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.season\": \"\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"\",\n  \"components.RequestModal.alreadyrequested\": \"\",\n  \"components.RequestModal.approve\": \"\",\n  \"components.RequestModal.autoapproval\": \"\",\n  \"components.RequestModal.cancel\": \"\",\n  \"components.RequestModal.edit\": \"\",\n  \"components.RequestModal.errorediting\": \"\",\n  \"components.RequestModal.numberofepisodes\": \"\",\n  \"components.RequestModal.pending4krequest\": \"\",\n  \"components.RequestModal.pendingapproval\": \"\",\n  \"components.RequestModal.pendingrequest\": \"\",\n  \"components.RequestModal.requestApproved\": \"\",\n  \"components.RequestModal.requestCancel\": \"\",\n  \"components.RequestModal.requestSuccess\": \"\",\n  \"components.RequestModal.requestadmin\": \"\",\n  \"components.RequestModal.requestcancelled\": \"\",\n  \"components.RequestModal.requestcollection4ktitle\": \"\",\n  \"components.RequestModal.requestcollectiontitle\": \"\",\n  \"components.RequestModal.requestedited\": \"\",\n  \"components.RequestModal.requesterror\": \"\",\n  \"components.RequestModal.requestfrom\": \"\",\n  \"components.RequestModal.requestmovie4ktitle\": \"\",\n  \"components.RequestModal.requestmovies\": \"\",\n  \"components.RequestModal.requestmovies4k\": \"\",\n  \"components.RequestModal.requestmovietitle\": \"\",\n  \"components.RequestModal.requestseasons\": \"\",\n  \"components.RequestModal.requestseasons4k\": \"\",\n  \"components.RequestModal.requestseries4ktitle\": \"\",\n  \"components.RequestModal.requestseriestitle\": \"\",\n  \"components.RequestModal.season\": \"\",\n  \"components.RequestModal.seasonnumber\": \"\",\n  \"components.RequestModal.selectmovies\": \"\",\n  \"components.RequestModal.selectseason\": \"\",\n  \"components.ResetPassword.confirmpassword\": \"\",\n  \"components.ResetPassword.password\": \"\",\n  \"components.ResetPassword.passwordreset\": \"\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"\",\n  \"components.ResetPassword.resetpassword\": \"\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"\",\n  \"components.ResetPassword.validationemailrequired\": \"\",\n  \"components.ResetPassword.validationpasswordmatch\": \"\",\n  \"components.ResetPassword.validationpasswordminchars\": \"\",\n  \"components.ResetPassword.validationpasswordrequired\": \"\",\n  \"components.Search.search\": \"\",\n  \"components.Search.searchresults\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.nooptions\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchGenres\": \"\",\n  \"components.Selector.searchKeywords\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchStudios\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Selector.showless\": \"\",\n  \"components.Selector.showmore\": \"\",\n  \"components.Selector.starttyping\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.Settings.Notifications.agentenabled\": \"\",\n  \"components.Settings.Notifications.allowselfsigned\": \"\",\n  \"components.Settings.Notifications.authPass\": \"\",\n  \"components.Settings.Notifications.authUser\": \"\",\n  \"components.Settings.Notifications.botAPI\": \"\",\n  \"components.Settings.Notifications.botApiTip\": \"\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"\",\n  \"components.Settings.Notifications.botUsername\": \"\",\n  \"components.Settings.Notifications.botUsernameTip\": \"\",\n  \"components.Settings.Notifications.chatId\": \"\",\n  \"components.Settings.Notifications.chatIdTip\": \"\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"\",\n  \"components.Settings.Notifications.emailsender\": \"\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.enableMentions\": \"\",\n  \"components.Settings.Notifications.encryption\": \"\",\n  \"components.Settings.Notifications.encryptionDefault\": \"\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"\",\n  \"components.Settings.Notifications.encryptionNone\": \"\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"\",\n  \"components.Settings.Notifications.encryptionTip\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.pgpPassword\": \"\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"\",\n  \"components.Settings.Notifications.sendSilently\": \"\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"\",\n  \"components.Settings.Notifications.senderName\": \"\",\n  \"components.Settings.Notifications.smtpHost\": \"\",\n  \"components.Settings.Notifications.smtpPort\": \"\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"\",\n  \"components.Settings.Notifications.validationEmail\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"\",\n  \"components.Settings.Notifications.validationTypes\": \"\",\n  \"components.Settings.Notifications.validationUrl\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.Notifications.webhookUrl\": \"\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.add\": \"\",\n  \"components.Settings.RadarrModal.announced\": \"\",\n  \"components.Settings.RadarrModal.apiKey\": \"\",\n  \"components.Settings.RadarrModal.baseUrl\": \"\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"\",\n  \"components.Settings.RadarrModal.createradarr\": \"\",\n  \"components.Settings.RadarrModal.default4kserver\": \"\",\n  \"components.Settings.RadarrModal.defaultserver\": \"\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"\",\n  \"components.Settings.RadarrModal.editradarr\": \"\",\n  \"components.Settings.RadarrModal.enableSearch\": \"\",\n  \"components.Settings.RadarrModal.externalUrl\": \"\",\n  \"components.Settings.RadarrModal.hostname\": \"\",\n  \"components.Settings.RadarrModal.inCinemas\": \"\",\n  \"components.Settings.RadarrModal.loadingTags\": \"\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"\",\n  \"components.Settings.RadarrModal.notagoptions\": \"\",\n  \"components.Settings.RadarrModal.port\": \"\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"\",\n  \"components.Settings.RadarrModal.released\": \"\",\n  \"components.Settings.RadarrModal.rootfolder\": \"\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"\",\n  \"components.Settings.RadarrModal.selecttags\": \"\",\n  \"components.Settings.RadarrModal.server4k\": \"\",\n  \"components.Settings.RadarrModal.servername\": \"\",\n  \"components.Settings.RadarrModal.ssl\": \"\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"\",\n  \"components.Settings.RadarrModal.tagRequests\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.RadarrModal.tags\": \"\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"\",\n  \"components.Settings.SettingsAbout.about\": \"\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"\",\n  \"components.Settings.SettingsAbout.documentation\": \"\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"\",\n  \"components.Settings.SettingsAbout.outofdate\": \"\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"\",\n  \"components.Settings.SettingsAbout.timezone\": \"\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"\",\n  \"components.Settings.SettingsAbout.uptodate\": \"\",\n  \"components.Settings.SettingsAbout.version\": \"\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.cache\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"\",\n  \"components.Settings.SettingsJobsCache.command\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.process\": \"\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"\",\n  \"components.Settings.SettingsLogs.extraData\": \"\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"\",\n  \"components.Settings.SettingsLogs.filterError\": \"\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"\",\n  \"components.Settings.SettingsLogs.label\": \"\",\n  \"components.Settings.SettingsLogs.level\": \"\",\n  \"components.Settings.SettingsLogs.logDetails\": \"\",\n  \"components.Settings.SettingsLogs.logs\": \"\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"\",\n  \"components.Settings.SettingsLogs.message\": \"\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"\",\n  \"components.Settings.SettingsLogs.showall\": \"\",\n  \"components.Settings.SettingsLogs.time\": \"\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"\",\n  \"components.Settings.SettingsMain.apikey\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"\",\n  \"components.Settings.SettingsMain.applicationurl\": \"\",\n  \"components.Settings.SettingsMain.cacheImages\": \"\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.general\": \"\",\n  \"components.Settings.SettingsMain.generalsettings\": \"\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.locale\": \"\",\n  \"components.Settings.SettingsMain.originallanguage\": \"\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"\",\n  \"components.Settings.SettingsUsers.localLogin\": \"\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.userSettings\": \"\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"\",\n  \"components.Settings.SettingsUsers.users\": \"\",\n  \"components.Settings.SonarrModal.add\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.animeTags\": \"\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"\",\n  \"components.Settings.SonarrModal.apiKey\": \"\",\n  \"components.Settings.SonarrModal.baseUrl\": \"\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.createsonarr\": \"\",\n  \"components.Settings.SonarrModal.default4kserver\": \"\",\n  \"components.Settings.SonarrModal.defaultserver\": \"\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"\",\n  \"components.Settings.SonarrModal.editsonarr\": \"\",\n  \"components.Settings.SonarrModal.enableSearch\": \"\",\n  \"components.Settings.SonarrModal.externalUrl\": \"\",\n  \"components.Settings.SonarrModal.hostname\": \"\",\n  \"components.Settings.SonarrModal.languageprofile\": \"\",\n  \"components.Settings.SonarrModal.loadingTags\": \"\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"\",\n  \"components.Settings.SonarrModal.notagoptions\": \"\",\n  \"components.Settings.SonarrModal.port\": \"\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"\",\n  \"components.Settings.SonarrModal.rootfolder\": \"\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"\",\n  \"components.Settings.SonarrModal.selecttags\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.server4k\": \"\",\n  \"components.Settings.SonarrModal.servername\": \"\",\n  \"components.Settings.SonarrModal.ssl\": \"\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SonarrModal.tags\": \"\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"\",\n  \"components.Settings.activeProfile\": \"\",\n  \"components.Settings.addradarr\": \"\",\n  \"components.Settings.address\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.addsonarr\": \"\",\n  \"components.Settings.advancedTooltip\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.cancelscan\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.currentlibrary\": \"\",\n  \"components.Settings.default\": \"\",\n  \"components.Settings.default4k\": \"\",\n  \"components.Settings.deleteServer\": \"\",\n  \"components.Settings.deleteserverconfirm\": \"\",\n  \"components.Settings.email\": \"\",\n  \"components.Settings.enablessl\": \"\",\n  \"components.Settings.experimentalTooltip\": \"\",\n  \"components.Settings.externalUrl\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.hostname\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.is4k\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.librariesRemaining\": \"\",\n  \"components.Settings.manualscan\": \"\",\n  \"components.Settings.manualscanDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.mediaTypeMovie\": \"\",\n  \"components.Settings.mediaTypeSeries\": \"\",\n  \"components.Settings.menuAbout\": \"\",\n  \"components.Settings.menuGeneralSettings\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuJobs\": \"\",\n  \"components.Settings.menuLogs\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.menuNotifications\": \"\",\n  \"components.Settings.menuPlexSettings\": \"\",\n  \"components.Settings.menuServices\": \"\",\n  \"components.Settings.menuUsers\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noDefault4kServer\": \"\",\n  \"components.Settings.noDefaultNon4kServer\": \"\",\n  \"components.Settings.noDefaultServer\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"\",\n  \"components.Settings.notifications\": \"\",\n  \"components.Settings.notificationsettings\": \"\",\n  \"components.Settings.notrunning\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.plex\": \"\",\n  \"components.Settings.plexlibraries\": \"\",\n  \"components.Settings.plexlibrariesDescription\": \"\",\n  \"components.Settings.plexsettings\": \"\",\n  \"components.Settings.plexsettingsDescription\": \"\",\n  \"components.Settings.port\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.radarrsettings\": \"\",\n  \"components.Settings.restartrequiredTooltip\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scan\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.scanning\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.serverLocal\": \"\",\n  \"components.Settings.serverRemote\": \"\",\n  \"components.Settings.serverSecure\": \"\",\n  \"components.Settings.serverpreset\": \"\",\n  \"components.Settings.serverpresetLoad\": \"\",\n  \"components.Settings.serverpresetManualMessage\": \"\",\n  \"components.Settings.serverpresetRefreshing\": \"\",\n  \"components.Settings.serviceSettingsDescription\": \"\",\n  \"components.Settings.services\": \"\",\n  \"components.Settings.settingUpPlexDescription\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.sonarrsettings\": \"\",\n  \"components.Settings.ssl\": \"\",\n  \"components.Settings.startscan\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.tautulliApiKey\": \"\",\n  \"components.Settings.tautulliSettings\": \"\",\n  \"components.Settings.tautulliSettingsDescription\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.toastPlexConnecting\": \"\",\n  \"components.Settings.toastPlexConnectingFailure\": \"\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"\",\n  \"components.Settings.toastPlexRefresh\": \"\",\n  \"components.Settings.toastPlexRefreshFailure\": \"\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.urlBase\": \"\",\n  \"components.Settings.validationApiKey\": \"\",\n  \"components.Settings.validationHostnameRequired\": \"\",\n  \"components.Settings.validationPortRequired\": \"\",\n  \"components.Settings.validationUrl\": \"\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Settings.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.webAppUrl\": \"\",\n  \"components.Settings.webAppUrlTip\": \"\",\n  \"components.Settings.webhook\": \"\",\n  \"components.Settings.webpush\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.configureservices\": \"\",\n  \"components.Setup.continue\": \"\",\n  \"components.Setup.finish\": \"\",\n  \"components.Setup.finishing\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.setup\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinMessage\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.Setup.welcome\": \"\",\n  \"components.StatusBadge.managemedia\": \"\",\n  \"components.StatusBadge.openinarr\": \"\",\n  \"components.StatusBadge.playonplex\": \"\",\n  \"components.StatusBadge.seasonepisodenumber\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.StatusBadge.status\": \"\",\n  \"components.StatusBadge.status4k\": \"\",\n  \"components.StatusChecker.appUpdated\": \"\",\n  \"components.StatusChecker.appUpdatedDescription\": \"\",\n  \"components.StatusChecker.reloadApp\": \"\",\n  \"components.StatusChecker.restartRequired\": \"\",\n  \"components.StatusChecker.restartRequiredDescription\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.cleardata\": \"\",\n  \"components.TitleCard.mediaerror\": \"\",\n  \"components.TitleCard.tmdbid\": \"\",\n  \"components.TitleCard.tvdbid\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.Season.noepisodes\": \"\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.anime\": \"\",\n  \"components.TvDetails.cast\": \"\",\n  \"components.TvDetails.episodeCount\": \"\",\n  \"components.TvDetails.episodeRuntime\": \"\",\n  \"components.TvDetails.nextAirDate\": \"\",\n  \"components.TvDetails.originallanguage\": \"\",\n  \"components.TvDetails.originaltitle\": \"\",\n  \"components.TvDetails.overview\": \"\",\n  \"components.TvDetails.overviewunavailable\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.productioncountries\": \"\",\n  \"components.TvDetails.recommendations\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.reportissue\": \"\",\n  \"components.TvDetails.rtaudiencescore\": \"\",\n  \"components.TvDetails.rtcriticsscore\": \"\",\n  \"components.TvDetails.seasonnumber\": \"\",\n  \"components.TvDetails.seasons\": \"\",\n  \"components.TvDetails.seasonstitle\": \"\",\n  \"components.TvDetails.showtype\": \"\",\n  \"components.TvDetails.similar\": \"\",\n  \"components.TvDetails.status4k\": \"\",\n  \"components.TvDetails.streamingproviders\": \"\",\n  \"components.TvDetails.tmdbuserscore\": \"\",\n  \"components.TvDetails.viewfullcrew\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.TvDetails.watchtrailer\": \"\",\n  \"components.UserList.accounttype\": \"\",\n  \"components.UserList.autogeneratepassword\": \"\",\n  \"components.UserList.autogeneratepasswordTip\": \"\",\n  \"components.UserList.bulkedit\": \"\",\n  \"components.UserList.create\": \"\",\n  \"components.UserList.created\": \"\",\n  \"components.UserList.createlocaluser\": \"\",\n  \"components.UserList.creating\": \"\",\n  \"components.UserList.deleteconfirm\": \"\",\n  \"components.UserList.deleteuser\": \"\",\n  \"components.UserList.edituser\": \"\",\n  \"components.UserList.email\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importedfromplex\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.importfromplex\": \"\",\n  \"components.UserList.importfromplexerror\": \"\",\n  \"components.UserList.localLoginDisabled\": \"\",\n  \"components.UserList.localuser\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.newplexsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.nouserstoimport\": \"\",\n  \"components.UserList.owner\": \"\",\n  \"components.UserList.password\": \"\",\n  \"components.UserList.passwordinfodescription\": \"\",\n  \"components.UserList.plexuser\": \"\",\n  \"components.UserList.role\": \"\",\n  \"components.UserList.sortCreated\": \"\",\n  \"components.UserList.sortRequests\": \"\",\n  \"components.UserList.totalrequests\": \"\",\n  \"components.UserList.user\": \"\",\n  \"components.UserList.usercreatedfailed\": \"\",\n  \"components.UserList.usercreatedfailedexisting\": \"\",\n  \"components.UserList.usercreatedsuccess\": \"\",\n  \"components.UserList.userdeleted\": \"\",\n  \"components.UserList.userdeleteerror\": \"\",\n  \"components.UserList.userlist\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.users\": \"\",\n  \"components.UserList.userssaved\": \"\",\n  \"components.UserList.validationEmail\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserList.validationpasswordminchars\": \"\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"\",\n  \"components.UserProfile.ProfileHeader.profile\": \"\",\n  \"components.UserProfile.ProfileHeader.settings\": \"\",\n  \"components.UserProfile.ProfileHeader.userid\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"\",\n  \"components.UserProfile.emptywatchlist\": \"\",\n  \"components.UserProfile.limit\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"components.UserProfile.movierequests\": \"\",\n  \"components.UserProfile.pastdays\": \"\",\n  \"components.UserProfile.plexwatchlist\": \"\",\n  \"components.UserProfile.recentlywatched\": \"\",\n  \"components.UserProfile.recentrequests\": \"\",\n  \"components.UserProfile.requestsperdays\": \"\",\n  \"components.UserProfile.seriesrequest\": \"\",\n  \"components.UserProfile.totalrequests\": \"\",\n  \"components.UserProfile.unlimited\": \"\",\n  \"i18n.advanced\": \"\",\n  \"i18n.all\": \"\",\n  \"i18n.approve\": \"\",\n  \"i18n.approved\": \"\",\n  \"i18n.areyousure\": \"\",\n  \"i18n.available\": \"\",\n  \"i18n.back\": \"\",\n  \"i18n.cancel\": \"\",\n  \"i18n.canceling\": \"\",\n  \"i18n.close\": \"\",\n  \"i18n.collection\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.decline\": \"\",\n  \"i18n.declined\": \"\",\n  \"i18n.delete\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.deleting\": \"\",\n  \"i18n.delimitedlist\": \"\",\n  \"i18n.edit\": \"\",\n  \"i18n.experimental\": \"\",\n  \"i18n.failed\": \"\",\n  \"i18n.import\": \"\",\n  \"i18n.importing\": \"\",\n  \"i18n.loading\": \"\",\n  \"i18n.movie\": \"\",\n  \"i18n.movies\": \"\",\n  \"i18n.next\": \"\",\n  \"i18n.noresults\": \"\",\n  \"i18n.notrequested\": \"\",\n  \"i18n.open\": \"\",\n  \"i18n.partiallyavailable\": \"\",\n  \"i18n.pending\": \"\",\n  \"i18n.previous\": \"\",\n  \"i18n.processing\": \"\",\n  \"i18n.request\": \"\",\n  \"i18n.requested\": \"\",\n  \"i18n.resolved\": \"\",\n  \"i18n.showingresults\": \"\",\n  \"i18n.status\": \"\",\n  \"i18n.test\": \"\",\n  \"i18n.testing\": \"\",\n  \"i18n.tvshow\": \"\",\n  \"i18n.tvshows\": \"\",\n  \"i18n.unavailable\": \"\",\n  \"i18n.usersettings\": \"\",\n  \"i18n.view\": \"\",\n  \"pages.errormessagewithcode\": \"\",\n  \"pages.internalservererror\": \"\",\n  \"pages.oops\": \"\",\n  \"pages.pagenotfound\": \"\",\n  \"pages.returnHome\": \"\",\n  \"pages.serviceunavailable\": \"\",\n  \"pages.somethingwentwrong\": \"\",\n  \"components.Layout.Sidebar.issues\": \"\",\n  \"components.Layout.Sidebar.requests\": \"\",\n  \"components.Layout.Sidebar.settings\": \"\",\n  \"components.Layout.Sidebar.users\": \"\",\n  \"components.ResetPassword.email\": \"\",\n  \"components.Discover.trending\": \"\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"\",\n  \"components.ResetPassword.emailresetlink\": \"\",\n  \"components.ResetPassword.gobacklogin\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"\",\n  \"components.UserList.sortDisplayName\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"\",\n  \"components.TvDetails.firstAirDate\": \"\",\n  \"components.TvDetails.manageseries\": \"\",\n  \"components.TvDetails.network\": \"\",\n  \"components.UserList.admin\": \"\",\n  \"components.UserList.userfail\": \"\",\n  \"i18n.request4k\": \"\",\n  \"i18n.requesting\": \"\",\n  \"i18n.restartRequired\": \"\",\n  \"i18n.resultsperpage\": \"\",\n  \"i18n.retry\": \"\",\n  \"i18n.retrying\": \"\",\n  \"i18n.save\": \"\",\n  \"i18n.saving\": \"\",\n  \"i18n.settings\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/sq.json",
    "content": "{\n  \"components.Layout.Sidebar.requests\": \"Kërkesat\",\n  \"components.Layout.Sidebar.settings\": \"Cilësimet\",\n  \"components.Login.signin\": \"Hyr\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Paraqit Problemin\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Raporti i problemit për <strong>{title}</strong> u paraqit me sukses!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Shiko Problemin\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Kjo do të heqë në mënyrë të pakthyeshme të gjitha të dhënat për këtë {mediaType}, duke përfshirë çdo kërkesë. Nëse ky artikull ekziston në bibliotekën tuaj {mediaServerName}, informacioni i medias do të rikrijohet gjatë skanimit të ardhshëm.\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Monitimi i volumit <code>{appDataPath}</code> nuk u konfigurua siç duhet. Gjithë informacioni do të fshihet kur kontenieri do të mbyllet ose të ristartohet.\",\n  \"components.Discover.StudioSlider.studios\": \"Studiot\",\n  \"components.Layout.UserDropdown.settings\": \"Cilësimet\",\n  \"components.Login.signingin\": \"Po identifikohet…\",\n  \"components.ManageSlideOver.opentautulli\": \"Hape në Tautulli\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"E avancuar\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Pastro të dhënat\",\n  \"components.ManageSlideOver.playedby\": \"Luajtur nga\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Ekuipazhi i plotë\",\n  \"components.MovieDetails.markavailable\": \"Shënoni si të disponueshme\",\n  \"components.MovieDetails.revenue\": \"Të ardhurat\",\n  \"components.MovieDetails.originaltitle\": \"Titulli Origjinal\",\n  \"components.MovieDetails.showless\": \"Shfaq më pak\",\n  \"components.MovieDetails.mark4kavailable\": \"Shënoni si të disponueshëm në 4K\",\n  \"components.MovieDetails.runtime\": \"{minutes} minuta\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Episodi i ndikuar\",\n  \"components.IssueList.sortAdded\": \"Më të fundit\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Episodi {episodeNumber}\",\n  \"components.IssueList.sortModified\": \"Modifikuar së Fundmi\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Të gjithë Episodet\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Të gjithë Sezonet\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Ekstrat\",\n  \"components.Login.loginerror\": \"Diçka shkoi keq duke u përpjekur të hyja.\",\n  \"components.Login.signinheader\": \"Identifikohu për të vazhduar\",\n  \"components.MovieDetails.budget\": \"Buxheti\",\n  \"components.ManageSlideOver.openarr4k\": \"Hape në 4K {arr}\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profili\",\n  \"components.IssueList.showallissues\": \"Shfaq të gjithë Problemet\",\n  \"components.IssueDetails.IssueComment.edit\": \"Modifiko Komentin\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Modifiko Përshkrimin\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Filma\",\n  \"components.CollectionDetails.overview\": \"Faqja e Përgjithshme\",\n  \"components.CollectionDetails.requestcollection\": \"Kërko Koleksionin\",\n  \"components.CollectionDetails.requestcollection4k\": \"Kërko Koleksionin në 4K\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Filma {genre}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Filma {language}\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Seriale {network}\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Filma {studio}\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Seriale {genre}\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Seriale {language}\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Zhanre Filmi\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Zhanre Filmi\",\n  \"components.Discover.NetworkSlider.networks\": \"Rrjetet\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Zhanre Seriali\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Zhanre Seriali\",\n  \"components.Discover.discover\": \"Zbulo\",\n  \"components.Discover.popularmovies\": \"Filma Popullorë\",\n  \"components.Discover.populartv\": \"Seriale Popullore\",\n  \"components.Discover.recentlyAdded\": \"Shtuar së Fundmi\",\n  \"components.Discover.recentrequests\": \"Kërkesat e Fundit\",\n  \"components.Discover.trending\": \"Në Trend\",\n  \"components.Discover.upcoming\": \"Filmat që vijnë së shpejti\",\n  \"components.Discover.upcomingmovies\": \"Filmat që vijnë së shpejti\",\n  \"components.Discover.upcomingtv\": \"Serialet që vijnë së shpejti\",\n  \"components.DownloadBlock.estimatedtime\": \"Rreth {time}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"A jeni të sigurt që doni të fshini këtë koment?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Fshi Komentin\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Postuar {relativeTime} nga {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Postuar {relativeTime} nga {username} (Modifikuar)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Ju duhet të vendosni një mesazh\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Fshi Problemin\",\n  \"components.IssueDetails.IssueDescription.description\": \"Përshkrim\",\n  \"components.IssueDetails.allepisodes\": \"Të gjithë Episodet\",\n  \"components.IssueDetails.allseasons\": \"Të gjithë Sezonet\",\n  \"components.IssueDetails.closeissue\": \"Mbyll Problemin\",\n  \"components.IssueDetails.closeissueandcomment\": \"Mbyll me Koment\",\n  \"components.IssueDetails.commentplaceholder\": \"Shto një koment…\",\n  \"components.IssueDetails.comments\": \"Komentet\",\n  \"components.IssueDetails.deleteissue\": \"Fshi Problemin\",\n  \"components.IssueDetails.deleteissueconfirm\": \"A jeni të sigurt që doni të fshini këtë problem?\",\n  \"components.IssueDetails.episode\": \"Episodi {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Problem\",\n  \"components.IssueDetails.issuetype\": \"Tipi\",\n  \"components.IssueDetails.lastupdated\": \"Përditësuar së Fundmi\",\n  \"components.IssueDetails.leavecomment\": \"Koment\",\n  \"components.IssueDetails.nocomments\": \"Asnjë koment.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} hapur {relativeTime} nga {username}\",\n  \"components.IssueDetails.openin4karr\": \"Hape në 4K {arr}\",\n  \"components.IssueDetails.openinarr\": \"Hape në {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Luaje në 4K në {mediaServerName}\",\n  \"components.IssueDetails.playonplex\": \"Luaje në {mediaServerName}\",\n  \"components.IssueDetails.problemepisode\": \"Episodi i ndikuar\",\n  \"components.IssueDetails.problemseason\": \"Sezoni i ndikuar\",\n  \"components.IssueDetails.reopenissue\": \"Rihap Problemin\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Rihap me Koment\",\n  \"components.IssueDetails.season\": \"Sezoni {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Diçka shkoi keq duke modifikuar përshkrimin e problemit.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Përshkrimi i Problemit u modifikua me sukses!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Problemi u fshi me sukses!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Diçka shkoi keq duke fshirë problemin.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Statusi i problemit u përditësua me sukses!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Diçka shkoi keq duke përditësuar statusin e problemit.\",\n  \"components.IssueDetails.unknownissuetype\": \"E panjohur\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Statusi\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tipi\",\n  \"components.IssueList.IssueItem.opened\": \"Hapur\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} nga {user}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"E panjohur\",\n  \"components.IssueList.IssueItem.viewissue\": \"Shfaq problemin\",\n  \"components.IssueList.issues\": \"Problemet\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Episodi i ndikuar\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Sezoni i ndikuar\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Ju lutemi të jepni një shpjegim të hollësishëm për problemin që keni hasur.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Raportoni një problem\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Sezoni {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Diçka shkoi keq duke paraqitur problemin.\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Ju duhet të jepni një përshkrim\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Çfarë nuk shkon?\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.IssueModal.issueOther\": \"Të tjera\",\n  \"components.IssueModal.issueSubtitles\": \"Titra\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.LanguageSelector.languageServerDefault\": \"E Parazgjedhur ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Të gjitha Gjuhët\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Shfaq Gjuhën\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Kërko Filma & Seriale\",\n  \"components.Layout.Sidebar.dashboard\": \"Zbulo\",\n  \"components.Layout.Sidebar.issues\": \"Problemet\",\n  \"components.Layout.Sidebar.users\": \"Përdoruesit\",\n  \"components.Layout.UserDropdown.signout\": \"Dilni\",\n  \"components.Layout.VersionStatus.outofdate\": \"E skaduar\",\n  \"components.Login.email\": \"Adresa e emailit\",\n  \"components.Login.forgotpassword\": \"Harrove Fjalëkalimin?\",\n  \"components.Login.password\": \"Fjalëkalimi\",\n  \"components.Login.signinwithoverseerr\": \"Përdor llogarinë tënde {applicationTitle}\",\n  \"components.Login.signinwithplex\": \"Përdor llogarinë tënde Plex\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {version} other {versione}} mbrapa\",\n  \"components.Login.validationemailrequired\": \"Ju duhet të jepni një adresë të vlefshme e-mail\",\n  \"components.Login.validationpasswordrequired\": \"Duhet të jepni një fjalëkalim\",\n  \"components.ManageSlideOver.alltime\": \"Të gjitha kohërat\",\n  \"components.ManageSlideOver.downloadstatus\": \"Shkarkimet\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Probleme të hapura\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Media\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"Media 4K\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Asnjë kërkesë.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Kërkesat\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Menaxho {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Shënoni si të disponueshëm në 4K\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Shënoni të gjitha Sezonet si të disponueshme në 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Shënoni të gjitha Sezonet si të disponueshme\",\n  \"components.ManageSlideOver.markavailable\": \"Shënoni si të disponueshme\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.ManageSlideOver.openarr\": \"Hape në {arr}\",\n  \"components.ManageSlideOver.pastdays\": \"Kaluar {days, number} Ditë\",\n  \"components.ManageSlideOver.tvshow\": \"seri\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Shih më shumë\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Kasti i plotë\",\n  \"components.MovieDetails.cast\": \"Kasti\",\n  \"components.MovieDetails.originallanguage\": \"Gjuha Origjinale\",\n  \"components.MovieDetails.overview\": \"Vështrim i përgjithshëm\",\n  \"components.MovieDetails.overviewunavailable\": \"Vështrimi i përgjithshëm i paarritshëm.\",\n  \"components.MovieDetails.productioncountries\": \"Prodhimi {countryCount, plural, one {Shtet} other {Shtete}}\",\n  \"components.MovieDetails.recommendations\": \"Rekomandime\",\n  \"components.MovieDetails.showmore\": \"Shfaq më shumë\",\n  \"components.MovieDetails.similar\": \"Tituj të ngjashëm\",\n  \"components.MovieDetails.streamingproviders\": \"Po Transmetohet Në\",\n  \"components.MovieDetails.viewfullcrew\": \"Shiko ekuipazhin e plotë\",\n  \"components.Settings.menuJobs\": \"Punët & Cache\",\n  \"components.Settings.menuNotifications\": \"Njoftime\",\n  \"components.Settings.menuServices\": \"Shërbime\",\n  \"components.Settings.menuUsers\": \"Përdoruesit\",\n  \"components.Settings.noDefault4kServer\": \"Një server 4K {serverType} duhet të shënohet si i prezgjedhur në mënyrë që t'u mundësojë përdoruesve të paraqesin kërkesat e {mediaType} 4K .\",\n  \"components.Settings.noDefaultNon4kServer\": \"Nëse keni vetëm një server të vetëm {serverType} për të dy përmbajtjet jo-4K dhe 4K (ose nëse shkarkon vetëm përmbajtjen 4K), serveri juaj {serverType} <strong>NUK</strong>duhet të caktohet si një server 4K.\",\n  \"components.Settings.noDefaultServer\": \"Të paktën një server {serverType} duhet të shënohet si parazgjedhje në mënyrë që kërkesat për {mediaType} të përpunohen.\",\n  \"components.Settings.notifications\": \"Njoftimet\",\n  \"components.Settings.notificationsettings\": \"Cilësimet e njoftimit\",\n  \"components.Settings.notrunning\": \"Nuk Po Punon\",\n  \"components.Settings.plexlibraries\": \"Libraritë e Plex\",\n  \"components.Settings.scan\": \"Sinkronizoni Libraritë\",\n  \"components.Settings.scanning\": \"Po sinkronizohet…\",\n  \"components.Settings.serverSecure\": \"i sigurt\",\n  \"components.Settings.serverpreset\": \"Serveri\",\n  \"components.Settings.serverpresetLoad\": \"Shtyp butonin për të ngarkuar serverët e disponueshëm\",\n  \"components.Settings.toastPlexConnecting\": \"Duke u përpjekur për t'u lidhur me Plex…\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Dështoi lidhja me Plex.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Lidhja Plex u krijua me sukses!\",\n  \"i18n.testing\": \"Duke testuar…\",\n  \"i18n.view\": \"Pamje\",\n  \"components.MovieDetails.watchtrailer\": \"Shiko Trailerin\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Lajmërohu kur përdoruesit e tjerë komentojnë mbi problemet.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Njoftohuni kur problemet rihapen nga përdorues të tjerë.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Komenti i Problemit\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Dërgoni njoftime kur problemet marrin komente të reja.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Problemi i Raportuar\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Dërgoni njoftime kur raportohen probleme.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Problemi u Rihap\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Dërgo njoftime kur problemet rihapen.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Problemi u Zgjidh\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Dërgo njoftime kur përdoruesit paraqesin kërkesa të reja për media të cilat miratohen automatikisht.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Kërkesa u Miratua\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Dërgo njoftime kur kërkesat për media miratohen manualisht.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Kërkesa e Disponueshme\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Dërgo njoftime kur të bëhen të disponueshme kërkesat për media.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Kërkesa u refuzua\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Dërgoni njoftime kur kërkesat për media refuzohen.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Përpunimi i kërkesës dështoi\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Dërgo njoftime kur kërkesat për media nuk shtohen te Radarr ose Sonarr.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Kërkesë në pritje të miratimit\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Dërgo njoftime kur përdoruesit paraqesin kërkesa të reja për media të cilat kërkojnë miratim.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Llojet e njoftimeve\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Njoftohu kur problemet që ke raportuar marrin komente të reja.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Lajmërohu kur përdoruesit e tjerë raportojnë probleme.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Njoftohu kur problemet që keni raportuar rihapen.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Njoftohu kur problemet që keni raportuar zgjidhen.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Njoftohuni kur përdoruesit e tjerë paraqesin kërkesa të reja për media të cilat miratohen automatikisht.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Njoftohuni kur kërkesat tuaja për media miratohen.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Njoftohuni kur kërkesat tuaja për media bëhen të disponueshme.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Njoftohuni kur kërkesat tuaja për media refuzohen.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Njoftohuni kur përdoruesit e tjerë paraqesin kërkesa të reja për media që kërkojnë miratim.\",\n  \"components.PermissionEdit.admin\": \"Administrator\",\n  \"components.PermissionEdit.adminDescription\": \"Akses i plotë i administratorit. Anashkalon të gjitha kontrollet e tjera të lejeve.\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Jep aprovimin automatik për kërkesat e serive 4K.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Jep miratim automatik për të gjitha kërkesat për media jo-4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Aprovo automatikisht filmat\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Jep aprovimin automatik për kërkesat e filmave jo-4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Aprovo automatikisht Serialet\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Jep aprovimin automatik për kërkesat e serialeve jo-4K.\",\n  \"components.PermissionEdit.createissues\": \"Raporto Problemet\",\n  \"components.PermissionEdit.createissuesDescription\": \"Jepni leje për të raportuar problemet e medias.\",\n  \"components.PermissionEdit.manageissues\": \"Menaxho Problemet\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Jepni leje për të menaxhuar problemet e medias.\",\n  \"components.PermissionEdit.managerequests\": \"Menaxho Kërkesat\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Jepni leje për të menaxhuar kërkesat e medias. Të gjitha kërkesat e bëra nga një përdorues me këtë leje do të miratohen automatikisht.\",\n  \"components.PermissionEdit.request\": \"Kërkesë\",\n  \"components.PermissionEdit.request4k\": \"Kërkesë 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Jep leje për të paraqitur kërkesat për media 4K.\",\n  \"components.PermissionEdit.request4kMovies\": \"Kërko filma 4K\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Jep leje për të dërguar kërkesa për filma 4K.\",\n  \"components.PermissionEdit.request4kTv\": \"Kërko Seriale 4K\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Jep leje për të dërguar kërkesa për seriale 4K.\",\n  \"components.PermissionEdit.requestDescription\": \"Jep leje për të paraqitur kërkesat për media jo-4K.\",\n  \"components.PermissionEdit.requestTv\": \"Kërko Serialin\",\n  \"components.PermissionEdit.requestTvDescription\": \"Jep leje për të paraqitur kërkesa për seri jo-4K.\",\n  \"components.PermissionEdit.users\": \"Menaxho Përdoruesit\",\n  \"components.PermissionEdit.usersDescription\": \"Jep leje për të menaxhuar përdoruesit. Përdoruesit me këtë leje nuk mund të modifikojnë ose të japin privilegjin e administratorit.\",\n  \"components.PermissionEdit.viewissues\": \"Shiko Problemet\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Jep leje për të parë problemet e medias të raportuara nga përdoruesit e tjerë.\",\n  \"components.PermissionEdit.viewrequests\": \"Shikoni Kërkesat\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Jepni leje për të parë kërkesat për media të paraqitura nga përdorues të tjerë.\",\n  \"components.PersonDetails.alsoknownas\": \"Njohur edhe si: {names}\",\n  \"components.PersonDetails.appearsin\": \"Paraqitjet\",\n  \"components.PersonDetails.ascharacter\": \"si {character}\",\n  \"components.PersonDetails.birthdate\": \"Lindur {birthdate}\",\n  \"components.PersonDetails.crewmember\": \"Ekuipazhi\",\n  \"components.RegionSelector.regionServerDefault\": \"Parazgjedhur ({region})\",\n  \"components.RequestBlock.requestoverrides\": \"Anashkalime të Kërkesës\",\n  \"components.RequestBlock.rootfolder\": \"Direktoria\",\n  \"components.RequestBlock.server\": \"Serveri i destinacionit\",\n  \"components.RequestButton.decline4krequests\": \"Refuzo {requestCount, plural, one {Kërkesën 4K} other {{requestCount} Kërkesat 4K}}\",\n  \"components.RequestButton.declinerequest\": \"Refuzo kërkesën\",\n  \"components.RequestButton.declinerequests\": \"Refuzo {requestCount, plural, one {Kërkesën} other {{requestCount} Kërkesat}}\",\n  \"components.RequestButton.viewrequest4k\": \"Shiko Kërkesën 4K\",\n  \"components.RequestCard.failedretry\": \"Diçka shkoi keq duke e riprovuar kërkesën.\",\n  \"components.RequestList.RequestItem.modified\": \"Modifikuar\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} nga {user}\",\n  \"components.RequestList.RequestItem.requested\": \"Kërkuar\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Kërkuar\",\n  \"components.RequestList.requests\": \"Kërkesat\",\n  \"components.RequestList.showallrequests\": \"Shfaq të gjitha kërkesat\",\n  \"components.RequestList.sortAdded\": \"Më të fundit\",\n  \"components.RequestList.sortModified\": \"Modifikuar së Fundmi\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"E avancuar\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Kjo seri është një anime.\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Serveri i destinacionit\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Profili i gjuhës\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Kërko Si\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Ju lejoheni të kërkoni <strong>{limit}</strong> {type} çdo <strong>{days}</strong> ditë.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Nuk kanë mbetur kërkesa të mjaftueshme për sezonin\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Ju mund të shikoni një përmbledhje të kufizimeve tuaja të kërkesës në <ProfileLink>faqen tuaj të profilit</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"sezon\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Nuk mund të përputheshim automatikisht me kërkesën tënde. Ju lutem zgjidhni ndeshjen e saktë nga lista më poshtë.\",\n  \"components.RequestModal.alreadyrequested\": \"E Kërkuar Tashmë\",\n  \"components.RequestModal.approve\": \"Mirato Kërkesën\",\n  \"components.RequestModal.autoapproval\": \"Aprovim automatik\",\n  \"components.RequestModal.edit\": \"Ndrysho kërkesën\",\n  \"components.RequestModal.errorediting\": \"Diçka shkoi keq duke modifikuar kërkesën.\",\n  \"components.RequestModal.numberofepisodes\": \"# i Episodeve\",\n  \"components.RequestModal.pending4krequest\": \"\",\n  \"components.RequestModal.pendingrequest\": \"Kërkesë në pritje\",\n  \"components.RequestModal.requestApproved\": \"Kërkesa për <strong>{title}</strong> u miratua!\",\n  \"components.RequestModal.requestCancel\": \"Kërkesa për <strong>{title}</strong> u anullua.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> u kërkua me sukses!\",\n  \"components.RequestModal.requestadmin\": \"Kjo kërkesë do të miratohet automatikisht.\",\n  \"components.RequestModal.requestedited\": \"Kërkesa për <strong>{title}</strong> u modifikua me sukses!\",\n  \"components.RequestModal.requesterror\": \"Diçka shkoi keq duke paraqitur kërkesën.\",\n  \"components.RequestModal.requestfrom\": \"Kërkesa e {username} është në pritje të miratimit.\",\n  \"components.RequestModal.requestmovies\": \"Kërko {count} {count, plural, one {Film} other {Filma}}\",\n  \"components.RequestModal.requestmovies4k\": \"Kërko {count} {count, plural, one {Film} other {Filma}} në 4K\",\n  \"components.RequestModal.season\": \"Sezoni\",\n  \"components.RequestModal.seasonnumber\": \"Sezoni {numri}\",\n  \"components.RequestModal.selectmovies\": \"Zgjidh Filmat\",\n  \"components.RequestModal.selectseason\": \"Zgjidh Sezon(et)\",\n  \"components.ResetPassword.email\": \"Adresa e emailit\",\n  \"components.ResetPassword.resetpassword\": \"Zëvendëso fjalëkalimin tuaj\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Fjalëkalimi u zëvendësua me sukses!\",\n  \"components.ResetPassword.validationemailrequired\": \"Ju duhet të jepni një adresë të vlefshme e-mail\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Fjalëkalimet duhet të përputhen\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Fjalëkalimi është shumë i shkurtër; duhet të jetë një minimum prej 8 karakteresh\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Duhet të japësh një fjalëkalim\",\n  \"components.Search.search\": \"Kërko\",\n  \"components.Search.searchresults\": \"Rezultatet e Kërkimit\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Aktivizo agjentin\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Cilësimet e njoftimit të Gotify nuk u ruajtën.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Cilësimet e njoftimit Gotify u ruajtën me sukses!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Njoftimi i testit Gotify nuk u dërgua.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Po dërgohet njoftimi i testit Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"U dërgua njoftimi i testit Gotify!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Token e Aplikimit\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"URL e serverit\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Duhet të japësh një token aplikacioni\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Duhet të zgjedhësh të paktën një tip njoftimi\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Token Aksesimi\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Krijo një token nga <PushbulletSettingsLink>Cilësimet e llogarisë</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Aktivizo agjentin\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Etiketa e kanalit\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Duhet të japësh një Token hyrjeje\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Duhet të jepni një URL të vlefshme\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL e webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Krijo një integrim <WebhookLink>me Webhook</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Aktivizo agjentin\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Për të marrë njoftimet e shtytjes në internet, Seerr duhet të shërbehet mbi HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Njoftimi i testit në ueb dështoi të dërgohet.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Po dërgohet njoftimi test në ueb…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"U dërgua njoftimi test në ueb!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Cilësimet e njoftimit në ueb nuk u ruajtën.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Cilësimet e njoftimit në ueb u ruajtën me sukses!\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Aktivizo agjentin\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Header i autorizimit\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Rivendos në Parazgjedhje\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Njoftimi i testit Webhook dështoi të dërgonte.\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Ju duhet të siguroni një ngarkesë të vlefshme JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Duhet të zgjedhësh të paktën një tip njoftimi\",\n  \"components.Settings.Notifications.sendSilently\": \"Dërgo në heshtje\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Cilësimet e njoftimit të telegramit nuk u ruajtën.\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Njoftimi i testit të Discord nuk u dërgua.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Po dërgon njoftimin e testit Discord…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Njoftimi i testit me email u dërgua!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Njoftimi i testit telegram dështoi të dërgonte.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Po dërgohet njoftimi i testit të Telegramit…\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Njoftimi për testin e telegramit u dërgua!\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Ju duhet të jepni një TOKEN autorizimi të botit\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Ju duhet të siguroni një ID të vlefshme chat\",\n  \"components.Settings.Notifications.validationEmail\": \"Ju duhet të jepni një adresë të vlefshme emaili\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Duhet të jepni një fjalëkalim PGP\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Duhet të japësh një çelës privat PGP të vlefshëm\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Duhet të jepni një numër të vlefshëm porte\",\n  \"components.Settings.Notifications.validationTypes\": \"Duhet të zgjidhni të paktën një lloj njoftimi\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Testo lidhjen për të ngarkuar etiketat\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Lidhja me Radarr dështoi.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Lidhja Radarr u vendos me sukses!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Duhet të japësh një çelës API\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Duhet të jepni një URL të vlefshme\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Baza e URL nuk duhet të përfundojë me një slesh\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Duhet të zgjedhësh minimumin e disponueshmërisë\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Duhet të jepni një numër të vlefshëm porte\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Duhet të zgjedhësh një profil cilësie\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Duhet të zgjedhësh një dosje rrënjë\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Aktuale\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"E fundit\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Shfaq Changelog\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Shikoni në GitHub\",\n  \"components.Settings.SettingsAbout.about\": \"Rreth\",\n  \"components.Settings.menuAbout\": \"Rreth\",\n  \"components.Settings.menuGeneralSettings\": \"Gjeneral\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Jep leje për të dërguar kërkesa për filma jo-4K.\",\n  \"components.RequestButton.declinerequest4k\": \"Refuzo kërkesën 4K\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Njoftohuni kur kërkesat për media nuk shtohen te Radarr ose Sonarr.\",\n  \"components.PermissionEdit.advancedrequest\": \"Kërkesa të Avancuara\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Jep leje për të modifikuar opsionet e avancuara të kërkesës për media.\",\n  \"components.PermissionEdit.autoapprove\": \"Aprovo automatikisht\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Ky përdorues duhet të ketë të paktën <strong>{seasons}</strong> {seasons, plural, one {kërkesë sezoni} other {kërkesa sezonesh}} të mbetur në mënyrë që të paraqesë një kërkesë për këtë seri.\",\n  \"components.RegionSelector.regionDefault\": \"Të gjitha Rajonet\",\n  \"components.RequestButton.approverequests\": \"Mirato {requestCount, plural, one {Kërkesën} other {{requestCount} Kërkesat}}\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Anullo kërkesën\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Nuk ka etiketa.\",\n  \"components.ResetPassword.gobacklogin\": \"Kthehu te faqja e hyrjes\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Ju mund të shikoni një përmbledhje të kufijve të kërkesës së këtij përdoruesi në <ProfileLink>faqen e tyre të profilit</ProfileLink>.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Njoftohuni kur problemet zgjidhen nga përdoruesit e tjerë.\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Dërgoni njoftime kur problemet zgjidhen.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Kërkesa u Miratua Automatikisht\",\n  \"components.PermissionEdit.autoapprove4k\": \"Aprovo automatikisht 4K\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Aprovo automatikisht Filmat 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Jep aprovimin automatik për kërkesat e filmave 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Kërko Filma\",\n  \"components.QuotaSelector.unlimited\": \"Pa Limit\",\n  \"components.RequestButton.requestmore\": \"Kërko më shumë\",\n  \"components.RequestButton.requestmore4k\": \"Kërko më shumë në 4K\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Profili i cilësisë\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Etiketat\",\n  \"components.RequestCard.mediaerror\": \"Titulli shoqërues për këtë kërkesë nuk është më në dispozicion.\",\n  \"components.RequestList.RequestItem.editrequest\": \"Ndrysho kërkesën\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Direktoria\",\n  \"components.RequestButton.approverequest\": \"Mirato Kërkesën\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Jep aprovimin automatik për të gjitha kërkesat e mediave 4K.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Aprovo automatikisht Serialet 4K\",\n  \"components.RequestBlock.profilechanged\": \"Profili i cilësisë\",\n  \"components.RequestButton.approverequest4k\": \"Mirato kërkesën 4K\",\n  \"components.RequestCard.deleterequest\": \"Fshije Kërkesën\",\n  \"components.RequestList.RequestItem.mediaerror\": \"Titulli shoqërues për këtë kërkesë nuk është më në dispozicion.\",\n  \"components.RequestButton.viewrequest\": \"Shiko Kërkesën\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Fshije Kërkesën\",\n  \"components.RequestList.RequestItem.failedretry\": \"Diçka shkoi keq duke e riprovuar kërkesën.\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Zgjidh etiketat\",\n  \"components.RequestModal.requestcancelled\": \"Kërkesa për <strong>{title}</strong> u anullua.\",\n  \"components.ResetPassword.password\": \"Fjalëkalimi\",\n  \"components.Settings.RadarrModal.released\": \"Lëshuar\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Ky përdorues lejohet të kërkojë <strong>{limit}</strong> {type} çdo <strong>{days}</strong> ditë.\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.RequestModal.pendingapproval\": \"Kërkesa juaj është në pritje të miratimit.\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Duhet të keni të paktën <strong>{seasons}</strong> {seasons, plural, one {kërkesë sezoni} other {kërkesa sezonesh}} të mbetur në mënyrë që të dërgoni një kërkesë për këtë seri.\",\n  \"components.RequestModal.cancel\": \"Anullo kërkesën\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL nuk duhet të përfundojë me një slesh\",\n  \"i18n.unavailable\": \"I paarritshëm\",\n  \"i18n.tvshow\": \"Seri\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Një link për rivendosjen e fjalëkalimit do të dërgohet në adresën email të dhënë nëse është e lidhur me një përdorues të vlefshëm.\",\n  \"i18n.usersettings\": \"Cilësimet e përdoruesit\",\n  \"components.ResetPassword.confirmpassword\": \"Konfirmo fjalëkalimin\",\n  \"components.ResetPassword.emailresetlink\": \"Linku e rikuperimit të postës elektronike\",\n  \"i18n.tvshows\": \"Seria\",\n  \"components.ResetPassword.passwordreset\": \"Rivendos fjalëkalimin\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Cilësimet e njoftimit Pushbullet u ruajtën me sukses!\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Duhet të jepni një URL të vlefshme\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL nuk duhet të përfundojë me një slesh\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Cilësimet e njoftimit Pushbullet nuk u ruajtën.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Po dërgohet njoftimi i testit Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"Ngarkesa JSON u rivendos me sukses!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Duhet të jepni një URL të vlefshme\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Zgjidh profilin e cilësisë\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Njoftimi i testit Pushbullet dështoi të dërgohet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Njoftimi i testit pushbullet dërguar!\",\n  \"components.Settings.SettingsAbout.outofdate\": \"E skaduar\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP Host\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Duhet të jepni një emër hosti ose adresë IP të vlefshme\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Po dërgohet njoftimi i testit të webhook…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"U dërgua njoftimi i testit webhook!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Rregullimet e njoftimit të Webhook dështuan të ruhen.\",\n  \"components.Settings.Notifications.authPass\": \"Fjalëkalimi SMTP\",\n  \"components.Settings.Notifications.botAPI\": \"Token e Autorizimit të Bot\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Direktoria\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Testo lidhjen për të ngarkuar profilet e cilësisë\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL e webhook\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Cilësimet e njoftimit Webhook u ruajtën me sukses!\",\n  \"components.Settings.Notifications.agentenabled\": \"Aktivizo agjentin\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Lejo çertifikatat e vetë-nënshkruara\",\n  \"components.Settings.Notifications.authUser\": \"Emri i përdoruesit SMTP\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Zgjidh disponueshmërinë minimale\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Zgjidhni dosjen rrënjë\",\n  \"components.Settings.RadarrModal.selecttags\": \"Zgjidh etiketat\",\n  \"components.Settings.RadarrModal.server4k\": \"Serveri 4K\",\n  \"components.Settings.RadarrModal.servername\": \"Emri i serverit\",\n  \"components.Settings.RadarrModal.ssl\": \"Përdor SSL\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Aktivo skanimin\",\n  \"components.Settings.RadarrModal.tags\": \"Etiketat\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Testo lidhjen për të ngarkuar dosjet rrënjë\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Baza e URL-së duhet të ketë slesh në fillim\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Ju duhet të siguroni një emër të vlefshëm host ose adresën IP\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Duhet të japësh një emër serveri\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Lëshimet\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Çelësi privat PGP\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Të dhënat e lëshimit nuk janë të disponueshme.\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentacioni\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Marrja e mbështetjes\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Diskutimet e GitHub\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Dërgo njoftime pa zë\",\n  \"components.Settings.Notifications.senderName\": \"Emri i dërguesit\",\n  \"components.Settings.Notifications.smtpPort\": \"Porta SMTP\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Cilësimet e njoftimit të telegramit u ruajtën me sukses!\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Njoftimi i testit të Discord u dërgua!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Njoftimi i testit me email nuk u dërgua.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Po dërgohet njoftimi i testit me email…\",\n  \"components.Settings.startscan\": \"Nis skanimin\",\n  \"components.Settings.tautulliApiKey\": \"Çelësi API\",\n  \"components.Settings.tautulliSettings\": \"Cilësimet e Tautulli\",\n  \"components.Settings.toastPlexRefresh\": \"Duke marrë listën e serverave nga Plex…\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Konfiguro dhe aktivizo agjentët e njoftimit.\",\n  \"components.Settings.plexlibrariesDescription\": \"Libraritë e Seerr skanojnë për tituj. Vendos dhe ruaj cilësimet e lidhjes Plex, pastaj kliko në butonin më poshtë nëse nuk janë të listuara libraritë.\",\n  \"components.Settings.plexsettingsDescription\": \"Konfiguro cilësimet për serverin tuaj Plex. Seerr skanon libraritë tuaja Plex për të përcaktuar disponueshmërinë e përmbajtjes.\",\n  \"components.Settings.port\": \"Porta\",\n  \"components.Settings.radarrsettings\": \"Cilësimet e Radarr\",\n  \"components.Settings.serverRemote\": \"në distancë\",\n  \"components.Settings.sonarrsettings\": \"Cilësimet e Sonarr\",\n  \"components.Settings.serverLocal\": \"lokale\",\n  \"components.Settings.serverpresetRefreshing\": \"Duke marrë serverat…\",\n  \"components.Settings.tautulliSettingsDescription\": \"Konfiguro në mënyrë opsionale rregullimet për serverin tënd Tautulli. Seerr merr të dhënat e historisë për mediat tuaja Plex nga Tautulli.\",\n  \"components.Settings.plexsettings\": \"Cilësimet e Plex\",\n  \"components.Settings.serverpresetManualMessage\": \"Konfigurimi manual\",\n  \"components.Settings.services\": \"Shërbime\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Gabim gjatë marrjes së listës së serverave Plex.\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Episod} other {Episode}}\",\n  \"components.RequestModal.requestseasons4k\": \"Kërko {seasonCount} {seasonCount, plural, one {Sezon} other {Sezone}} në 4K\",\n  \"components.RequestModal.requestseasons\": \"Kërko {seasonCount} {seasonCount, plural, one {Sezon} other {Sezone}}\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Duhet të zgjidhni të paktën një lloj njoftimi\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Token API i aplikacionit\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Regjistroni një aplikacion</ApplicationRegistrationLink> për ta përdorur me Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Ativizo Agjentin\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Cilësimet e njoftimit të Pushover nuk u ruajtën.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Cilësimet e njoftimit Pushover u ruajtën me sukses!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Njoftimi i testit Pushover dështoi të dërgonte.\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"<UsersGroupsLink>Identifikuesi juaj i grupit ose i përdoruesit</UsersGroupsLink> me 30 karaktere\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Duhet të japësh një token të vlefshëm aplikimi\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Duhet të zgjedhësh të paktën një tip njoftimi\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Duhet të jepni një çelës të vlefshëm përdoruesi ose grupi\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Ativizo Agjentin\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Cilësimet e njoftimit të Slack nuk u ruajtën.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Cilësimet e njoftimeve të Slack u ruajtën me sukses!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Njoftimi i testit të Slack dështoi të dërgohet.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Po dërgohet njoftimi i testit Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"U dërgua njoftimi për testin e Slack!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Duhet të zgjidhni të paktën një lloj njoftimi\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Ngarkesa JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Ndihmë për variablin e shabllonit\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Krijo një bot</CreateBotLink> për ta përdorur me Seerr\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL-ja e Avatarit të Bot\",\n  \"components.Settings.Notifications.botUsername\": \"Emri i përdoruesit të botit\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Lejoni përdoruesit të fillojnë gjithashtu një bisedë me robotin tuaj dhe të konfigurojnë njoftimet e tyre\",\n  \"components.Settings.Notifications.chatId\": \"ID e bisedës\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Cilësimet e njoftimit të Diskordit nuk u ruajtën.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Cilësimet e njoftimit të Diskordit u ruajtën me sukses!\",\n  \"components.Settings.Notifications.emailsender\": \"Adresa e dërguesit\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Cilësimet e njoftimit me email nuk u ruajtën.\",\n  \"components.Settings.Notifications.enableMentions\": \"Aktivizo Përmendjet\",\n  \"components.Settings.Notifications.encryption\": \"Metoda e kriptimit\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Përdorni STARTTLS nëse disponohet\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Përdorni TLS të nënkuptuar\",\n  \"components.Settings.Notifications.encryptionNone\": \"Asnjë\",\n  \"components.Settings.Notifications.encryptionTip\": \"Në shumicën e rasteve, TLS Implicit përdor portën 465 dhe STARTTLS përdor portën 587\",\n  \"components.Settings.Notifications.pgpPassword\": \"Fjalëkalimi PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Nënshkruani mesazhet e emailit të koduar duke përdorur <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Nënshkruani mesazhet e emailit të koduar duke përdorur <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.validationUrl\": \"Duhet të jepni një URL të vlefshme\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL e Webhook\",\n  \"components.Settings.RadarrModal.add\": \"Shto Server\",\n  \"components.Settings.RadarrModal.announced\": \"I shpallur\",\n  \"components.Settings.RadarrModal.apiKey\": \"Çelësi API\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Baza URL\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Shto server të ri 4K Radarr\",\n  \"components.Settings.RadarrModal.createradarr\": \"Shto server të ri Radarr\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Serveri i parazgjedhur 4K\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Serveri i parazgjedhur\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Ndrysho serverin 4K Radarr\",\n  \"components.Settings.RadarrModal.editradarr\": \"Ndrysho serverin Radarr\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Aktivizo Kërkimin Automatik\",\n  \"components.Settings.RadarrModal.externalUrl\": \"URL e jashtme\",\n  \"components.Settings.RadarrModal.hostname\": \"Emri i host ose adresa IP\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Në Kinema\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Po ngarkon etiketat…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Duke ngarkuar profilet e cilësisë…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Duke ngarkuar dosjet rrënjë…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Disponueshmëria minimale\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Media totale\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Kërkesat totale\",\n  \"components.Settings.SettingsAbout.uptodate\": \"E përditësuar\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Memorie Cache\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"Memorja cache {cachename} u fshi.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Hitet\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Çelësat totalë\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Madhësia e çelësit\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Mungesa\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Emri i cache\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Madhësia e vlerës\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Anuloni punën\",\n  \"components.Settings.SettingsJobsCache.command\": \"Komandë\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Rivendos Sinkronizimin e Shkarkimit\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modifiko punën\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Frekuenca\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Çdo {jobScheduleHours, plural, one {orë} other {{jobScheduleHours} orë}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Çdo {jobScheduleMinutes, plural, one {minutë} other {{jobScheduleMinutes} minuta}}\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Pastro Cache\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Diçka shkoi keq duke ruajtur punën.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Puna u modifikua me sukses!\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} u anulua.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Emri i punës\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Punët\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Punët & Cache\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} filloi.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tipi\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Ekzekutimi tjetër\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Skanimi i plotë i Librarisë Plex\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Skanimi i të shtuarave kohët e fundit nga Plex\",\n  \"components.Settings.SettingsJobsCache.process\": \"Procesi\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Skanimi i Radarr\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Nise Tani\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Skanimi i Sonarr\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Punë e panjohur\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Mesazhi i regjistrit u kopjua.\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Kopjo\",\n  \"components.Settings.SettingsLogs.extraData\": \"Të dhëna shtesë\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Korrigjjo\",\n  \"components.Settings.SettingsLogs.filterError\": \"Gabim\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Informacion\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Paralajmërim\",\n  \"components.Settings.SettingsLogs.label\": \"Etiketa\",\n  \"components.Settings.SettingsLogs.level\": \"Ashpërsia\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Detajet e regjistrit\",\n  \"components.Settings.SettingsLogs.logs\": \"Regjistrat\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Ju gjithashtu mund t'i shikoni këto regjistra direkt nëpërmjet <code>stdout</code>, ose në <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Ndalo\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Rinis\",\n  \"components.Settings.SettingsLogs.showall\": \"Shfaq të gjitha regjistrat\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Përdorni gjithmonë STARTTLS\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Çelësi i përdoruesit ose i grupit\",\n  \"components.Settings.Notifications.chatIdTip\": \"Fillo një bisedë me robotin tënd, shto <GetIdBotLink>@get_id_bot</GetIdBotLink>, dhe vendos komandën <code>/my_id</code>\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Duke dërguar njoftimin e testit Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Njoftimi i testit Pushover është dërguar!\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Krijo një integrim <DiscordWebhookLink>webhook</DiscordWebhookLink> në serverin tuaj\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Cilësimet e njoftimit me email u ruajtën me sukses!\",\n  \"components.Settings.SettingsAbout.version\": \"Versioni\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr ruan ne memorje cache kërkesat për api të jashtme për të optimizuar performancën dhe për të shmangur bërjen e thirrjeve API të panevojshme.\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Sinkonizim Shkarkimi\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Mbikëqyrësi kryen disa detyra mirëmbajtjeje si punë të programuara rregullisht, por ato mund të aktivizohen edhe manualisht më poshtë. Bërja manuale e një pune nuk do të ndryshojë programin e saj.\",\n  \"components.Settings.SettingsLogs.message\": \"Mesazh\",\n  \"components.Settings.menuLogs\": \"Regjistrat\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.settingUpPlexDescription\": \"Për të vendosur Plex, ju ose mund të vendosni detajet manualisht ose të zgjidhni një server të marrë nga <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Shtyp butonin në të djathtë të listës për të marrë listën e serverëve në dispozicion.\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Lista e serverëve Plex u mor me sukses!\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Diçka shkoi keq duke ruajtur cilësimet e Tautullit.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Cilësimet e Tautulli u ruajtën me sukses!\",\n  \"components.Settings.urlBase\": \"Baza URL\",\n  \"components.Settings.validationApiKey\": \"Duhet të japësh një çelës API\",\n  \"components.Settings.validationPortRequired\": \"Duhet të jepni një numër të vlefshëm porte\",\n  \"components.Settings.validationUrl\": \"Duhet të jepni një URL të vlefshme\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Baza e URL-së duhet të ketë slesh përpara\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"Baza e URL nuk duhet të përfundojë me një slesh\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL nuk duhet të përfundojë me një slesh\",\n  \"components.Settings.webAppUrl\": \"URL e <WebAppLink>Aplikacionit Web</WebAppLink>\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.webpush\": \"Web Push\",\n  \"components.Setup.configureservices\": \"Konfiguro Shërbimet\",\n  \"components.Setup.continue\": \"Vazhdo\",\n  \"components.Setup.finish\": \"Përfundo konfigurimin\",\n  \"components.Setup.finishing\": \"Duke përfunduar…\",\n  \"components.Setup.setup\": \"Konfigurimi\",\n  \"components.Setup.signinMessage\": \"Filloni duke u identifikuar me llogarinë tuaj Plex\",\n  \"components.Setup.welcome\": \"Mirë se vini në Seerr\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.StatusBadge.status4k\": \"{status} 4K\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Kast i plotë i serisë\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Ekuipazhi i plotë i serisë\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.cast\": \"Kasti\",\n  \"components.TvDetails.episodeRuntime\": \"Gjatësia e Episodit\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Rrjet} other {Rrjete}}\",\n  \"components.TvDetails.nextAirDate\": \"Data e ardhshme e transmetimit\",\n  \"components.TvDetails.originallanguage\": \"Gjuha Origjinale\",\n  \"components.TvDetails.originaltitle\": \"Titulli Origjinal\",\n  \"components.TvDetails.overview\": \"Vështrim i përgjithshëm\",\n  \"components.TvDetails.overviewunavailable\": \"Vështrimi i përgjithshëm i paarritshëm.\",\n  \"components.TvDetails.productioncountries\": \"{countryCount, plural, one {Shtet} other {Shtete}} Prodhimi\",\n  \"components.TvDetails.recommendations\": \"Rekomandime\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# Sezon} other {# Sezone}}\",\n  \"components.TvDetails.showtype\": \"Lloji i serisë\",\n  \"components.TvDetails.similar\": \"Seri të ngjashme\",\n  \"components.TvDetails.streamingproviders\": \"Po Transmetohet Në\",\n  \"components.TvDetails.viewfullcrew\": \"Shiko ekuipazhin e plotë\",\n  \"components.TvDetails.watchtrailer\": \"Shiko Trailerin\",\n  \"components.UserList.accounttype\": \"Tipi\",\n  \"components.UserList.admin\": \"Administrator\",\n  \"components.UserList.autogeneratepassword\": \"Gjenero automatikisht fjalëkalimin\",\n  \"components.UserList.autogeneratepasswordTip\": \"Dërgo një fjalëkalim të gjeneruar nga serveri tek përdoruesi\",\n  \"components.UserList.bulkedit\": \"Redaktimi në masë\",\n  \"components.UserList.create\": \"Krijo\",\n  \"components.UserList.created\": \"Të bashkuar\",\n  \"components.UserList.createlocaluser\": \"Krijo përdorues lokal\",\n  \"components.UserList.creating\": \"Duke krijuar…\",\n  \"components.UserList.deleteconfirm\": \"Je i sigurt që do ta fshish këtë përdorues? Të gjitha të dhënat e kërkesave të tyre do të hiqen përgjithmonë.\",\n  \"components.UserList.deleteuser\": \"Fshi përdoruesin\",\n  \"components.UserList.edituser\": \"Ndrysho të drejtat e përdoruesit\",\n  \"components.UserList.localLoginDisabled\": \"Cilësimi <strong>Aktivizo identifikimin lokal</strong> është aktualisht i çaktivizuar.\",\n  \"components.UserList.localuser\": \"Përdorues Lokal\",\n  \"components.UserList.newplexsigninenabled\": \"Cilësimi <strong>Aktivizo hyrjen e re në Plex</strong> është aktualisht i aktivizuar. Përdoruesit e Plex me akses në librari nuk kanë nevojë të importohen për t'u identifikuar.\",\n  \"components.UserList.nouserstoimport\": \"Nuk ka përdorues Plex për të importuar.\",\n  \"components.UserList.owner\": \"Pronari\",\n  \"components.UserList.password\": \"Fjalëkalimi\",\n  \"components.UserList.passwordinfodescription\": \"Konfiguro një URL aplikacioni dhe aktivizo njoftimet me email për të lejuar gjenerimin automatik të fjalëkalimit.\",\n  \"components.UserList.plexuser\": \"Përdoruesi Plex\",\n  \"components.UserList.sortRequests\": \"Numri i kërkesave\",\n  \"components.UserList.role\": \"Roli\",\n  \"components.UserList.sortCreated\": \"Data e anëtarësimit\",\n  \"components.UserList.sortDisplayName\": \"Emri i shfaqur\",\n  \"components.UserList.totalrequests\": \"Kërkesat\",\n  \"components.UserList.user\": \"Përdoruesi\",\n  \"components.UserList.usercreatedfailed\": \"Diçka shkoi keq duke krijuar përdoruesin.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Adresa e email-it e dhënë është tashmë në përdorim nga një përdorues tjetër.\",\n  \"components.UserList.usercreatedsuccess\": \"Përdoruesi u krijua me sukses!\",\n  \"components.UserList.userdeleted\": \"Përdoruesi u fshi me sukses!\",\n  \"components.UserList.userdeleteerror\": \"Diçka shkoi keq duke fshirë përdoruesin.\",\n  \"components.UserList.userfail\": \"Diçka shkoi keq duke ruajtur lejet e përdoruesit.\",\n  \"components.UserList.userlist\": \"Lista e përdoruesve\",\n  \"components.UserList.users\": \"Përdoruesit\",\n  \"components.UserList.userssaved\": \"Të drejtat e përdoruesit të ruajtura me sukses!\",\n  \"components.UserList.validationEmail\": \"Ju duhet të jepni një adresë të vlefshme e-mail\",\n  \"components.UserList.validationpasswordminchars\": \"Fjalëkalimi është shumë i shkurtër; duhet të jetë një minimum prej 8 karakteresh\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"U bashkua në {joindate}\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Shfaq profilin\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Ndrysho cilësimet\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID e përdoruesit: {userid}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Lloji i llogarisë\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrator\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Shfaq Gjuhën\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Emri i shfaqur\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID e përdoruesit të Diskordit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"<FindDiscordIdLink>Numri i identifikimit me shumë shifra</FindDiscordIdLink> i lidhur me llogarinë tuaj të përdoruesit Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Tejkalo limitin global\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Gjeneral\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Cilësimet e përgjithshme\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"E Parazgjedhur ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Përdorues Lokal\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Kufiri i Kërkesës për Film\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Gjuha e Zbulimit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtro përmbajtjen sipas gjuhës origjinale\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtro përmbajtjen sipas disponueshmërisë rajonale\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Roli\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Pronari\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Përdoruesi Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Rajoni i Zbulimit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Diçka shkoi keq duke ruajtur cilësimet.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Cilësimet u ruajtën me sukses!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Ju duhet të siguroni një ID të vlefshme të përdoruesit Discord\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID e përdoruesit\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Limiti i kërkesës së serisë\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Cilësimet e njoftimit me email nuk u ruajtën.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Cilësimet e njoftimit me email u ruajtën me sukses!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Njoftimet\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Cilësimet e njoftimit\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Çelësi publik PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Kripto mesazhet e emailit duke përdorur <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Cilësimet e njoftimit Pushbullet nuk u ruajtën.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Cilësimet e njoftimit Pushbullet u ruajtën me sukses!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Token API i aplikacionit\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Çelësi i përdoruesit ose i grupit\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"<UsersGroupsLink>Identifikuesi juaj i grupit ose i përdoruesit</UsersGroupsLink> me 30 karaktere\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Cilësimet e njoftimit të Pushover nuk u ruajtën.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Dërgo në heshtje\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Dërgo njoftime pa zë\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID e bisedës\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink> Fillo një chat</TelegramBotLink>, shto <GetIdBotLink>@get_id_bot</GetIdBotLink>, dhe lëshoni komandën <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Cilësimet e njoftimit të Telegramit nuk u ruajtën.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Cilësimet e njoftimit Pushover u ruajtën me sukses!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Cilësimet e njoftimit të Telegramit u ruajtën me sukses!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Ju duhet të jepni një ID të vlefshme përdoruesi\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Duhet të japësh një token të vlefshëm aplikimi\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Duhet të jepni një çelës të vlefshëm përdoruesi ose grupi\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Duhet të jepni një ID të vlefshme bisede\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Push\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Konfirmo fjalëkalimin\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Fjalëkalimi aktual\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Fjalëkalimi i ri\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Kjo llogari përdoruesi aktualisht nuk ka një fjalëkalim të caktuar. Konfiguro një fjalëkalim më poshtë për të mundësuar që kjo llogari të identifikohet si \\\"përdorues lokal.\\\"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Llogaria juaj aktualisht nuk ka një fjalëkalim të caktuar. Konfiguro një fjalëkalim më poshtë për të mundësuar identifikimin si \\\"përdorues lokal\\\" duke përdorur adresën tënde të emailit.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Fjalëkalimi\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Diçka shkoi keq duke ruajtur fjalëkalimin.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Fjalëkalimi u ruajt me sukses!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Ju duhet të konfirmoni fjalëkalimin e ri\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Fjalëkalimet duhet të përputhen\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Duhet të japësh një fjalëkalim të ri\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Fjalëkalimi është shumë i shkurtër; duhet të jetë së paku 8 karaktere\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Lejet\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Nuk mund të ndryshosh të drejtat e tua.\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Fjalëkalimi\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Gjeneral\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Njoftime\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Lejet\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Ju nuk keni leje për të modifikuar cilësimet e këtij përdoruesi.\",\n  \"components.UserProfile.limit\": \"{remaining} prej {limit}\",\n  \"components.UserProfile.pastdays\": \"{type} (kaluar {days} ditë)\",\n  \"components.UserProfile.recentlywatched\": \"Shikuar së fundmi\",\n  \"components.UserProfile.totalrequests\": \"Kërkesat totale\",\n  \"components.UserProfile.unlimited\": \"Pa Limit\",\n  \"i18n.advanced\": \"E avancuar\",\n  \"i18n.approved\": \"Aprovuar\",\n  \"i18n.areyousure\": \"A je i sigurt?\",\n  \"i18n.canceling\": \"Duke anulluar…\",\n  \"i18n.close\": \"Mbylle\",\n  \"i18n.decline\": \"Refuzo\",\n  \"i18n.declined\": \"Refuzuar\",\n  \"i18n.delete\": \"Fshije\",\n  \"i18n.deleting\": \"Duke e fshirë…\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.failed\": \"Dështoi\",\n  \"i18n.import\": \"Importo\",\n  \"i18n.importing\": \"Duke importuar…\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.open\": \"Hap\",\n  \"i18n.partiallyavailable\": \"Pjesërisht në dispozicion\",\n  \"i18n.pending\": \"Në pritje\",\n  \"i18n.previous\": \"Para\",\n  \"i18n.processing\": \"Përpunim\",\n  \"i18n.request\": \"Kërkesë\",\n  \"i18n.request4k\": \"Kërkesë në 4K\",\n  \"i18n.save\": \"Ruaj ndryshimet\",\n  \"i18n.saving\": \"Duke ruajtur…\",\n  \"i18n.settings\": \"Cilësimet\",\n  \"i18n.requested\": \"E Kërkuar\",\n  \"i18n.requesting\": \"Duke kërkuar…\",\n  \"i18n.resolved\": \"U Zgjidh\",\n  \"i18n.resultsperpage\": \"Shfaq {pageSize} rezultate për faqe\",\n  \"i18n.retry\": \"Provo sërish\",\n  \"i18n.retrying\": \"Duke provuar sërish…\",\n  \"i18n.showingresults\": \"Duke shfaqur <strong>{from}</strong> tek <strong>{to}</strong> e <strong>{total}</strong> rezultateve\",\n  \"i18n.status\": \"Statusi\",\n  \"i18n.test\": \"Test\",\n  \"pages.internalservererror\": \"Gabim i brendshëm i serverit\",\n  \"pages.oops\": \"Ups\",\n  \"pages.pagenotfound\": \"Faqja nuk u gjet\",\n  \"pages.returnHome\": \"Kthehu në shtëpi\",\n  \"pages.serviceunavailable\": \"Shërbimi i paarritshëm\",\n  \"pages.somethingwentwrong\": \"Diçka shkoi keq\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Sezon} other {Sezone}}\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr në Zhvillim\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stabël\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {luajtje} other {luajtje}}\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Data e Lëshimit} other {Datat e Lëshimit}}\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studio}}\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {ditë} other {ditë}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {filma}}\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {sezon} other {sezone}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} për {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} për {quotaDays} {days}</quotaUnits>\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Sezon} other {Sezone}}\",\n  \"components.RequestButton.approve4krequests\": \"Aprovo {requestCount, plural, one {Kërkesën 4K} other {{requestCount} Kërkesat 4K}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Sezoni} other {Sezonet}}\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Sezoni} other {Sezonet}}\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (e parazgjedhur)\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {filma}}\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Asnjë} other {<strong>#</strong>}} {type} {remaining, plural, one {kërkesë} other {kërkesa}} ngelur\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {sezon} other {sezone}}\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Nuk ka etiketa.\",\n  \"components.Settings.RadarrModal.port\": \"Porta\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Profili i cilësisë\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Ndryshimet\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Ju jeni duke përdorur degën <code>develop</code> të Seerr, e cila është e rekomanduar vetëm për ata që kontribuojnë në zhvillimin ose të ndihmojë në testimin.\",\n  \"components.Settings.SettingsAbout.timezone\": \"Zona Kohore\",\n  \"components.Settings.SettingsLogs.time\": \"Vula kohore\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Lejet e parazgjedhura\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Aktivizo identifikimin lokal\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Lejo përdoruesit të identifikohen duke përdorur adresën e tyre të emailit dhe fjalëkalimin, në vend të Plex OAuth\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Limiti Global i kërkesës për Filma\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Aktivizo hyrjen në {mediaServerName} të ri\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Lejo përdoruesit e {mediaServerName} të identifikohen pa u importuar më parë\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Diçka shkoi keq duke ruajtur cilësimet.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Cilësimet e përdoruesit u ruajtën me sukses!\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Limiti Global i kërkesës së Serialeve\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Cilësimet e përdoruesit\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Konfiguro cilësimet globale dhe të paracaktuara të përdoruesit.\",\n  \"components.Settings.SettingsUsers.users\": \"Përdoruesit\",\n  \"components.Settings.SonarrModal.add\": \"Shto Server\",\n  \"components.Settings.SonarrModal.animeTags\": \"Etiketat anime\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Profili i gjuhës anime\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Profili i Cilësisë së Anime\",\n  \"components.Settings.SonarrModal.apiKey\": \"Çelësi API\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Baza URL\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Shto Serverin e Ri Sonarr\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Ndrysho serverin 4K Sonarr\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Ndrysho serverin Sonarr\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Aktivizo Kërkimin Automatik\",\n  \"components.Settings.SonarrModal.externalUrl\": \"URL e jashtme\",\n  \"components.Settings.SonarrModal.hostname\": \"Emri i hostit ose adresa IP\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Profili i gjuhës\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Duke ngarkuar etiketat…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Ngarkimi i profileve gjuhësore…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Duke ngarkuar profilet e cilësisë…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Duke ngarkuar dosjet rrënjë…\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Nuk ka etiketa.\",\n  \"components.Settings.SonarrModal.port\": \"Porta\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Profili i cilësisë\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Direktoria\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Dosjet e sezonit\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Zgjidh profilin e gjuhës\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Zgjidh profilin e cilësisë\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Zgjidhni dosjen rrënjë\",\n  \"components.Settings.SonarrModal.selecttags\": \"Zgjidh etiketat\",\n  \"components.Settings.SonarrModal.server4k\": \"Serveri 4K\",\n  \"components.Settings.SonarrModal.servername\": \"Emri i serverit\",\n  \"components.Settings.SonarrModal.tags\": \"Etiketat\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Testo lidhjen për të ngarkuar profilet e cilësisë\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Testo lidhjen për të ngarkuar dosjet rrënjë\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Dështoi lidhja me Sonarr.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Lidhja Sonarr u krijua me sukses!\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Duhet të japësh një çelës API\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Duhet të jepni një URL të vlefshme\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL nuk duhet të përfundojë me një slesh\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"URL bazë duhet të ketë një slesh perpara\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"URL bazë nuk duhet të përfundojë me një slesh\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Ju duhet të siguroni një emër të vlefshëm host ose adrese IP\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Duhet të zgjedhësh një profil gjuhe\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Duhet të japësh një emër serveri\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Duhet të jepni një numër të vlefshëm porte\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Duhet të zgjedhësh një profil cilësie\",\n  \"components.Settings.activeProfile\": \"Profili aktiv\",\n  \"components.Settings.addradarr\": \"Shto Serverin Radarr\",\n  \"components.Settings.address\": \"Adresa\",\n  \"components.Settings.addsonarr\": \"Shto Serverin Sonarr\",\n  \"components.Settings.cancelscan\": \"Anullo skanimin\",\n  \"components.Settings.currentlibrary\": \"Libraria aktuale: {name}\",\n  \"components.Settings.default\": \"E paracaktuar\",\n  \"components.Settings.default4k\": \"E Paracaktuar 4K\",\n  \"components.Settings.deleteserverconfirm\": \"Jeni i sigurt që dëshironi ta fshini këtë server?\",\n  \"components.Settings.email\": \"Email\",\n  \"components.Settings.enablessl\": \"Përdorni SSL\",\n  \"components.Settings.externalUrl\": \"URL e jashtme\",\n  \"components.Settings.hostname\": \"Emri i hostit ose adresa IP\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.librariesRemaining\": \"Libraritë e mbetura: {count}\",\n  \"components.Settings.manualscan\": \"Skanimi manual i Librarisë\",\n  \"components.Settings.manualscanDescription\": \"Normalisht, kjo do të bëhet vetëm një herë në 24 orë. Seerr do të kontrollojë serverin tuaj Plex për media të shtuar kohët e fundit në mënyrë më agresive. Nëse kjo është hera e parë që konfiguroni Plex, këshillohet një skanim manual një herë i plotë i librarisë!\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.mediaTypeSeries\": \"seri\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Serveri i parazgjedhur 4K\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Dosja e rrënjës së animes\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Lejet fillestare të caktuara për përdoruesit e rinj\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Serveri i parazgjedhur\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Lidhja e provës për të ngarkuar profilet e gjuhës\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Shto Serverin e Ri Sonarr 4K\",\n  \"components.Settings.SonarrModal.ssl\": \"Përdor SSL\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Aktivo skanimin\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Testo lidhjen për të ngarkuar etiketat\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Duhet të zgjedhësh një dosje rrënjë\",\n  \"components.Settings.serviceSettingsDescription\": \"Konfiguro serverin tënd {serverType} më poshtë. Ju mund të lidhni shumë servera {serverType}, por vetëm dy prej tyre mund të shënohen si të prezgjedhur (një jo-4K dhe një 4K). Administratorët janë në gjendje të kapërcejnë serverin e përdorur për të përpunuar kërkesa të reja përpara miratimit.\",\n  \"components.Settings.validationHostnameRequired\": \"Ju duhet të siguroni një emër të vlefshëm host ose adrese IP\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Ju nuk keni leje për të modifikuar fjalëkalimin e këtij përdoruesi.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Diçka shkoi keq duke ruajtur fjalëkalimin. A u fut fjalëkalimi në mënyrë korrekte?\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Diçka shkoi keq duke ruajtur cilësimet.\",\n  \"components.Settings.webAppUrlTip\": \"Në mënyrë opsionale drejto përdoruesit në aplikacionin web në serverin tënd në vend të atij web\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minuta\",\n  \"components.UserList.importfrommediaserver\": \"Importoni përdoruesit {mediaServerName}\",\n  \"components.UserList.importfromplex\": \"Importoni përdoruesit Plex\",\n  \"components.UserList.importfromplexerror\": \"Diçka shkoi keq duke importuar përdoruesit Plex.\",\n  \"components.TvDetails.firstAirDate\": \"Data e parë e transmetimit\",\n  \"components.UserList.email\": \"Adresa email\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> {userCount, plural, one {përdorues} other {përdorues}} nga Plex u importuan me sukses!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"<FindDiscordIdLink>Numri i identifikimit me shumë shifra</FindDiscordIdLink> i lidhur me llogarinë tuaj të përdoruesit\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Duhet të jepni një çelës publik të vlefshëm PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Duhet të japësh një Token hyrjeje\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Lejet u ruajtën me sukses!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Cilësimet e njoftimit të Diskordit nuk u ruajtën.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Krijo një token nga <PushbulletSettingsLink>Cilësimet e llogarisë</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Regjistro një aplikacion</ApplicationRegistrationLink> për përdorim me {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Ju duhet të jepni fjalëkalimin tuaj aktual\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Cilësimet e njoftimit të Diskordit u ruajtën me sukses!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Email\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Përdoruesi\",\n  \"i18n.movies\": \"Filma\",\n  \"components.UserProfile.recentrequests\": \"Kërkesat e Fundit\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Token Aksesimi\",\n  \"components.UserProfile.movierequests\": \"Kërkesa për filma\",\n  \"components.UserProfile.requestsperdays\": \"{limit} të mbetura\",\n  \"i18n.all\": \"Të gjitha\",\n  \"i18n.approve\": \"Mirato\",\n  \"i18n.back\": \"Mbrapa.\",\n  \"i18n.loading\": \"Po ngarkohet…\",\n  \"components.UserProfile.seriesrequest\": \"Kërkesat e serisë\",\n  \"i18n.available\": \"Në dispozicion\",\n  \"i18n.cancel\": \"Anulo\",\n  \"i18n.edit\": \"Ndrysho\",\n  \"i18n.next\": \"Tjetra\",\n  \"i18n.experimental\": \"Eksperimentale\",\n  \"i18n.noresults\": \"S'ka rezultate.\",\n  \"i18n.notrequested\": \"Nuk është Kerkuar\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Direktoria e të dhënave\",\n  \"components.MovieDetails.digitalrelease\": \"Publikimi Dixhital\",\n  \"components.MovieDetails.physicalrelease\": \"Lëshimi Fizik\",\n  \"components.MovieDetails.theatricalrelease\": \"Publikimi Teatror\",\n  \"components.PermissionEdit.viewrecent\": \"Shiko Shtuar së fundi\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Jep leje për të parë listën e mediave të shtuara kohët e fundit.\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Lista juaj e shikimit në Plex\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Jepni lejen për të paraqitur automatikisht kërkesat për mediat jo-4K nëpërmjet Plex Watchlist.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Kërkesa Automatike Serialesh\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Jep leje për të paraqitur automatikisht kërkesat për seri jo-4K nëpërmjet Plex Watchlist.\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Lista e Shikimit Plex\",\n  \"components.Discover.plexwatchlist\": \"Lista juaj e shikimit në Plex\",\n  \"components.MovieDetails.reportissue\": \"Raportoni një problem\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Kërkesa u dorëzua automatikisht\",\n  \"components.PermissionEdit.autorequest\": \"Auto-Kërkesë\",\n  \"components.PermissionEdit.autorequestDescription\": \"Jepni lejen për të paraqitur automatikisht kërkesat për mediat jo-4K nëpërmjet Plex Watchlist.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Kërkesë automatike për filma\",\n  \"components.PermissionEdit.viewwatchlists\": \"Shiko listat e shikimit të Plex\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Jep leje për të parë listat e Plex Watchlist të përdoruesve të tjerë.\",\n  \"components.MovieDetails.managemovie\": \"Menaxho filmin\",\n  \"components.AirDateBadge.airedrelative\": \"Transmetuar {relativeTime}\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Kërkesat e Filmave\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Kërkesat e Serialeve\",\n  \"components.Layout.UserDropdown.requests\": \"Kërkesat\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rezultati i audiencës së Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Tomatometeri i Rotten Tomatoes\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Njoftohuni kur kërkesat e reja të medias dorëzohen automatikisht për artikujt në Listën tuaj të Plex Watchlist.\",\n  \"components.RequestBlock.languageprofile\": \"Profili i gjuhës\",\n  \"components.AirDateBadge.airsrelative\": \"Duke u Transmetuar {relativeTime}\",\n  \"components.Discover.emptywatchlist\": \"Këtu do të shfaqet media e shtuar në listën tuaj <PlexWatchlistSupportLink>Plex</PlexWatchlistSupportLink>.\",\n  \"components.RequestBlock.decline\": \"Refuzo kërkesën\",\n  \"components.RequestBlock.delete\": \"Fshije Kërkesën\",\n  \"components.RequestBlock.edit\": \"Ndrysho kërkesën\",\n  \"components.MovieDetails.tmdbuserscore\": \"Nota e përdoruesve TMDB\",\n  \"components.RequestBlock.approve\": \"Mirato Kërkesën\",\n  \"components.RequestBlock.lastmodifiedby\": \"Ndryshuar së fundi nga\",\n  \"components.RequestBlock.requestdate\": \"Data e Kërkesës\",\n  \"components.RequestBlock.requestedby\": \"Kërkuar nga\",\n  \"components.RequestCard.approverequest\": \"Mirato Kërkesën\",\n  \"components.Discover.CreateSlider.addSlider\": \"\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"\",\n  \"components.Discover.CreateSlider.addfail\": \"\",\n  \"components.Discover.CreateSlider.addsuccess\": \"\",\n  \"components.Discover.CreateSlider.editSlider\": \"\",\n  \"components.Discover.CreateSlider.editfail\": \"\",\n  \"components.Discover.CreateSlider.editsuccess\": \"\",\n  \"components.Discover.CreateSlider.needresults\": \"\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"\",\n  \"components.Discover.CreateSlider.searchGenres\": \"\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"\",\n  \"components.Discover.CreateSlider.searchStudios\": \"\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"\",\n  \"components.Discover.CreateSlider.starttyping\": \"\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"\",\n  \"components.Discover.DiscoverTv.activefilters\": \"\",\n  \"components.Discover.DiscoverTv.discovertv\": \"\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"\",\n  \"components.Discover.FilterSlideover.activefilters\": \"\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.filters\": \"\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"\",\n  \"components.Discover.FilterSlideover.from\": \"\",\n  \"components.Discover.FilterSlideover.genres\": \"\",\n  \"components.Discover.FilterSlideover.keywords\": \"\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"\",\n  \"components.Discover.FilterSlideover.ratingText\": \"\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"\",\n  \"components.Discover.FilterSlideover.runtime\": \"\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"\",\n  \"components.Discover.FilterSlideover.studio\": \"\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"\",\n  \"components.Discover.FilterSlideover.to\": \"\",\n  \"components.Discover.FilterSlideover.voteCount\": \"\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.Discover.createnewslider\": \"\",\n  \"components.Discover.customizediscover\": \"\",\n  \"components.Discover.moviegenres\": \"\",\n  \"components.Discover.resetfailed\": \"\",\n  \"components.Discover.resetsuccess\": \"\",\n  \"components.Discover.resettodefault\": \"\",\n  \"components.Discover.resetwarning\": \"\",\n  \"components.Discover.stopediting\": \"\",\n  \"components.Discover.studios\": \"\",\n  \"components.Discover.tmdbmoviegenre\": \"\",\n  \"components.Discover.tmdbmoviekeyword\": \"\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"\",\n  \"components.Discover.tmdbnetwork\": \"\",\n  \"components.Discover.tmdbsearch\": \"\",\n  \"components.Discover.tmdbstudio\": \"\",\n  \"components.Discover.tmdbtvgenre\": \"\",\n  \"components.Discover.tmdbtvkeyword\": \"\",\n  \"components.Discover.tmdbtvstreamingservices\": \"\",\n  \"components.Discover.tvgenres\": \"\",\n  \"components.Discover.updatefailed\": \"\",\n  \"components.Discover.updatesuccess\": \"\",\n  \"components.DownloadBlock.formattedTitle\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Layout.Sidebar.browsemovies\": \"\",\n  \"components.Layout.Sidebar.browsetv\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.imdbuserscore\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.RequestCard.cancelrequest\": \"\",\n  \"components.RequestCard.declinerequest\": \"\",\n  \"components.RequestCard.editrequest\": \"\",\n  \"components.RequestCard.tmdbid\": \"\",\n  \"components.RequestCard.tvdbid\": \"\",\n  \"components.RequestCard.unknowntitle\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.RequestItem.tmdbid\": \"\",\n  \"components.RequestList.RequestItem.tvdbid\": \"\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"\",\n  \"components.RequestModal.requestcollection4ktitle\": \"\",\n  \"components.RequestModal.requestcollectiontitle\": \"\",\n  \"components.RequestModal.requestmovie4ktitle\": \"\",\n  \"components.RequestModal.requestmovietitle\": \"\",\n  \"components.RequestModal.requestseries4ktitle\": \"\",\n  \"components.RequestModal.requestseriestitle\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.nooptions\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchGenres\": \"\",\n  \"components.Selector.searchKeywords\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchStudios\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Selector.showless\": \"\",\n  \"components.Selector.showmore\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.tagRequests\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"\",\n  \"components.Settings.SettingsMain.apikey\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"\",\n  \"components.Settings.SettingsMain.applicationurl\": \"\",\n  \"components.Settings.SettingsMain.cacheImages\": \"\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.general\": \"\",\n  \"components.Settings.SettingsMain.generalsettings\": \"\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.locale\": \"\",\n  \"components.Settings.SettingsMain.originallanguage\": \"\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.advancedTooltip\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.deleteServer\": \"\",\n  \"components.Settings.experimentalTooltip\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.restartrequiredTooltip\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.managemedia\": \"\",\n  \"components.StatusBadge.openinarr\": \"\",\n  \"components.StatusBadge.playonplex\": \"\",\n  \"components.StatusBadge.seasonepisodenumber\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.StatusChecker.appUpdated\": \"\",\n  \"components.StatusChecker.appUpdatedDescription\": \"\",\n  \"components.StatusChecker.reloadApp\": \"\",\n  \"components.StatusChecker.restartRequired\": \"\",\n  \"components.StatusChecker.restartRequiredDescription\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.mediaerror\": \"\",\n  \"components.TitleCard.tmdbid\": \"\",\n  \"components.TitleCard.tvdbid\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.Season.noepisodes\": \"\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.episodeCount\": \"\",\n  \"components.TvDetails.manageseries\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.reportissue\": \"\",\n  \"components.TvDetails.rtaudiencescore\": \"\",\n  \"components.TvDetails.rtcriticsscore\": \"\",\n  \"components.TvDetails.seasonnumber\": \"\",\n  \"components.TvDetails.seasonstitle\": \"\",\n  \"components.TvDetails.status4k\": \"\",\n  \"components.TvDetails.tmdbuserscore\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.emptywatchlist\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"components.UserProfile.plexwatchlist\": \"\",\n  \"i18n.collection\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"i18n.restartRequired\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Discover.CreateSlider.nooptions\": \"\",\n  \"components.Discover.networks\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Selector.starttyping\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.TitleCard.cleardata\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/sr.json",
    "content": "{\n  \"components.RequestModal.requestseasons\": \"Zatraži {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}\",\n  \"components.Layout.Sidebar.dashboard\": \"Pronađi novo\",\n  \"pages.returnHome\": \"Povratak na glavnu stranicu\",\n  \"pages.oops\": \"Ups\",\n  \"i18n.unavailable\": \"Nije dostupno\",\n  \"i18n.tvshows\": \"Serije\",\n  \"i18n.processing\": \"Obradjuje se\",\n  \"i18n.pending\": \"Na čekanju\",\n  \"i18n.partiallyavailable\": \"Delimično dostupno\",\n  \"i18n.movies\": \"Filmovi\",\n  \"i18n.deleting\": \"Brisanje u toku…\",\n  \"i18n.delete\": \"Obriši\",\n  \"i18n.declined\": \"Odbijeno\",\n  \"i18n.decline\": \"Odbij\",\n  \"i18n.cancel\": \"Poništi\",\n  \"i18n.available\": \"Dostupno\",\n  \"i18n.approved\": \"Odobreno\",\n  \"i18n.approve\": \"Odobri\",\n  \"components.UserList.userlist\": \"Lista korisnika\",\n  \"components.UserList.userdeleteerror\": \"Nešto nije u redu prilikom brisanje korisnika.\",\n  \"components.UserList.userdeleted\": \"Korisnik izbrisan!\",\n  \"components.UserList.user\": \"Korisnik\",\n  \"components.UserList.totalrequests\": \"Zahtevi\",\n  \"components.UserList.role\": \"Uloga\",\n  \"components.UserList.plexuser\": \"Plex korisnik\",\n  \"components.UserList.deleteuser\": \"Izbriši korisnika\",\n  \"components.UserList.deleteconfirm\": \"Da li ste sigurni da želite da izbrišete ovog korisnika? Svi njegovi zahtevi će biti trajno izbrisani.\",\n  \"components.UserList.created\": \"Pridružio\",\n  \"components.UserList.admin\": \"Administrator\",\n  \"components.TvDetails.similar\": \"Slične serije\",\n  \"components.TvDetails.showtype\": \"Tip serije\",\n  \"components.TvDetails.recommendations\": \"Preporuke\",\n  \"components.TvDetails.overviewunavailable\": \"Pregled nije dostupan.\",\n  \"components.TvDetails.overview\": \"Pregled\",\n  \"components.TvDetails.originallanguage\": \"Originalni jezik\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Mreža} other {Mreže}}\",\n  \"components.TvDetails.cast\": \"Uloge\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Svi glumci serije\",\n  \"components.Setup.welcome\": \"Dobrodošli u Seerr\",\n  \"components.Setup.signinMessage\": \"Započni tako što ćete se prijaviti sa svojim Plex nalogom\",\n  \"components.Setup.finishing\": \"Završavanje…\",\n  \"components.Setup.finish\": \"Završite podešavanja\",\n  \"components.Setup.continue\": \"Nastavi\",\n  \"components.Setup.configureservices\": \"Konfiguriši servise\",\n  \"components.Settings.validationPortRequired\": \"Morate dodati važeći broj porta\",\n  \"components.Settings.validationHostnameRequired\": \"Morate dodati važeći hostname ili IP adresu\",\n  \"components.Settings.startscan\": \"Pokreni skeniranje\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.sonarrsettings\": \"Sonarr podešavanja\",\n  \"components.Settings.radarrsettings\": \"Radarr podešavanja\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.plexsettingsDescription\": \"Konfigurišite podešavanja za Vaš Plex server. Seerr skenira vaše Plex biblioteke da utvrdi šta je dostupno od sadržaja.\",\n  \"components.Settings.plexsettings\": \"Plex podešavanja\",\n  \"components.Settings.plexlibrariesDescription\": \"Seerr skenira sadržaj za imena. Podesite informacije o Plex konekciji, a zatim kliknite dugme ispod ako nije navedena nijedna biblioteka.\",\n  \"components.Settings.plexlibraries\": \"Plex biblioteke\",\n  \"components.Settings.notificationsettings\": \"Podešavanje notifikacija\",\n  \"components.Settings.menuServices\": \"Servisi\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Notifikacije\",\n  \"components.Settings.menuLogs\": \"Logovi\",\n  \"components.Settings.menuJobs\": \"Poslovi & Keš\",\n  \"components.Settings.menuGeneralSettings\": \"Opšta\",\n  \"components.Settings.menuAbout\": \"O nama\",\n  \"components.Settings.manualscanDescription\": \"Normalno, ovo će biti pokrenutno na svakih 24 sata. Seerr će proveriti nedavno dodati Plex sadržaj češće. Ako je ovo prvi put da se Plex konfiguriše, jedan ručni scan sadržaja je preporučen!\",\n  \"components.Settings.manualscan\": \"Ručno skeniranje sadržaja\",\n  \"components.Settings.librariesRemaining\": \"Broj sadržaja koji se obradjuje: {count}\",\n  \"components.Settings.hostname\": \"Hostname ili IP adresa\",\n  \"components.Settings.deleteserverconfirm\": \"Da li ste sigurni da želite da izbrišete ovaj server?\",\n  \"components.Settings.default4k\": \"Podrazumevano 4K\",\n  \"components.Settings.default\": \"Podrazumeno\",\n  \"components.Settings.currentlibrary\": \"Trenutna biblioteka: {name}\",\n  \"components.Settings.cancelscan\": \"Otkaži skeniranje\",\n  \"components.Settings.addsonarr\": \"Dodaj Sonarr server\",\n  \"components.Settings.address\": \"Adresa\",\n  \"components.Settings.addradarr\": \"Dodaj Radarr server\",\n  \"components.Settings.activeProfile\": \"Aktivni profil\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Morate odabrati root folder\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Morate odabrati profil kvaliteta\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Morate popuniti važeći broj porta\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Morate popuniti ime servera\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Morate dodati važeći hostname ili IP adresu\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Morate dodati API ključ\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Testirajte konekciju da učitate root foldere\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Testirajte konekciju da učitate profile kvaliteta\",\n  \"components.Settings.SonarrModal.ssl\": \"Koristi SSL\",\n  \"components.Settings.SonarrModal.servername\": \"Naziv servera\",\n  \"components.Settings.SonarrModal.server4k\": \"4K Server\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Odaberi root folder\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Odaberi profil kvaliteta\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Sezona folderi\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Root folder\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Profil kvaliteta\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Učitavanje root foldera…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Učitavanje profila kvaliteta…\",\n  \"components.Settings.SonarrModal.hostname\": \"Hostname ili IP adresa\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Izmeni Sonarr server\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Podrazumevani server\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Dodaj novi Sonarr server\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Osnovni URL\",\n  \"components.Settings.SonarrModal.apiKey\": \"API Ključ\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Root folder za anime\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Kvalitet profila za anime\",\n  \"components.Settings.SonarrModal.add\": \"Dodaj server\",\n  \"components.Settings.SettingsAbout.version\": \"Verzija\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Ukupno zahteva\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Ukupno medija\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub rasprave\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Pomoć\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Morate odabrati root folder\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Morate odabrati profil kvaliteta\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Morate da navedete važeći broj porta\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Morate popuniti ime servera\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Morate odabrati minimalnu dostupnost\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Morate dodati hostname ili IP adresu\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Morate dodati API ključ\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Konekcija sa Radarr serverom uspešno uspostavljena!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Neuspešna konekcija ka Radarr.\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Testirajte konekciju da učitate root foldere\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Testirajte konekciju da učitate profile kvaliteta\",\n  \"components.Settings.notrunning\": \"Ne radi\",\n  \"components.Settings.RadarrModal.ssl\": \"Koristi SSL\",\n  \"components.Settings.RadarrModal.servername\": \"Naziv servera\",\n  \"components.Settings.RadarrModal.server4k\": \"4K Server\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Odaberi root folder\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Odaberi profil kvaliteta\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Odaberi minimalnu dostupnost\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Root folder\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Profil kvaliteta\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Minimalna dostupnost\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Učitavanje root foldera…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Učitavanje nivoa kvaliteta…\",\n  \"components.Settings.RadarrModal.hostname\": \"Hostname ili IP adresa\",\n  \"components.Settings.RadarrModal.editradarr\": \"Izmeni Radarr server\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Podrazumevani server\",\n  \"components.Settings.RadarrModal.createradarr\": \"Dodaj novi Radarr server\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Osnovni URL\",\n  \"components.Settings.RadarrModal.apiKey\": \"API Ključ\",\n  \"components.Settings.RadarrModal.add\": \"Dodaj Server\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook adresa\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Morate da navedete važeći broj porta\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Morate da navedete važeće ime hosta ili IP adresu\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP Port\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP Host\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Email notifikacija uspešno sačuvana!\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Email notifikacija nije uspešno sačuvana.\",\n  \"components.Settings.Notifications.emailsender\": \"Adresa pošiljaoca\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord notifikacija uspešno sačuvana!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discord notifikacija za podešavanje nije uspešno sačuvana.\",\n  \"components.Settings.Notifications.authUser\": \"SMTP Korisničko ime\",\n  \"components.Settings.Notifications.authPass\": \"SMTP lozinka\",\n  \"components.Settings.Notifications.agentenabled\": \"Omogući agenta\",\n  \"components.Search.searchresults\": \"Rezultati pretrage\",\n  \"components.RequestModal.selectseason\": \"Odaberi sezonu(e)\",\n  \"components.RequestModal.seasonnumber\": \"Sezona {number}\",\n  \"components.RequestModal.season\": \"Sezona\",\n  \"components.RequestModal.requestfrom\": \"Trenutno postoji zahtev na čekanju od {username}.\",\n  \"components.RequestModal.requestadmin\": \"Ovaj zahtev će odmah biti prihvaćen.\",\n  \"components.RequestModal.requestSuccess\": \"Poslat zahtev za <strong>{title}</strong> !\",\n  \"components.RequestModal.requestCancel\": \"Zahtev za <strong>{title}</strong> otkazan.\",\n  \"components.RequestModal.pendingrequest\": \"Zahtev na čekanju\",\n  \"components.RequestModal.numberofepisodes\": \"# broj epizoda\",\n  \"components.RequestModal.cancel\": \"Otkaži zahtev\",\n  \"components.RequestList.requests\": \"Zahtevi\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Sezona} other {Sezona}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Sezona} other {Sezone}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Sezona} other {Sezone}}\",\n  \"components.PersonDetails.ascharacter\": \"kao {character}\",\n  \"components.PersonDetails.appearsin\": \"Pojavljivanja\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Izdavačka kuća} other {Izdavačke kuće}}\",\n  \"components.MovieDetails.similar\": \"Slični naslovi\",\n  \"components.MovieDetails.runtime\": \"{minutes} minuta\",\n  \"components.MovieDetails.revenue\": \"Prihod\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Datum izlaska} other {Datumi izlaska}}\",\n  \"components.MovieDetails.recommendations\": \"Preporuke\",\n  \"components.MovieDetails.overviewunavailable\": \"Pregled nije dostupan.\",\n  \"components.MovieDetails.overview\": \"Pregled\",\n  \"components.MovieDetails.originallanguage\": \"Originalni jezik\",\n  \"components.MovieDetails.cast\": \"Uloge\",\n  \"components.MovieDetails.budget\": \"Budžet\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Kompletna glumačka postava\",\n  \"components.Layout.UserDropdown.signout\": \"Odjava\",\n  \"components.Layout.Sidebar.users\": \"Korisnici\",\n  \"components.Layout.Sidebar.settings\": \"Podešavanja\",\n  \"components.Layout.Sidebar.requests\": \"Zahtevi\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Pretraži filmove i serije\",\n  \"components.Discover.upcomingmovies\": \"Predstojeći filmovi\",\n  \"components.Discover.upcoming\": \"Predstojeći filmovi\",\n  \"components.Discover.trending\": \"Popularno\",\n  \"components.Discover.recentrequests\": \"Nedavni zahtevi\",\n  \"components.Discover.recentlyAdded\": \"Nedavno dodato\",\n  \"components.Discover.populartv\": \"Popularne serije\",\n  \"components.Discover.popularmovies\": \"Popularni filmovi\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.UserProfile.movierequests\": \"Zahtev za film\",\n  \"i18n.advanced\": \"Napredno\",\n  \"i18n.back\": \"Nazad\",\n  \"components.Discover.discover\": \"Pronađi novo\",\n  \"components.MovieDetails.showless\": \"Prikaži manje\",\n  \"components.Settings.SettingsLogs.logs\": \"Logovi\",\n  \"components.MovieDetails.watchtrailer\": \"Pogledaj najavu\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Notifikacije\",\n  \"components.UserList.create\": \"Kreiraj\",\n  \"components.Settings.SettingsJobsCache.process\": \"Proces\",\n  \"components.Settings.menuUsers\": \"Korisnici\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Opšte\",\n  \"i18n.requested\": \"Zahtevano\",\n  \"components.Discover.NetworkSlider.networks\": \"Mreže\",\n  \"components.Discover.StudioSlider.studios\": \"Studiji\",\n  \"i18n.failed\": \"Neuspešno\",\n  \"components.CollectionDetails.overview\": \"Pregled\",\n  \"i18n.loading\": \"Učitavanje…\",\n  \"components.UserList.creating\": \"Kreiranje…\",\n  \"components.UserList.accounttype\": \"Tip\",\n  \"i18n.tvshow\": \"Serije\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Layout.UserDropdown.settings\": \"Podešavanja\",\n  \"components.Login.password\": \"Lozinka\",\n  \"components.MovieDetails.showmore\": \"Prikaži više\",\n  \"components.MovieDetails.viewfullcrew\": \"Prikažu celu postavu\",\n  \"components.PersonDetails.crewmember\": \"Uloge\",\n  \"components.PermissionEdit.request\": \"Zahtev\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Oznake\",\n  \"components.Settings.RadarrModal.tags\": \"Oznake\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tip\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Pauza\",\n  \"components.Settings.email\": \"Email\",\n  \"components.Settings.serverLocal\": \"lokalni\",\n  \"components.Settings.serverRemote\": \"udaljeni\",\n  \"components.Settings.serverpreset\": \"Server\",\n  \"components.Settings.services\": \"Servisi\",\n  \"components.UserList.users\": \"Korisnici\",\n  \"i18n.all\": \"Sve\",\n  \"components.QuotaSelector.unlimited\": \"Neograničeno\",\n  \"components.RequestCard.deleterequest\": \"Obriši zahtev\",\n  \"components.RequestList.RequestItem.modified\": \"Modifikovano\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Keš\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.SonarrModal.tags\": \"Oznake\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.UserList.owner\": \"Vlasnik\",\n  \"components.UserList.password\": \"Lozinka\",\n  \"i18n.request\": \"Zahtev\",\n  \"i18n.requesting\": \"Zahteva se…\",\n  \"i18n.saving\": \"Čuvanje…\",\n  \"i18n.testing\": \"Testiranje…\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Trenutni\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Najnovije\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administrator\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Vlasnik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Opšte\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Dozvole\",\n  \"components.PermissionEdit.admin\": \"Administrator\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Lozinka\",\n  \"components.ResetPassword.password\": \"Lozinka\",\n  \"components.Search.search\": \"Pretraga\",\n  \"components.MovieDetails.originaltitle\": \"Originalni naslov\",\n  \"components.RequestList.RequestItem.requested\": \"Zahtevano\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Napredno\",\n  \"components.RequestModal.QuotaDisplay.season\": \"sezona\",\n  \"components.Settings.scanning\": \"Sinhronizacija u toku…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Korisnik\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Izdanja\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Poslovi\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Otklanjanje grešaka\",\n  \"components.Settings.SettingsLogs.filterError\": \"Greška\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Upozorenje\",\n  \"components.Settings.SettingsLogs.message\": \"Poruka\",\n  \"components.Settings.SettingsLogs.time\": \"Vremenska oznaka\",\n  \"components.Settings.SettingsAbout.about\": \"O nama\",\n  \"components.Settings.SettingsUsers.users\": \"Korisnici\",\n  \"components.Settings.notifications\": \"Notifikacije\",\n  \"components.Setup.setup\": \"Podesiti\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Lozinka\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Notifikacije\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Dozvole\",\n  \"i18n.close\": \"Zatvori\",\n  \"i18n.canceling\": \"Otkazivanje…\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.retry\": \"Pokušaj ponovo\",\n  \"i18n.edit\": \"Izmena\",\n  \"i18n.settings\": \"Podešavanja\",\n  \"i18n.next\": \"Sledeći\",\n  \"i18n.view\": \"Pogled\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Obriši zahtev\",\n  \"components.RequestModal.selectmovies\": \"Selektuj film(ove)\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentacija\",\n  \"i18n.experimental\": \"Eksperimentalno\",\n  \"components.PermissionEdit.autoapprove\": \"Automatsko odobrenje\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Uloga\",\n  \"components.UserProfile.unlimited\": \"Neograničeno\",\n  \"i18n.previous\": \"Prethodni\",\n  \"components.UserList.sortCreated\": \"Datum pridruživanja\",\n  \"components.Discover.upcomingtv\": \"Predstojeće serije\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Da li ste sigurni da želite da obrišete ovaj komentar?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Obriši komentar\",\n  \"components.IssueDetails.IssueComment.edit\": \"Izmeni komentar\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Morate uneti poruku\",\n  \"components.Layout.Sidebar.issues\": \"Problemi\",\n  \"components.PermissionEdit.request4k\": \"Zahtevajte 4K\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Sledeće izvršenje\",\n  \"components.Settings.Notifications.senderName\": \"Ime pošiljaoca\",\n  \"components.DownloadBlock.estimatedtime\": \"Procenjeno {time}\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Zahtevaj kao\",\n  \"i18n.retrying\": \"Ponovni pokušaj…\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Žanrovi filmova\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Žanrovi serija\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Žanrovi filmova\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Žanrovi serija\",\n  \"components.RegionSelector.regionDefault\": \"Svi regioni\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Eksterni URL\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} filmova\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} filmova\",\n  \"components.RequestList.sortAdded\": \"Najnoviji\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} filmovi\",\n  \"components.IssueDetails.comments\": \"Komentari\",\n  \"components.IssueDetails.commentplaceholder\": \"Dodajte komentar…\",\n  \"components.IssueDetails.issuetype\": \"Tip\",\n  \"components.IssueDetails.deleteissue\": \"Obriši problem\",\n  \"components.IssueDetails.episode\": \"Epizoda {episodeNumber}\",\n  \"components.IssueDetails.lastupdated\": \"Poslednja izmena\",\n  \"components.IssueDetails.nocomments\": \"Nema komentara.\",\n  \"components.IssueDetails.openin4karr\": \"Otvori u 4K {arr}\",\n  \"components.IssueDetails.openinarr\": \"Otvori u {arr}\",\n  \"components.IssueDetails.playonplex\": \"Pusti na {mediaServerName}u\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tip\",\n  \"components.IssueDetails.season\": \"Sezona {seasonNumber}\",\n  \"components.IssueList.IssueItem.opened\": \"Otvoren\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Nepoznat\",\n  \"components.IssueModal.issueOther\": \"Ostalo\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.Login.signin\": \"Prijavite se\",\n  \"components.Login.signingin\": \"Prijavljivanje…\",\n  \"components.Login.forgotpassword\": \"Zaboravili ste lozinku?\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Zahtevi\",\n  \"components.ManageSlideOver.tvshow\": \"serije\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Vidi više\",\n  \"components.RequestBlock.profilechanged\": \"Profil kvaliteta\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Automatsko odobrenje filmova\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Automatsko odobrenje serija\",\n  \"components.RequestButton.requestmore\": \"Zatraži još\",\n  \"components.RequestButton.viewrequest\": \"Pogledaj zahtev\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Root folder\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Eksterni URL\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Veličina ključa\",\n  \"components.Settings.serverpresetManualMessage\": \"Ručna konfiguracija\",\n  \"components.UserList.sortRequests\": \"Broj zahteva\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Lokalni korisnik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Standardna podešavanja\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex korisnik\",\n  \"components.PermissionEdit.autoapprove4k\": \"Automatsko odobrenje 4K\",\n  \"components.IssueModal.issueSubtitles\": \"Titl\",\n  \"components.PermissionEdit.managerequests\": \"Upravljajte zahtevima\",\n  \"components.RequestBlock.rootfolder\": \"Root folder\",\n  \"components.RequestButton.declinerequest\": \"Odbijte zahtev\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Odredišni server\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Zahtevano\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Pristupni token\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Ime posla\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Jezik profila\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.mediaTypeSeries\": \"serije\",\n  \"components.Settings.serverSecure\": \"bezbedno\",\n  \"components.UserList.bulkedit\": \"Grupno uređivanje\",\n  \"components.UserList.localuser\": \"Lokalni korisnik\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Izmena podešavanja\",\n  \"i18n.status\": \"Status\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Izmeni opis\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Status\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} je započeo.\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Pogledaj profil\",\n  \"components.IssueDetails.allepisodes\": \"Sve epizode\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Izbriši problem\",\n  \"components.IssueDetails.IssueDescription.description\": \"Opis\",\n  \"components.IssueDetails.allseasons\": \"Sve sezone\",\n  \"components.IssueDetails.unknownissuetype\": \"Nepoznat\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Omogući skeniranje\",\n  \"components.ResetPassword.confirmpassword\": \"Potvrdi lozinku\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Ime keša\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Dodaci\",\n  \"components.RequestModal.autoapproval\": \"Automatsko odobrenje\",\n  \"components.Settings.Notifications.encryptionNone\": \"Nijedan\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Pokreni sada\",\n  \"components.IssueDetails.play4konplex\": \"Pusti u 4K na {mediaServerName}u\",\n  \"components.IssueList.issues\": \"Problemi\",\n  \"components.IssueModal.issueAudio\": \"Audio\",\n  \"components.PermissionEdit.viewrequests\": \"Pogledaj zahteve\",\n  \"components.RequestButton.approverequest\": \"Odobri zahtev\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Jezik profila\",\n  \"components.Settings.SettingsAbout.timezone\": \"Vremenska zona\",\n  \"components.Settings.serverpresetRefreshing\": \"Preuzimanje servera…\",\n  \"components.Settings.RadarrModal.announced\": \"Najavljeno\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Omogući skeniranje\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Pogodaka\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Frekvencija\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Prikaži dnevnik promena\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Ukupno ključeva\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Otkaži posao\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} je otkazan.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID korisnika\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Podešavanje notifikacija\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Potvrdi lozinku\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Trenutna lozinka\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nova lozinka\",\n  \"components.UserProfile.recentrequests\": \"Nedavni zahtevi\",\n  \"i18n.open\": \"Otvori\",\n  \"i18n.resolved\": \"Rešeno\",\n  \"components.RequestBlock.server\": \"Odredišni server\",\n  \"components.PermissionEdit.advancedrequest\": \"Napredni zahtevi\",\n  \"components.IssueDetails.leavecomment\": \"Komentar\",\n  \"components.PermissionEdit.users\": \"Upravljajte korisnica\",\n  \"components.TvDetails.watchtrailer\": \"Pogledaj najavu\",\n  \"components.CollectionDetails.requestcollection\": \"Zahtevaj kolekciju\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Omogući agenta\",\n  \"components.IssueDetails.issuepagetitle\": \"Problem\",\n  \"components.Login.email\": \"Email adresa\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Rezime\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Zahtev je odobren\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook adresa\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Napredno\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Mediji\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON zadržaj\",\n  \"components.Settings.SettingsLogs.label\": \"Labela\",\n  \"components.Settings.SettingsLogs.level\": \"Ozbiljnost\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Dnevnik promena\",\n  \"i18n.import\": \"Uvoz\",\n  \"i18n.importing\": \"Uvoz…\",\n  \"components.Settings.SettingsJobsCache.command\": \"Komanda\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Zahtev dostupan\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Omogući agenta\",\n  \"components.Settings.Notifications.chatId\": \"Chat-ID\",\n  \"components.ManageSlideOver.downloadstatus\": \"Preuzimanja\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Zaglavlje autorizacije\",\n  \"i18n.test\": \"Test\",\n  \"components.RequestList.sortModified\": \"Poslednja izmena\",\n  \"components.Settings.RadarrModal.released\": \"U bioskopima od\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Email\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Gospođica\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook adresa\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Omogući agenta\",\n  \"components.RegionSelector.regionServerDefault\": \"Podrazumevano ({region})\",\n  \"components.UserList.email\": \"Email adresa\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{network} film\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} serija\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Obriši keš\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Otkrijte jezik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Otkrijte region\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Zahtev odbijen\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Podrazumevano)\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Profil kvaliteta\",\n  \"components.ResetPassword.email\": \"Email adresa\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Omogući agenta\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Download sinhronizacija\",\n  \"components.Settings.Notifications.sendSilently\": \"Pošalji tiho\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Tip naloga\",\n  \"components.UserProfile.requestsperdays\": \"{limit} preostalo\",\n  \"components.PersonDetails.birthdate\": \"Rođen {birthdate}\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Podrazumevane dozvole\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Serije na jeziku {language}\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Serije\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.alreadyrequested\": \"Već je traženo\",\n  \"components.ResetPassword.passwordreset\": \"Resetovanje lozinke\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Korisnička podešavanja\",\n  \"pages.serviceunavailable\": \"Servis nije dostupan\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Nepoznat posao\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr skeniranje\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr skeniranje\",\n  \"components.Settings.SettingsLogs.extraData\": \"Dodatni podaci\",\n  \"components.Settings.enablessl\": \"Koristi SSL\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minuta\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chat-ID\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.usersettings\": \"Korisnička podešavanja\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Pridružio se {joindate}\",\n  \"components.Settings.Notifications.botUsername\": \"Bot korisničko ime\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP lozinka\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Detalji dnevnika\",\n  \"components.Settings.scan\": \"Sinhronizacija biblioteka\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Pošalji tiho\",\n  \"i18n.notrequested\": \"Nije zahtevano\",\n  \"components.Settings.Notifications.validationEmail\": \"Morate uneti validnu email adresu\",\n  \"components.UserList.usercreatedfailedexisting\": \"Email adresa je već iskorišćena od strane drugog korisnika.\",\n  \"components.CollectionDetails.requestcollection4k\": \"Zahtevaj kolekciju u 4K\",\n  \"components.Login.signinheader\": \"Uloguj se za nastavak\",\n  \"components.Login.signinwithoverseerr\": \"Iskoristi nalog od {applicationTitle}\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Modifikuj posao\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Posao uspešno izmenjen!\",\n  \"i18n.save\": \"Sačuvaj izmene\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Automatski odobri 4K filmove\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Dozvoli automatsko odobravanje zahteva za 4K filmove.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Automatski odobri 4K serije\",\n  \"components.ResetPassword.resetpassword\": \"Resetuj svoju lozinku\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Šaljem Gotify probno obaveštenje…\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Dodaj novi 4K Radarr server\",\n  \"components.ManageSlideOver.alltime\": \"Sve vreme\",\n  \"components.Settings.validationUrl\": \"Morate uneti validnu URL adresu\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Prikaži jezik\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Prikaži ime\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Morate potvrditi novu lozinku\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Došlo je do greške prilikom čuvanja posla.\",\n  \"components.Login.signinwithplex\": \"Koristi tvoj Plex nalog\",\n  \"components.Login.validationemailrequired\": \"Moraš uneti validnu email adresu\",\n  \"components.Login.validationpasswordrequired\": \"Moraš uneti lozinku\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Neuspelo povezivanje na Plex.\",\n  \"components.RequestBlock.languageprofile\": \"Jezički profil\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Lozinka uspešno resetovana!\",\n  \"components.ResetPassword.validationemailrequired\": \"Moraš uneti validnu email adresu\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Lozinka je previše kratka; mora imati najmanje 8 znakova\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Moraš uneti lozinku\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Šaljem Pushbullet probno obaveštenje…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet probno obaveštenje poslato!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Šaljem Pushover probno obaveštenje…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Šaljem Slack probno obaveštenje…\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Omogući agenta\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Morate uneti validnu URL adresu\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Uvek koristi STARTTLS\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Izmeni 4K Radarr server\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Zastarelo\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Poslovi i keš\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Podešavanja korisnika uspešno sačuvana!\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Jezički profil za anime\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime oznake\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Omogući automatsku pretragu\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Oznake se učitavaju…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Učitavanje jezičkih profila…\",\n  \"components.Settings.SonarrModal.selecttags\": \"Izaberi oznake\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Izaberi jezički profil\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Neuspešno povezivanje na Sonarr.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Povezivanje na Sonarr uspešno!\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Moraš uneti validnu URL adresu\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Moraš izabrati jezički profil\",\n  \"components.Settings.externalUrl\": \"Spoljni URL\",\n  \"components.Settings.tautulliSettings\": \"Tautulli podešavanja\",\n  \"components.Settings.tautulliApiKey\": \"API ključ\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Nešto nije u redu prilikom čuvanja Tautulli podešavanja.\",\n  \"components.Settings.tautulliSettingsDescription\": \"Opciono konfiguriši podešavanja za tvoj Tautulli server. Seerr će učitavati istoriju gledanja Plex sadržaja iz Tautulli-ja.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Povezivanje sa Plex-om uspešno!\",\n  \"components.Settings.toastPlexRefresh\": \"Učitavam listu servera sa Plex-a…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Neuspešno učitavanje liste servara sa Plexa.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Lista Plex servera uspešno preuzeta!\",\n  \"components.TvDetails.nextAirDate\": \"Sledeći datum prikazivanja\",\n  \"components.UserList.nouserstoimport\": \"Nema Plex korisnika za unos.\",\n  \"components.UserList.createlocaluser\": \"Kreiraj lokalnog korisnika\",\n  \"components.UserList.autogeneratepassword\": \"Automatski generiši šifru\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Podašavanja uspešno sačuvana!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Enkriptuj email poruke koristeći <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Pošalji notifikacije bez zvuka\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Morate uneti trenutnu lozinku\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Morate uneti novu lozinku\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Lozinka je previše kratka; mora imati najmanje 8 znakova\",\n  \"components.UserProfile.totalrequests\": \"Ukupan broj zahteva\",\n  \"i18n.noresults\": \"Nema rezultata.\",\n  \"i18n.request4k\": \"Zahtevaj u 4K\",\n  \"i18n.resultsperpage\": \"Prikaži {pageSize} rezultata po strani\",\n  \"i18n.showingresults\": \"Prikazujem <strong>{from}</strong> do <strong>{to}</strong> od <strong>{total}</strong> rezultata\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Morate uneti validnu URL adresu\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Pogledaj na GitHub\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Izmeni 4K Sonarr server\",\n  \"components.UserList.validationEmail\": \"Morate uneti validnu email adresu\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Lozinka uspešno sačuvana!\",\n  \"components.Settings.toastPlexConnecting\": \"Pokušavam povezivanje na Plex…\",\n  \"pages.somethingwentwrong\": \"Nešto je pogrešno\",\n  \"pages.internalservererror\": \"Interna greška servera\",\n  \"pages.pagenotfound\": \"Stranica nije pronađena\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Obeleži kao dostupno u 4K\",\n  \"components.Login.loginerror\": \"Dogodila se greška prilikom prijave.\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Dodaj novi 4K Sonarr server\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Dozvoli automatsko odobravanje zahteva za 4K serije.\",\n  \"components.ResetPassword.gobacklogin\": \"Vrati se na stranu za prijavu\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Svaki {jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Najsvežiji\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Morate da navedete važeći JSON korisni teret\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Morate da navedete važeći ID za ćaskanje\",\n  \"components.StatusBadge.playonplex\": \"Igrajte na {mediaServerName}-u\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Morate da obezbedite pristupni token\",\n  \"components.UserList.userssaved\": \"Korisničke dozvole su uspešno sačuvane!\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Филмови\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Претражи жанрове…\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Креирај нови клизач и сачувана подешавања прилагођавања открића.\",\n  \"components.Discover.CreateSlider.editfail\": \"Неуспешно измењивање клизача.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Измени клизач\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Наведите TMDB ID мреже\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Измењен клизач и сачувана подешавања прилагођавања открића.\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Наведите упит за претрагу\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Наведите ID кључне речи TMDB\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Наведите TMDB Студио ID\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Морате да наведете вредност података.\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Претражи студије…\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Филмови\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Претражи кључне речи…\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Датум изласка опадајући\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Наведите ID TMDB жанра\",\n  \"components.Discover.CreateSlider.addSlider\": \"Додај клизач\",\n  \"components.AirDateBadge.airedrelative\": \"Емитовано {relativeTime}\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Направи прилагођени клизач\",\n  \"components.Discover.CreateSlider.addfail\": \"Неуспешно креирање новог клизача.\",\n  \"components.AirDateBadge.airsrelative\": \"Емитује се {relativeTime}\",\n  \"components.Discover.CreateSlider.needresults\": \"Морате имати најмање 1 резултат.\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code> монтирање фолдера није правилно конфигурисано. Сви подаци ће бити избрисани када се контејнер заустави или рестартује.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Нема резултата.\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Име клизача\",\n  \"components.Discover.CreateSlider.starttyping\": \"Почните да куцате за претрагу.\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Наслов (Z-A) опадајуће\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Морати дати наслов.\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Наслов (А-З) растуће\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Active Filter} остали {# Active Filters}}\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Популарност растућа\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Популарност опадајућа\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Датум изласка растући\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"\",\n  \"components.Discover.DiscoverTv.activefilters\": \"\",\n  \"components.Discover.DiscoverTv.discovertv\": \"\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"\",\n  \"components.Discover.FilterSlideover.activefilters\": \"\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.Discover.FilterSlideover.filters\": \"\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"\",\n  \"components.Discover.FilterSlideover.from\": \"\",\n  \"components.Discover.FilterSlideover.genres\": \"\",\n  \"components.Discover.FilterSlideover.keywords\": \"\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"\",\n  \"components.Discover.FilterSlideover.ratingText\": \"\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"\",\n  \"components.Discover.FilterSlideover.runtime\": \"\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"\",\n  \"components.Discover.FilterSlideover.studio\": \"\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"\",\n  \"components.Discover.FilterSlideover.to\": \"\",\n  \"components.Discover.FilterSlideover.voteCount\": \"\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"\",\n  \"components.Discover.createnewslider\": \"\",\n  \"components.Discover.customizediscover\": \"\",\n  \"components.Discover.emptywatchlist\": \"\",\n  \"components.Discover.moviegenres\": \"\",\n  \"components.Discover.networks\": \"\",\n  \"components.Discover.plexwatchlist\": \"\",\n  \"components.Discover.resetfailed\": \"\",\n  \"components.Discover.resetsuccess\": \"\",\n  \"components.Discover.resettodefault\": \"\",\n  \"components.Discover.resetwarning\": \"\",\n  \"components.Discover.stopediting\": \"\",\n  \"components.Discover.studios\": \"\",\n  \"components.Discover.tmdbmoviegenre\": \"\",\n  \"components.Discover.tmdbmoviekeyword\": \"\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"\",\n  \"components.Discover.tmdbnetwork\": \"\",\n  \"components.Discover.tmdbsearch\": \"\",\n  \"components.Discover.tmdbstudio\": \"\",\n  \"components.Discover.tmdbtvgenre\": \"\",\n  \"components.Discover.tmdbtvkeyword\": \"\",\n  \"components.Discover.tmdbtvstreamingservices\": \"\",\n  \"components.Discover.tvgenres\": \"\",\n  \"components.Discover.updatefailed\": \"\",\n  \"components.Discover.updatesuccess\": \"\",\n  \"components.DownloadBlock.formattedTitle\": \"\",\n  \"components.IssueDetails.IssueComment.postedby\": \"\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"\",\n  \"components.IssueDetails.closeissue\": \"\",\n  \"components.IssueDetails.closeissueandcomment\": \"\",\n  \"components.IssueDetails.deleteissueconfirm\": \"\",\n  \"components.IssueDetails.openedby\": \"\",\n  \"components.IssueDetails.problemepisode\": \"\",\n  \"components.IssueDetails.problemseason\": \"\",\n  \"components.IssueDetails.reopenissue\": \"\",\n  \"components.IssueDetails.reopenissueandcomment\": \"\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"\",\n  \"components.IssueDetails.toastissuedeleted\": \"\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"\",\n  \"components.IssueDetails.toaststatusupdated\": \"\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.IssueList.IssueItem.episodes\": \"\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"\",\n  \"components.IssueList.IssueItem.problemepisode\": \"\",\n  \"components.IssueList.IssueItem.seasons\": \"\",\n  \"components.IssueList.IssueItem.viewissue\": \"\",\n  \"components.IssueList.showallissues\": \"\",\n  \"components.IssueList.sortAdded\": \"\",\n  \"components.IssueList.sortModified\": \"\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"\",\n  \"components.IssueModal.CreateIssueModal.season\": \"\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"\",\n  \"components.LanguageSelector.languageServerDefault\": \"\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"\",\n  \"components.Layout.Sidebar.browsemovies\": \"\",\n  \"components.Layout.Sidebar.browsetv\": \"\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"\",\n  \"components.Layout.UserDropdown.requests\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"\",\n  \"components.Layout.UserWarnings.emailRequired\": \"\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"\",\n  \"components.Layout.VersionStatus.outofdate\": \"\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"\",\n  \"components.Layout.VersionStatus.streamstable\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.credentialerror\": \"\",\n  \"components.Login.description\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"\",\n  \"components.ManageSlideOver.manageModalIssues\": \"\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.manageModalTitle\": \"\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"\",\n  \"components.ManageSlideOver.markavailable\": \"\",\n  \"components.ManageSlideOver.openarr\": \"\",\n  \"components.ManageSlideOver.openarr4k\": \"\",\n  \"components.ManageSlideOver.opentautulli\": \"\",\n  \"components.ManageSlideOver.pastdays\": \"\",\n  \"components.ManageSlideOver.playedby\": \"\",\n  \"components.ManageSlideOver.plays\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.digitalrelease\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.imdbuserscore\": \"\",\n  \"components.MovieDetails.managemovie\": \"\",\n  \"components.MovieDetails.mark4kavailable\": \"\",\n  \"components.MovieDetails.markavailable\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.physicalrelease\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.productioncountries\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.reportissue\": \"\",\n  \"components.MovieDetails.rtaudiencescore\": \"\",\n  \"components.MovieDetails.rtcriticsscore\": \"\",\n  \"components.MovieDetails.streamingproviders\": \"\",\n  \"components.MovieDetails.theatricalrelease\": \"\",\n  \"components.MovieDetails.tmdbuserscore\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.issuecomment\": \"\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.issuecreated\": \"\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"\",\n  \"components.NotificationTypeSelector.issuereopened\": \"\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.issueresolved\": \"\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediafailed\": \"\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"\",\n  \"components.NotificationTypeSelector.mediarequested\": \"\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"\",\n  \"components.PermissionEdit.adminDescription\": \"\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"\",\n  \"components.PermissionEdit.autoapproveDescription\": \"\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"\",\n  \"components.PermissionEdit.autorequest\": \"\",\n  \"components.PermissionEdit.autorequestDescription\": \"\",\n  \"components.PermissionEdit.autorequestMovies\": \"\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"\",\n  \"components.PermissionEdit.autorequestSeries\": \"\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"\",\n  \"components.PermissionEdit.createissues\": \"\",\n  \"components.PermissionEdit.createissuesDescription\": \"\",\n  \"components.PermissionEdit.manageissues\": \"\",\n  \"components.PermissionEdit.manageissuesDescription\": \"\",\n  \"components.PermissionEdit.managerequestsDescription\": \"\",\n  \"components.PermissionEdit.request4kDescription\": \"\",\n  \"components.PermissionEdit.request4kMovies\": \"\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"\",\n  \"components.PermissionEdit.request4kTv\": \"\",\n  \"components.PermissionEdit.request4kTvDescription\": \"\",\n  \"components.PermissionEdit.requestDescription\": \"\",\n  \"components.PermissionEdit.requestMovies\": \"\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"\",\n  \"components.PermissionEdit.requestTv\": \"\",\n  \"components.PermissionEdit.requestTvDescription\": \"\",\n  \"components.PermissionEdit.usersDescription\": \"\",\n  \"components.PermissionEdit.viewissues\": \"\",\n  \"components.PermissionEdit.viewissuesDescription\": \"\",\n  \"components.PermissionEdit.viewrecent\": \"\",\n  \"components.PermissionEdit.viewrecentDescription\": \"\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"\",\n  \"components.PermissionEdit.viewwatchlists\": \"\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"\",\n  \"components.PersonDetails.alsoknownas\": \"\",\n  \"components.PersonDetails.lifespan\": \"\",\n  \"components.QuotaSelector.days\": \"\",\n  \"components.QuotaSelector.movieRequests\": \"\",\n  \"components.QuotaSelector.movies\": \"\",\n  \"components.QuotaSelector.seasons\": \"\",\n  \"components.QuotaSelector.tvRequests\": \"\",\n  \"components.RequestBlock.approve\": \"\",\n  \"components.RequestBlock.decline\": \"\",\n  \"components.RequestBlock.delete\": \"\",\n  \"components.RequestBlock.edit\": \"\",\n  \"components.RequestBlock.lastmodifiedby\": \"\",\n  \"components.RequestBlock.requestdate\": \"\",\n  \"components.RequestBlock.requestedby\": \"\",\n  \"components.RequestBlock.requestoverrides\": \"\",\n  \"components.RequestButton.approve4krequests\": \"\",\n  \"components.RequestButton.approverequest4k\": \"\",\n  \"components.RequestButton.approverequests\": \"\",\n  \"components.RequestButton.decline4krequests\": \"\",\n  \"components.RequestButton.declinerequest4k\": \"\",\n  \"components.RequestButton.declinerequests\": \"\",\n  \"components.RequestButton.requestmore4k\": \"\",\n  \"components.RequestButton.viewrequest4k\": \"\",\n  \"components.RequestCard.approverequest\": \"\",\n  \"components.RequestCard.cancelrequest\": \"\",\n  \"components.RequestCard.declinerequest\": \"\",\n  \"components.RequestCard.editrequest\": \"\",\n  \"components.RequestCard.failedretry\": \"\",\n  \"components.RequestCard.mediaerror\": \"\",\n  \"components.RequestCard.tmdbid\": \"\",\n  \"components.RequestCard.tvdbid\": \"\",\n  \"components.RequestCard.unknowntitle\": \"\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"\",\n  \"components.RequestList.RequestItem.editrequest\": \"\",\n  \"components.RequestList.RequestItem.failedretry\": \"\",\n  \"components.RequestList.RequestItem.mediaerror\": \"\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.RequestItem.tmdbid\": \"\",\n  \"components.RequestList.RequestItem.tvdbid\": \"\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"\",\n  \"components.RequestList.showallrequests\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"\",\n  \"components.RequestModal.approve\": \"\",\n  \"components.RequestModal.edit\": \"\",\n  \"components.RequestModal.errorediting\": \"\",\n  \"components.RequestModal.pending4krequest\": \"\",\n  \"components.RequestModal.pendingapproval\": \"\",\n  \"components.RequestModal.requestApproved\": \"\",\n  \"components.RequestModal.requestcancelled\": \"\",\n  \"components.RequestModal.requestcollection4ktitle\": \"\",\n  \"components.RequestModal.requestcollectiontitle\": \"\",\n  \"components.RequestModal.requestedited\": \"\",\n  \"components.RequestModal.requesterror\": \"\",\n  \"components.RequestModal.requestmovie4ktitle\": \"\",\n  \"components.RequestModal.requestmovies\": \"\",\n  \"components.RequestModal.requestmovies4k\": \"\",\n  \"components.RequestModal.requestmovietitle\": \"\",\n  \"components.RequestModal.requestseasons4k\": \"\",\n  \"components.RequestModal.requestseries4ktitle\": \"\",\n  \"components.RequestModal.requestseriestitle\": \"\",\n  \"components.ResetPassword.emailresetlink\": \"\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"\",\n  \"components.ResetPassword.validationpasswordmatch\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.nooptions\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Selector.searchGenres\": \"\",\n  \"components.Selector.searchKeywords\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchStudios\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Selector.showless\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.Settings.Notifications.allowselfsigned\": \"\",\n  \"components.Settings.Notifications.botAPI\": \"\",\n  \"components.Settings.Notifications.botApiTip\": \"\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"\",\n  \"components.Settings.Notifications.botUsernameTip\": \"\",\n  \"components.Settings.Notifications.chatIdTip\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.enableMentions\": \"\",\n  \"components.Settings.Notifications.encryption\": \"\",\n  \"components.Settings.Notifications.encryptionDefault\": \"\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"\",\n  \"components.Settings.Notifications.encryptionTip\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"\",\n  \"components.Settings.Notifications.validationTypes\": \"\",\n  \"components.Settings.Notifications.validationUrl\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.RadarrModal.default4kserver\": \"\",\n  \"components.Settings.RadarrModal.enableSearch\": \"\",\n  \"components.Settings.RadarrModal.inCinemas\": \"\",\n  \"components.Settings.RadarrModal.loadingTags\": \"\",\n  \"components.Settings.RadarrModal.notagoptions\": \"\",\n  \"components.Settings.RadarrModal.selecttags\": \"\",\n  \"components.Settings.RadarrModal.tagRequests\": \"\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"\",\n  \"components.Settings.SettingsLogs.showall\": \"\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"\",\n  \"components.Settings.SettingsMain.apikey\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"\",\n  \"components.Settings.SettingsMain.applicationurl\": \"\",\n  \"components.Settings.SettingsMain.cacheImages\": \"\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.general\": \"\",\n  \"components.Settings.SettingsMain.generalsettings\": \"\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.locale\": \"\",\n  \"components.Settings.SettingsMain.originallanguage\": \"\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"\",\n  \"components.Settings.SettingsUsers.localLogin\": \"\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"\",\n  \"components.Settings.SonarrModal.default4kserver\": \"\",\n  \"components.Settings.SonarrModal.notagoptions\": \"\",\n  \"components.Settings.SonarrModal.seriesType\": \"\",\n  \"components.Settings.SonarrModal.tagRequests\": \"\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.advancedTooltip\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.deleteServer\": \"\",\n  \"components.Settings.experimentalTooltip\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noDefault4kServer\": \"\",\n  \"components.Settings.noDefaultNon4kServer\": \"\",\n  \"components.Settings.noDefaultServer\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.restartrequiredTooltip\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.serverpresetLoad\": \"\",\n  \"components.Settings.serviceSettingsDescription\": \"\",\n  \"components.Settings.settingUpPlexDescription\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.urlBase\": \"\",\n  \"components.Settings.validationApiKey\": \"\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Settings.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.webAppUrl\": \"\",\n  \"components.Settings.webAppUrlTip\": \"\",\n  \"components.Settings.webpush\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.managemedia\": \"\",\n  \"components.StatusBadge.openinarr\": \"\",\n  \"components.StatusBadge.seasonepisodenumber\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.StatusChecker.appUpdated\": \"\",\n  \"components.StatusChecker.appUpdatedDescription\": \"\",\n  \"components.StatusChecker.reloadApp\": \"\",\n  \"components.StatusChecker.restartRequired\": \"\",\n  \"components.StatusChecker.restartRequiredDescription\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.cleardata\": \"\",\n  \"components.TitleCard.mediaerror\": \"\",\n  \"components.TitleCard.tmdbid\": \"\",\n  \"components.TitleCard.tvdbid\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.Season.noepisodes\": \"\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.episodeCount\": \"\",\n  \"components.TvDetails.episodeRuntime\": \"\",\n  \"components.TvDetails.firstAirDate\": \"\",\n  \"components.TvDetails.manageseries\": \"\",\n  \"components.TvDetails.originaltitle\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.productioncountries\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.reportissue\": \"\",\n  \"components.TvDetails.rtaudiencescore\": \"\",\n  \"components.TvDetails.rtcriticsscore\": \"\",\n  \"components.TvDetails.seasonnumber\": \"\",\n  \"components.TvDetails.seasons\": \"\",\n  \"components.TvDetails.seasonstitle\": \"\",\n  \"components.TvDetails.status4k\": \"\",\n  \"components.TvDetails.streamingproviders\": \"\",\n  \"components.TvDetails.tmdbuserscore\": \"\",\n  \"components.TvDetails.viewfullcrew\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.autogeneratepasswordTip\": \"\",\n  \"components.UserList.edituser\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importedfromplex\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.importfromplex\": \"\",\n  \"components.UserList.importfromplexerror\": \"\",\n  \"components.UserList.localLoginDisabled\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.newplexsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.passwordinfodescription\": \"\",\n  \"components.UserList.sortDisplayName\": \"\",\n  \"components.UserList.usercreatedfailed\": \"\",\n  \"components.UserList.usercreatedsuccess\": \"\",\n  \"components.UserList.userfail\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserList.validationpasswordminchars\": \"\",\n  \"components.UserProfile.ProfileHeader.userid\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"\",\n  \"components.UserProfile.emptywatchlist\": \"\",\n  \"components.UserProfile.limit\": \"\",\n  \"components.UserProfile.localWatchlist\": \"\",\n  \"components.UserProfile.pastdays\": \"\",\n  \"components.UserProfile.plexwatchlist\": \"\",\n  \"components.UserProfile.recentlywatched\": \"\",\n  \"components.UserProfile.seriesrequest\": \"\",\n  \"i18n.areyousure\": \"\",\n  \"i18n.collection\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Selector.showmore\": \"\",\n  \"i18n.restartRequired\": \"\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Selector.starttyping\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"\",\n  \"i18n.specials\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/sv.json",
    "content": "{\n  \"components.Setup.finishing\": \"Slutför…\",\n  \"components.Setup.finish\": \"Slutför konfiguration\",\n  \"components.Setup.continue\": \"Fortsätt\",\n  \"components.Setup.configureservices\": \"Konfigurera tjänster\",\n  \"components.Settings.validationPortRequired\": \"Du måste ange ett giltigt portnummer\",\n  \"components.Settings.validationHostnameRequired\": \"Du måste ange ett giltigt värdnamn eller en IP-adress\",\n  \"components.Settings.startscan\": \"Starta skanning\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.sonarrsettings\": \"Sonarr-inställningar\",\n  \"components.Settings.radarrsettings\": \"Radarr-inställningar\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.plexsettingsDescription\": \"Konfigurera inställningarna för din Plex-server. Seerr skannar din Plex-server för att avgöra tillgängligt innehåll.\",\n  \"components.Settings.plexsettings\": \"Plex-inställningar\",\n  \"components.Settings.plexlibrariesDescription\": \"De bibliotek som Seerr skannar efter titlar. Ställ in och spara dina Plex-anslutningsinställningar, och klicka sedan på knappen nedan om inga bibliotek visas.\",\n  \"components.Settings.plexlibraries\": \"Plex-bibliotek\",\n  \"components.Settings.notrunning\": \"Körs inte\",\n  \"components.Settings.notificationsettings\": \"Meddelandeinställningar\",\n  \"components.Settings.menuServices\": \"Tjänster\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"Meddelanden\",\n  \"components.Settings.menuLogs\": \"Loggar\",\n  \"components.Settings.menuJobs\": \"Jobb och cache\",\n  \"components.Settings.menuGeneralSettings\": \"Allmänt\",\n  \"components.Settings.menuAbout\": \"Om\",\n  \"components.Settings.manualscanDescription\": \"Normalt kommer detta endast att köras en gång var 24:e timme. Seerr kommer att kontrollera nyligen tillagda filmer på din Plex-server mer intensivt. Om det är första gången du konfigurerar Plex rekommenderas en engångs, fullständig manuell biblioteksskanning!\",\n  \"components.Settings.manualscan\": \"Manuell biblioteksskanning\",\n  \"components.Settings.librariesRemaining\": \"Återstående bibliotek: {count}\",\n  \"components.Settings.hostname\": \"Värdnamn eller IP-adress\",\n  \"components.Settings.deleteserverconfirm\": \"Är du säker på att du vill radera denna instans?\",\n  \"components.Settings.default4k\": \"Standard 4K\",\n  \"components.Settings.default\": \"Standard\",\n  \"components.Settings.currentlibrary\": \"Nuvarande bibliotek: {name}\",\n  \"components.Settings.cancelscan\": \"Avbryt skanning\",\n  \"components.Settings.addsonarr\": \"Lägg till Sonarr-instans\",\n  \"components.Settings.address\": \"Adress\",\n  \"components.Settings.addradarr\": \"Lägg till Radarr-instans\",\n  \"components.Settings.activeProfile\": \"Aktiv profil\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Du måste ange en rotmapp\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Du måste ange en kvalitetsprofil\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Du måste ange ett giltigt portnummer\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Du måste ange ett instansnamn\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Du måste ange ett giltigt värdnamn eller en IP-adress\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Du måste ange en API-nyckel\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Testa anslutningen för att ladda in rotmappar\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Testa anslutningen för att ladda in kvalitetsprofiler\",\n  \"components.Settings.SonarrModal.ssl\": \"Använd SSL\",\n  \"components.Settings.SonarrModal.servername\": \"Instansnamn\",\n  \"components.Settings.SonarrModal.server4k\": \"4K-instans\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Välj rotmapp\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Välj kvalitetsprofil\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Säsongsmappar\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Rotmapp\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Kvalitetsprofiler\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Laddar rotmappar…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Laddar kvalitetsprofiler…\",\n  \"components.Settings.SonarrModal.hostname\": \"Värdnamn eller IP-adress\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Ändra Sonarr-instans\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Standard-instans\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Lägg till ny Sonarr-instans\",\n  \"components.Settings.SonarrModal.baseUrl\": \"URL-bas\",\n  \"components.Settings.SonarrModal.apiKey\": \"API-nyckel\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime-rotmapp\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime-kvalitetsprofil\",\n  \"components.Settings.SonarrModal.add\": \"Lägg till instans\",\n  \"components.Settings.SettingsAbout.version\": \"Version\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Totalt antal förfrågningar\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Totalt antal mediaobjekt\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub-diskussioner\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Få support\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Du måste ange en rotmapp\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Du måste välja en kvalitetsprofil\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Du måste ange ett giltigt portnummer\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Du måste ange ett instansnamn\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Du måste välja lägsta tillgänglighet\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Du måste ange ett giltigt värdnamn eller en IP-adress\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Du måste ange en API-nyckel\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Anslutningen till Radarr lyckades!\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Kunde inte ansluta till Radarr.\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Testa anslutningen för att ladda in rotmappar\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Testa anslutningen för att ladda in kvalitetsprofiler\",\n  \"components.Settings.RadarrModal.ssl\": \"Använd SSL\",\n  \"components.Settings.RadarrModal.servername\": \"Instansnamn\",\n  \"components.Settings.RadarrModal.server4k\": \"4K-instans\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Välj rotmapp\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Välj kvalitetsprofil\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Ange lägsta tillgänglighet\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Rotmapp\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Lägsta tillgänglighet\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Laddar rotmappar…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Laddar kvalitetsprofiler…\",\n  \"components.Settings.RadarrModal.hostname\": \"Värdnamn eller IP-adress\",\n  \"components.Settings.RadarrModal.editradarr\": \"Ändra Radarr-instans\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Standard-instans\",\n  \"components.Settings.RadarrModal.createradarr\": \"Lägg till ny Radarr-instans\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Bas-URL\",\n  \"components.Settings.RadarrModal.apiKey\": \"API-nyckel\",\n  \"components.Settings.RadarrModal.add\": \"Lägg till instans\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Du måste ange ett giltigt portnummer\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Du måste ange ett giltigt värdnamn eller en IP-adress\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP-port\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP-värd\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"E-postmeddelandeinställningar har sparats!\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discords meddelandeinställningar kunde inte sparas.\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"E-postmeddelandeinställningar kunde inte sparas.\",\n  \"components.Settings.Notifications.emailsender\": \"Avsändaradress\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discords meddelandeinställningar har sparats!\",\n  \"components.Settings.Notifications.authUser\": \"SMTP-användarnamn\",\n  \"components.Settings.Notifications.authPass\": \"SMTP-lösenord\",\n  \"components.Settings.Notifications.agentenabled\": \"Aktivera agent\",\n  \"components.Search.searchresults\": \"Sökresultat\",\n  \"components.RequestModal.selectseason\": \"Välj säsong(er)\",\n  \"components.RequestModal.seasonnumber\": \"Säsong {number}\",\n  \"components.RequestModal.season\": \"Säsong\",\n  \"components.RequestModal.requestfrom\": \"Förfrågan från {username} väntar på godkännande.\",\n  \"components.RequestModal.requestadmin\": \"Denna förfrågan kommer att godkännas automatiskt.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> har begärts!\",\n  \"components.RequestModal.requestCancel\": \"Förfrågan för <strong>{title}</strong> avbruten.\",\n  \"components.RequestModal.pendingrequest\": \"Väntande förfrågan\",\n  \"components.RequestModal.numberofepisodes\": \"Antal avsnitt\",\n  \"components.RequestModal.cancel\": \"Avbryt förfrågan\",\n  \"components.RequestList.requests\": \"Förfrågningar\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {säsong} other {säsonger}}\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {säsong} other {säsonger}}\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {säsong} other {säsonger}}\",\n  \"components.PersonDetails.ascharacter\": \"som {character}\",\n  \"components.PersonDetails.appearsin\": \"Kan ses i\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Studio} other {Studior}}\",\n  \"components.MovieDetails.similar\": \"Liknande titlar\",\n  \"components.MovieDetails.runtime\": \"{minutes} minuter\",\n  \"components.MovieDetails.revenue\": \"Inkomster\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Utgivningsdatum} other {Utgivningsdatum}}\",\n  \"components.MovieDetails.recommendations\": \"Rekommendationer\",\n  \"components.MovieDetails.overview\": \"Översikt\",\n  \"components.MovieDetails.overviewunavailable\": \"Ingen översikt tillgänglig.\",\n  \"components.MovieDetails.originallanguage\": \"Originalspråk\",\n  \"components.MovieDetails.cast\": \"Rollista\",\n  \"components.MovieDetails.budget\": \"Budget\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Hela rollistan\",\n  \"components.Layout.UserDropdown.signout\": \"Logga ut\",\n  \"components.Layout.Sidebar.users\": \"Användare\",\n  \"components.Layout.Sidebar.settings\": \"Inställningar\",\n  \"components.Layout.Sidebar.requests\": \"Förfrågningar\",\n  \"components.Layout.Sidebar.dashboard\": \"Upptäck\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Sök filmer och serier\",\n  \"components.Discover.upcomingmovies\": \"Kommande filmer\",\n  \"components.Discover.upcoming\": \"Kommande filmer\",\n  \"components.Discover.trending\": \"Trendande\",\n  \"components.Discover.recentrequests\": \"Senaste förfrågningarna\",\n  \"components.Discover.recentlyAdded\": \"Nyligen tillagda\",\n  \"components.Discover.populartv\": \"Populära serier\",\n  \"components.Discover.popularmovies\": \"Populära filmer\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Hela seriens rollista\",\n  \"components.Setup.welcome\": \"Välkommen till Seerr\",\n  \"components.Setup.signinMessage\": \"Kom igång genom att logga in\",\n  \"components.RequestModal.requestseasons\": \"Begär {seasonCount} {seasonCount, plural, one {Säsong} other {Säsonger}}\",\n  \"pages.returnHome\": \"Gå tillbaka till startsidan\",\n  \"pages.oops\": \"Hoppsan\",\n  \"i18n.unavailable\": \"Otillgänglig\",\n  \"i18n.tvshows\": \"Serier\",\n  \"i18n.processing\": \"Behandlar\",\n  \"i18n.pending\": \"Väntande\",\n  \"i18n.partiallyavailable\": \"Delvis tillgänglig\",\n  \"i18n.movies\": \"Filmer\",\n  \"i18n.deleting\": \"Tar bort…\",\n  \"i18n.delete\": \"Ta bort\",\n  \"i18n.declined\": \"Nekad\",\n  \"i18n.decline\": \"Neka\",\n  \"i18n.cancel\": \"Avbryt\",\n  \"i18n.available\": \"Tillgänglig\",\n  \"i18n.approved\": \"Godkänd\",\n  \"i18n.approve\": \"Godkänn\",\n  \"components.UserList.userlist\": \"Användarlista\",\n  \"components.UserList.userdeleteerror\": \"Något gick fel när användaren skulle tas bort.\",\n  \"components.UserList.userdeleted\": \"Användare borttagen!\",\n  \"components.UserList.user\": \"Användare\",\n  \"components.UserList.totalrequests\": \"Förfrågningar\",\n  \"components.UserList.role\": \"Roll\",\n  \"components.UserList.plexuser\": \"Plex-användare\",\n  \"components.UserList.deleteuser\": \"Ta bort användare\",\n  \"components.UserList.deleteconfirm\": \"Är du säker på att du vill ta bort denna användare? All deras förfrågningsdata kommer att tas bort permanent.\",\n  \"components.UserList.created\": \"Gick med\",\n  \"components.UserList.admin\": \"Administratör\",\n  \"components.TvDetails.similar\": \"Liknande serier\",\n  \"components.TvDetails.showtype\": \"Serietyp\",\n  \"components.TvDetails.recommendations\": \"Rekommendationer\",\n  \"components.TvDetails.overviewunavailable\": \"Beskrivning saknas.\",\n  \"components.TvDetails.overview\": \"Översikt\",\n  \"components.TvDetails.originallanguage\": \"Originalspråk\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Nätverk} other {Nätverk}}\",\n  \"components.TvDetails.cast\": \"Rollista\",\n  \"i18n.close\": \"Stäng\",\n  \"components.Settings.SettingsAbout.timezone\": \"Tidszon\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Visa på GitHub\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Visa ändringslogg\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version}-ändringslogg\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Versioner\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Versionsdata är för närvarande inte tillgänglig.\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Senaste versionen\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Aktuell\",\n  \"components.UserList.importfrommediaserver\": \"Importera {mediaServerName}-användare\",\n  \"components.UserList.importfromplex\": \"Importera Plex-användare\",\n  \"components.UserList.importfromplexerror\": \"Något gick fel när Plex-användare skulle importeras.\",\n  \"components.TvDetails.watchtrailer\": \"Visa trailer\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Tillåt självsignerade certifikat\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Meddelandeinställningarna för Slack sparades!\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Meddelandeinställningarna för Slack kunde inte sparas.\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Aktivera Slack\",\n  \"components.MovieDetails.watchtrailer\": \"Visa trailer\",\n  \"components.CollectionDetails.requestcollection\": \"Begär samling\",\n  \"components.CollectionDetails.overview\": \"Översikt\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} filmer\",\n  \"i18n.retry\": \"Försök igen\",\n  \"i18n.requested\": \"Begärd\",\n  \"i18n.request\": \"Begär\",\n  \"i18n.failed\": \"Misslyckades\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {användare} other {användare}} importerades!\",\n  \"components.TvDetails.viewfullcrew\": \"Visa hela teamet\",\n  \"components.TvDetails.firstAirDate\": \"Första sändningsdatum\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Hela teamet\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dokumentation\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Du måste ange ett giltigt chatt-ID\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Du måste ange en bot-auktoriseringstoken\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegrams meddelandeinställningar har sparats!\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegrams meddelandeinställningar kunde inte sparas.\",\n  \"components.Settings.Notifications.senderName\": \"Avsändarens namn\",\n  \"components.Settings.Notifications.chatId\": \"Chatt-ID\",\n  \"components.Settings.Notifications.botAPI\": \"Botens auktoriseringstoken\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Webhook-meddelandeinställningar har sparats!\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Webhook-meddelandeinställningar kunde inte sparas.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook-URL\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Du måste ange en giltig JSON-nyttolast\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Lathund för mallvariabler\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON-nyttolast återställd!\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Återställ till standard\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON-nyttolast\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Auktoriseringrubrik (header)\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Aktivera Webhook\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Du måste ange en giltig användar- eller gruppnyckel\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Du måste ange en giltig applikationstoken\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Användar- eller gruppnyckel\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Inställningarna för Pushover-meddelanden sparades!\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Meddelandeinställningarna för Pushover kunde inte sparas.\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Aktivera Pushover\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Applikation-API-token\",\n  \"components.RequestModal.pending4krequest\": \"Väntande 4K-förfrågan\",\n  \"components.RequestList.sortModified\": \"Senast ändrad\",\n  \"components.RequestList.sortAdded\": \"Senaste\",\n  \"components.RequestList.showallrequests\": \"Visa alla förfrågningar\",\n  \"components.RequestList.RequestItem.failedretry\": \"Något gick fel vid återförsök av förfrågan.\",\n  \"components.RequestButton.viewrequest4k\": \"Visa 4K-förfrågan\",\n  \"components.RequestButton.viewrequest\": \"Visa förfrågan\",\n  \"components.RequestButton.requestmore4k\": \"Begär fler i 4K\",\n  \"components.RequestButton.requestmore\": \"Begär fler\",\n  \"components.RequestButton.declinerequests\": \"Neka {requestCount, plural, one {förfrågan} other {{requestCount} förfrågningar}}\",\n  \"components.RequestButton.declinerequest4k\": \"Neka 4K-förfrågan\",\n  \"components.RequestButton.declinerequest\": \"Neka förfrågan\",\n  \"components.RequestButton.decline4krequests\": \"Neka {requestCount, plural, one {4K-förfrågan} other {{requestCount} 4K-förfrågningar}}\",\n  \"components.RequestButton.approverequests\": \"Godkänn {requestCount, plural, one {förfrågan} other {{requestCount} förfrågningar}}\",\n  \"components.RequestButton.approverequest4k\": \"Godkänn 4K-förfrågan\",\n  \"components.RequestButton.approverequest\": \"Godkänn förfrågan\",\n  \"components.RequestButton.approve4krequests\": \"Godkänn {requestCount, plural, one {4K-förfrågan} other {{requestCount} 4K-förfrågningar}}\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Skicka meddelanden när användare skickar nya medieförfrågningar som kräver godkännande.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Förfrågan väntar på godkännande\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Skicka meddelanden när medieförfrågningar misslyckas att läggas till i Radarr eller Sonarr.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Bearbetning av förfrågan misslyckades\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Skicka meddelanden när medieförfrågningar blir tillgängliga.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Förfrågan tillgänglig\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Skicka meddelanden när medieförfrågningar godkänns manuellt.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Förfrågan godkänd\",\n  \"components.MovieDetails.viewfullcrew\": \"Visa hela teamet\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Team\",\n  \"components.UserList.userssaved\": \"Användarbehörigheter sparade!\",\n  \"components.UserList.bulkedit\": \"Massredigering\",\n  \"components.PermissionEdit.usersDescription\": \"Ge behörighet att hantera användare. Användare med denna behörighet kan inte ändra eller lägga till användare med adminrättigheter.\",\n  \"components.PermissionEdit.users\": \"Hantera användare\",\n  \"components.PermissionEdit.requestDescription\": \"Ge behörighet att skicka in förfrågningar för media som inte är 4K.\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Ge behörighet att skicka in förfrågningar för 4K-serier.\",\n  \"components.PermissionEdit.request4kTv\": \"Göra 4K-serieförfrågningar\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Ge behörighet att skicka in förfrågningar för 4K-filmer.\",\n  \"components.PermissionEdit.request4kMovies\": \"Göra 4K-filmförfrågningar\",\n  \"components.PermissionEdit.request4kDescription\": \"Ge behörighet att skicka in förfrågningar för 4K-media.\",\n  \"components.PermissionEdit.request4k\": \"Göra 4K-förfrågningar\",\n  \"components.PermissionEdit.request\": \"Göra förfrågningar\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Ge behörighet att hantera medieförfrågningar. Alla förfrågningar gjorda av en användare med denna behörighet kommer automatiskt att godkännas.\",\n  \"components.PermissionEdit.managerequests\": \"Hantera förfrågningar\",\n  \"components.PermissionEdit.adminDescription\": \"Fullständig administratörsbehörighet. Överskrider alla andra behörighetskontroller.\",\n  \"components.RequestModal.requesterror\": \"Något gick fel när förfrågan skickades.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Vi kunde inte automatiskt matcha denna serie. Välj rätt matchning nedan.\",\n  \"i18n.experimental\": \"Experimentell\",\n  \"components.RequestModal.autoapproval\": \"Automatiskt godkännande\",\n  \"i18n.edit\": \"Redigera\",\n  \"components.RequestModal.requestedited\": \"Förfrågan för <strong>{title}</strong> har redigerats!\",\n  \"components.RequestModal.requestcancelled\": \"Förfrågan för <strong>{title}</strong> avbruten.\",\n  \"components.RequestModal.errorediting\": \"Något gick fel vid redigering av förfrågan.\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Rotmapp\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Destinationsserver\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (standard)\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Denna serie är en anime.\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Avancerat\",\n  \"components.RequestBlock.server\": \"Destinationsserver\",\n  \"components.RequestBlock.rootfolder\": \"Rotmapp\",\n  \"components.RequestBlock.profilechanged\": \"Kvalitetsprofil\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Visa fler\",\n  \"components.UserList.validationpasswordminchars\": \"Lösenordet är för kort; det måste innehålla minst 8 tecken\",\n  \"components.UserList.usercreatedsuccess\": \"Användare skapad!\",\n  \"components.UserList.usercreatedfailed\": \"Någonting gick fel vid skapandet av användaren.\",\n  \"components.UserList.passwordinfodescription\": \"Konfigurera en applikations-URL och aktivera e-postmeddelanden för att tillåta automatisk lösenordsgenerering.\",\n  \"components.UserList.password\": \"Lösenord\",\n  \"components.UserList.localuser\": \"Lokal användare\",\n  \"components.UserList.email\": \"E-postadress\",\n  \"components.UserList.creating\": \"Skapar…\",\n  \"components.UserList.createlocaluser\": \"Skapa lokal användare\",\n  \"components.UserList.create\": \"Skapa\",\n  \"components.UserList.autogeneratepassword\": \"Generera lösenord automatiskt\",\n  \"components.PersonDetails.crewmember\": \"Teammedlem\",\n  \"components.Login.validationemailrequired\": \"Du måste ange en giltig e-postadress\",\n  \"components.Login.email\": \"E-postadress\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Ge automatiskt godkännande för serieförfrågningar som inte är 4K.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Godkänn serier automatiskt\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Ge automatiskt godkännande för filmförfrågningar som inte är 4K.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Godkänn filmer automatiskt\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Ge automatiskt godkännande för alla medieförfrågningar som inte är 4K.\",\n  \"components.PermissionEdit.autoapprove\": \"Godkänn automatiskt\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Ge behörighet att ändra avancerade alternativ för medieförfrågningar.\",\n  \"components.PermissionEdit.advancedrequest\": \"Avancerade förfrågningar\",\n  \"components.PermissionEdit.admin\": \"Admin\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Skicka meddelanden när medieförfrågningar nekas.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Förfrågan nekad\",\n  \"components.MovieDetails.markavailable\": \"Markera som tillgänglig\",\n  \"components.MovieDetails.mark4kavailable\": \"Markera som tillgänglig i 4K\",\n  \"components.Login.validationpasswordrequired\": \"Du måste ange ett lösenord\",\n  \"components.Login.signinwithplex\": \"Använd ditt Plex-konto\",\n  \"components.Login.signinwithoverseerr\": \"Använd ditt {applicationTitle}-konto\",\n  \"components.Login.signinheader\": \"Logga in för att fortsätta\",\n  \"components.Login.signingin\": \"Loggar in…\",\n  \"components.Login.signin\": \"Logga in\",\n  \"components.Login.password\": \"Lösenord\",\n  \"components.Login.loginerror\": \"Något gick fel vid inloggningen.\",\n  \"components.Login.forgotpassword\": \"Glömt lösenordet?\",\n  \"components.Discover.discover\": \"Upptäck\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Volymmonteringen för <code>{appDataPath}</code> är inte korrekt konfigurerad. All data kommer att rensas när containern stoppas eller startas om.\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Du måste ange ett lösenord\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Lösenordet är för kort; det måste innehålla minst 8 tecken\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Lösenorden måste vara samma\",\n  \"components.ResetPassword.validationemailrequired\": \"Du måste ange en giltig e-postadress\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Lösenordet har återställts!\",\n  \"components.ResetPassword.resetpassword\": \"Återställ ditt lösenord\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"En länk för återställning av lösenord kommer att skickas till den angivna e-postadressen om den är kopplad till en giltig användare.\",\n  \"components.ResetPassword.password\": \"Lösenord\",\n  \"components.ResetPassword.gobacklogin\": \"Gå tillbaka till sidan för inloggning\",\n  \"components.ResetPassword.emailresetlink\": \"Skicka återställningslänk\",\n  \"components.ResetPassword.email\": \"E-postadress\",\n  \"components.ResetPassword.confirmpassword\": \"Bekräfta lösenord\",\n  \"components.TvDetails.nextAirDate\": \"Nästa sändningsdatum\",\n  \"components.UserList.validationEmail\": \"E-postadress krävs\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Bas-URL får inte sluta med ett avslutande snedstreck\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Bas-URL:en måste börja med ett snedstreck\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL-basen får inte sluta med ett snedstreck\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL-basen måste börja med ett inledande snedstreck\",\n  \"components.Settings.Notifications.validationEmail\": \"Du måste ange en giltig e-postadress\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Du måste ange en giltig URL\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Du måste ange en giltig URL\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Du måste ange en giltig URL\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL får inte sluta med ett snedstreck\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Du måste ange en giltig URL\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL får inte sluta med ett snedstreck\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Ge behörighet att visa medieförfrågningar inskickade av andra användare.\",\n  \"components.PermissionEdit.viewrequests\": \"Visa förfrågningar\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Begär som\",\n  \"components.Setup.setup\": \"Installationsguide\",\n  \"components.UserList.users\": \"Användare\",\n  \"components.Search.search\": \"Sök\",\n  \"components.Settings.SettingsJobsCache.process\": \"Process\",\n  \"components.Settings.SettingsJobsCache.command\": \"Kommando\",\n  \"i18n.advanced\": \"Avancerad\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Kör nu\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Nästa körning\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Typ\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} startat.\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr utför vissa underhållsuppgifter som schemalagda jobb automatiskt, men de kan också köras manuellt nedan. Att köra ett jobb manuellt ändrar inte schemat.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Jobb\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Jobbnamn\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} avbrutet.\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Rensa cache\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Avbryt jobb\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Storleksvärde\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Cache-namn\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Missar\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Nyckelstorlek\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Totalt antal nycklar\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Träffar\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename}-cache rensad.\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr cachar förfrågningar till externa API:er för att optimera prestanda och undvika onödiga API-anrop.\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Cache\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Aktivera skanning\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Extern URL\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Aktivera skanning\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Extern URL\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Anslutningen till Sonarr lyckades!\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Kunde inte ansluta till Sonarr.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Hämtning av serverlistan från Plex lyckades!\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Misslyckades med att hämta serverlistan från Plex.\",\n  \"components.Settings.toastPlexRefresh\": \"Hämtar serverlistan från Plex…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Anslutningen till Plex lyckades!\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Misslyckades med att ansluta till Plex.\",\n  \"components.Settings.toastPlexConnecting\": \"Försöker ansluta till Plex…\",\n  \"components.Settings.settingUpPlexDescription\": \"För att konfigurera Plex kan du antingen ställa in inställningarna manuellt eller välja en server som hämtats via <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Tryck på knappen till höger om rullgardinsmenyn för att hämta listan över tillgängliga servrar.\",\n  \"components.Settings.serverpresetRefreshing\": \"Hämtar servrar…\",\n  \"components.Settings.serverpresetManualMessage\": \"Manuell konfiguration\",\n  \"components.Settings.serverpresetLoad\": \"Klicka på knappen för att ladda in tillgängliga servrar\",\n  \"components.Settings.serverpreset\": \"Server\",\n  \"components.Settings.serverRemote\": \"fjärr\",\n  \"components.Settings.serverLocal\": \"lokal\",\n  \"i18n.loading\": \"Laddar…\",\n  \"components.UserProfile.recentrequests\": \"Senaste förfrågningarna\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Behörigheter\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Meddelanden\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Allmänt\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Lösenord\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Behörigheterna har sparats!\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Något gick fel när inställningarna skulle sparas.\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Behörigheter\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Lösenordet är för kort; det måste innehålla minst 8 tecken\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Du måste ange ett nytt lösenord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Du måste ange ditt nuvarande lösenord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Lösenorden måste vara samma\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Du måste bekräfta det nya lösenordet\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Lösenordet har ändrats!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Något gick fel när lösenordet skulle sparas.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Lösenord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Du har inte behörighet att ändra användarens lösenord.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Nytt lösenord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Nuvarande lösenord\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Bekräfta lösenord\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Du måste ange ett giltigt chatt-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Du måste ange ett giltigt användar-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Starta en chatt</TelegramBotLink>, lägg till <GetIdBotLink>@get_id_bot</GetIdBotLink>, och kör kommandot <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Chatt-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Skicka meddelanden utan ljud\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Skicka tyst\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Meddelandeinställningar\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"Det <FindDiscordIdLink>flersiffriga ID-numret</FindDiscordIdLink> som är kopplat till ditt användarkonto\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Användar-ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Användare\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Inställningarna har sparats!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Något gick fel när inställningarna sparades.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Roll\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Filtrera innehåll efter regional tillgänglighet\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Region för Upptäck\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex-användare\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Ägare\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Filtrera innehåll efter originalspråk\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Språk för Upptäck\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Lokal användare\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Allmänna inställningar\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Visningsnamn\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Administratör\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Kontotyp\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Användar-ID: {userid}\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Ändra inställningar\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Visa profil\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Medlem sedan {joindate}\",\n  \"components.UserList.userfail\": \"Något gick fel när användarbehörigheter skulle sparas.\",\n  \"components.UserList.sortRequests\": \"Antal förfrågningar\",\n  \"components.UserList.sortDisplayName\": \"Visningsnamn\",\n  \"components.UserList.sortCreated\": \"Gick med datum\",\n  \"components.UserList.owner\": \"Ägare\",\n  \"components.UserList.edituser\": \"Redigera användarbehörigheter\",\n  \"components.UserList.accounttype\": \"Typ\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# säsong} other {# säsonger}}\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.scanning\": \"Synkroniserar…\",\n  \"components.Settings.scan\": \"Skanna bibliotek\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Konfigurera och aktivera meddelandetjänster.\",\n  \"components.Settings.menuUsers\": \"Användare\",\n  \"components.Settings.email\": \"E-post\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Du måste välja en språkprofil\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Testa anslutningen för att ladda in språkprofiler\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Välj spåkprofil\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Laddar språkprofiler…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Språkprofil\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime-språkprofil\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Konfigurera globala och standardinställningar för användare.\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Användarinställningar\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Användarinställningarna sparades!\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Något gick fel när inställningarna skulle sparas.\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Aktivera lokal inloggning\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Standardbehörigheter\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Okänt jobb\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr-skanning\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr-skanning\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Skanning av senast tillagda i Plex\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Full biblioteksskanning för Plex\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Full Jellyfin-biblioteksskanning\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Skanning av nyligen tillagda objekt i Jellyfin\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Nollställ nedladdningssynkronisering\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Nedladdningssynkronisering\",\n  \"components.Settings.Notifications.validationUrl\": \"Du måste ange en giltig URL\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Skicka meddelanden utan ljud\",\n  \"components.Settings.Notifications.sendSilently\": \"Skicka tyst\",\n  \"components.Settings.Notifications.botUsername\": \"Botens användarnamn\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Botens avatar-URL\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Du måste ange en åtkomsttoken\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet-meddelandeinställningar har sparats!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbullet-meddelandeinställningar kunde inte sparas.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Aktivera Pushbullet\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Åtkomsttoken\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Språkprofil\",\n  \"components.RequestList.RequestItem.requested\": \"Begärd\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} av {user}\",\n  \"components.RequestList.RequestItem.modified\": \"Ändrad\",\n  \"components.RequestBlock.requestoverrides\": \"Åsidosättningar för förfrågan\",\n  \"components.RegionSelector.regionServerDefault\": \"Standard ({region})\",\n  \"components.RegionSelector.regionDefault\": \"Alla regioner\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Ge automatiskt godkännande för 4K-serieförfrågningar.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Godkänn serier i 4K automatiskt\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Ge automatiskt godkännande för 4K-filmförfrågningar.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Godkänn filmer i 4K automatiskt\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Ge automatiskt godkännande för alla 4K-medieförfrågningar.\",\n  \"components.PermissionEdit.autoapprove4k\": \"Godkänn automatiskt 4K\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Skicka meddelanden när användare skickar in nya medieförfrågningar som godkänns automatiskt.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Förfrågan automatiskt godkänd\",\n  \"components.Layout.UserDropdown.settings\": \"Inställningar\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Discover.upcomingtv\": \"Kommande serier\",\n  \"components.Discover.StudioSlider.studios\": \"Studior\",\n  \"components.Discover.NetworkSlider.networks\": \"Nätverk\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} serier\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre}-serier\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio}-filmer\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network}-serier\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} filmer\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre}-filmer\",\n  \"components.CollectionDetails.requestcollection4k\": \"Begär samling i 4K\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Du har inte behörighet att ändra den här användarens inställningar.\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Du kan inte ändra dina egna behörigheter.\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Filmgenrer\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Filmgenrer\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Seriegenrer\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Seriegenrer\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} minuter\",\n  \"components.TvDetails.episodeRuntime\": \"Avsnittslängd\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Signera krypterade e-postmeddelanden med <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Privat PGP-nyckel\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Signera krypterade e-postmeddelanden med <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP-lösenord\",\n  \"components.RequestModal.alreadyrequested\": \"Redan begärd\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Allmänt\",\n  \"pages.somethingwentwrong\": \"Något gick fel\",\n  \"pages.serviceunavailable\": \"Tjänsten är inte tillgänglig\",\n  \"pages.pagenotfound\": \"Sidan hittas inte\",\n  \"pages.internalservererror\": \"Internt serverfel\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"i18n.usersettings\": \"Användarinställningar\",\n  \"i18n.settings\": \"Inställningar\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Något gick fel när lösenordet sparades. Har ditt nuvarande lösenord skrivits in korrekt?\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Meddelanden\",\n  \"components.Settings.services\": \"Tjänster\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"Meddelanden\",\n  \"components.Settings.SettingsUsers.users\": \"Användare\",\n  \"components.Settings.SettingsLogs.time\": \"Tidsstämpel\",\n  \"components.Settings.SettingsLogs.showall\": \"Visa alla loggar\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Återuppta\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Paus\",\n  \"components.Settings.SettingsLogs.message\": \"Meddelande\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Du kan också visa dessa loggar direkt via <code>stdout</code>, eller i <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.label\": \"Etikett\",\n  \"components.Settings.SettingsLogs.logs\": \"Loggar\",\n  \"components.Settings.SettingsLogs.level\": \"Allvarlighetsgrad\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Varning\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Info\",\n  \"components.Settings.SettingsLogs.filterError\": \"Fel\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Felsök\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Jobb och cache\",\n  \"components.Settings.SettingsAbout.about\": \"Om\",\n  \"components.ResetPassword.passwordreset\": \"Återställning av lösenord\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Logginformation\",\n  \"components.Settings.SettingsLogs.extraData\": \"Ytterligare data\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Kopiera till urklipp\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Kopierat loggmeddelande till urklipp.\",\n  \"components.Settings.enablessl\": \"Använd SSL\",\n  \"components.UserList.nouserstoimport\": \"Det finns inga Plex-användare att importera.\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.PersonDetails.birthdate\": \"Född {birthdate}\",\n  \"components.PersonDetails.alsoknownas\": \"Även känd som: {names}\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Inga} other {<strong>#</strong>}} {type}{remaining, plural, one {förfrågan} other {förfrågningar}} kvar\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Du kan se en sammanfattning av denna användares förfrågningsgränser på deras <ProfileLink>profilsida</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Du kan se en sammanfattning av dina förfrågningsgränser på din <ProfileLink>profilsida</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Inte tillräckligt med säsongsförfrågningar kvar\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {film} other {filmer}}\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"film\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Denna användare får begära <strong>{limit}</strong> {type} var <strong>{days}</strong> dag(ar).\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Du får begära <strong>{limit}</strong> {type} var <strong>{days}</strong> dag(ar).\",\n  \"components.QuotaSelector.unlimited\": \"Obegränsat\",\n  \"i18n.view\": \"Visa\",\n  \"i18n.tvshow\": \"Serie\",\n  \"i18n.testing\": \"Testar…\",\n  \"i18n.test\": \"Test\",\n  \"i18n.status\": \"Status\",\n  \"i18n.showingresults\": \"Visar <strong>{from}</strong> till <strong>{to}</strong> av <strong>{total}</strong> resultat\",\n  \"i18n.saving\": \"Sparar…\",\n  \"i18n.save\": \"Spara ändringar\",\n  \"i18n.resultsperpage\": \"Visa {pageSize} resultat per sida\",\n  \"i18n.requesting\": \"Begär…\",\n  \"i18n.request4k\": \"Begär i 4K\",\n  \"i18n.previous\": \"Föregående\",\n  \"i18n.notrequested\": \"Inte begärd\",\n  \"i18n.noresults\": \"Inga resultat.\",\n  \"i18n.next\": \"Nästa\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.canceling\": \"Avbryter…\",\n  \"i18n.back\": \"Bakåt\",\n  \"i18n.areyousure\": \"Är du säker?\",\n  \"i18n.all\": \"Alla\",\n  \"components.UserProfile.unlimited\": \"Obegränsat\",\n  \"components.UserProfile.totalrequests\": \"Totalt antal förfrågningar\",\n  \"components.UserProfile.seriesrequest\": \"Serieförfrågningar\",\n  \"components.UserProfile.requestsperdays\": \"{limit} kvar\",\n  \"components.UserProfile.pastdays\": \"{type} (senaste {days} dagar)\",\n  \"components.UserProfile.movierequests\": \"Filmförfrågningar\",\n  \"components.UserProfile.limit\": \"{remaining} av {limit}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Gräns för serieförfrågningar\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Gräns för filmförfrågningar\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Åsidosätt den globala gränsen\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Global gräns för serieförfrågningar\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Global gräns för filmförfrågningar\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Denna användare behöver ha minst <strong>{seasons}</strong> {seasons, plural, one {säsongsförfrågan} other {säsongsförfrågningar}} kvar för att kunna skicka in en förfrågan för denna serie.\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {säsong} other {säsonger}}\",\n  \"components.RequestModal.QuotaDisplay.season\": \"säsong\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Du behöver ha minst <strong>{seasons}</strong> {seasons, plural, one {säsongsförfrågan} other {säsongsförfrågningar}} kvar för att kunna skicka in en förfrågan för denna serie.\",\n  \"components.TvDetails.originaltitle\": \"Originaltitel\",\n  \"components.MovieDetails.originaltitle\": \"Originaltitel\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Alla språk\",\n  \"components.LanguageSelector.languageServerDefault\": \"Standard ({language})\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Testa anslutningen för att ladda in taggar\",\n  \"components.Settings.SonarrModal.tags\": \"Taggar\",\n  \"components.Settings.SonarrModal.selecttags\": \"Välj taggar\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Inga taggar.\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Laddar taggar…\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Redigera 4K Sonarr-instans\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Standard 4K-instans\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Lägg till ny 4K Sonarr-instans\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime-taggar\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Testa anslutningen för att ladda in taggar\",\n  \"components.Settings.RadarrModal.tags\": \"Taggar\",\n  \"components.Settings.RadarrModal.selecttags\": \"Välj taggar\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Lägg till ny 4K Radarr-instans\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Inga taggar.\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Redigera 4K Radarr-instans\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Standard 4K-instans\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Taggar\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Välj taggar\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Inga taggar.\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Laddar taggar…\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} hittades inte\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Ta bort förfrågan\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} hittades inte\",\n  \"components.RequestCard.deleterequest\": \"Ta bort förfrågan\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Discords meddelandeinställningar kunde inte sparas.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Du måste ange en giltig publik PGP-nyckel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegrams meddelandeinställningar har sparats!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Telegrams meddelandeinställningar kunde inte sparas.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Kryptera e-postmeddelanden med <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Publik PGP-nyckel\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"E-postmeddelandeinställningar har sparats!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"E-postmeddelandeinställningar kunde inte sparas.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-post\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discords meddelandeinställningar har sparats!\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Du måste ange en giltig privat PGP-nyckel\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Du måste ange ett PGP-lösenord\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Tillåt användare att även starta en chatt med din bot och konfigurera sina egna meddelanden\",\n  \"components.RequestModal.pendingapproval\": \"Din förfrågan väntar på godkännande.\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Avbryt förfrågan\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Meddelandetyper\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr stable\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr develop\",\n  \"components.Layout.VersionStatus.outofdate\": \"Föråldrad\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {ändring} other {ändringar}} efter\",\n  \"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.\",\n  \"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.\\\"\",\n  \"components.Settings.serviceSettingsDescription\": \"Konfigurera dina {serverType}-instanser nedan. Du kan ansluta flera {serverType}-instanser, men endast två av dem kan markeras som standard (en icke-4K och en 4K). Administratörer kan åsidosätta instansen som används för att bearbeta nya förfrågningar före godkännande.\",\n  \"components.Settings.noDefaultServer\": \"Minst en {serverType}-instans måste markeras som standard för att {mediaType}-förfrågningar ska kunna bearbetas.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Om du bara har en enda {serverType}-instans för både icke-4K- och 4K-innehåll (eller om du bara har 4K-innehåll) bör din {serverType}-instans<strong> INTE </strong> betecknas som en 4K-instans.\",\n  \"components.Settings.mediaTypeSeries\": \"serie\",\n  \"components.Settings.mediaTypeMovie\": \"film\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Uppdaterad\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Föråldrad\",\n  \"components.UserList.autogeneratepasswordTip\": \"Skicka ett servergenererat lösenord via e-post till användaren\",\n  \"i18n.retrying\": \"Försöker igen…\",\n  \"components.Settings.serverSecure\": \"säker\",\n  \"components.UserList.usercreatedfailedexisting\": \"Den angivna e-postadressen används redan.\",\n  \"components.RequestModal.edit\": \"Redigera förfrågan\",\n  \"components.RequestList.RequestItem.editrequest\": \"Redigera förfrågan\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Aktivera automatisk sökning\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Aktivera automatisk sökning\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Webbpush\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Visningsspråk\",\n  \"components.Settings.webpush\": \"Webbpush\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Webbpush-meddelandeinställningar har sparats!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Webbpush-meddelandeinställningar kunde inte sparas.\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Aktivera Webbpush\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Skickar Pushbullet-testmeddelande…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet-testmeddelande kunde inte skickas.\",\n  \"components.Settings.noDefault4kServer\": \"En 4K {serverType}-instans måste markeras som standard för att användare ska kunna skicka in 4K {mediaType}-förfrågningar.\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram-testmeddelande skickat!\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Skickar Telegram-testmeddelande…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram-testmeddelande kunde inte skickas.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"E-posttestmeddelande skickat!\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Skickar e-posttestmeddelande…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"E-posttestmeddelande kunde inte skickas.\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord-testmeddelande skickat!\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Skickar Discord-testmeddelande…\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord-testmeddelande kunde inte skickas.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook-testmeddelande skickat!\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Skickar Webhook-testmeddelande…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Webhook-testmeddelande kunde inte skickas.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Webbpush-testmeddelande skickat!\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Skickar Webbpush-testmeddelande…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Webbpush-testmeddelande kunde inte skickas.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack-testmeddelande skickat!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Skickar testmeddelande via Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack-testmeddelandet kunde inte skickas.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover-testmeddelande skickat!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Skickar testmeddelande via Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover-testmeddelandet kunde inte skickas.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet-testmeddelande skickat!\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Tillåt {mediaServerName}-användare att logga in utan att först importeras\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Aktivera ny {mediaServerName}-inloggning\",\n  \"components.PermissionEdit.requestTvDescription\": \"Ge behörighet att skicka in förfrågningar för serier som inte är 4K.\",\n  \"components.PermissionEdit.requestTv\": \"Göra serieförfrågningar\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Ge behörighet att skicka in förfrågningar för filmer som inte är 4K.\",\n  \"components.PermissionEdit.requestMovies\": \"Göra filmförfrågningar\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Standard ({language})\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Skapa en <DiscordWebhookLink>webhook-integration</DiscordWebhookLink> på din server\",\n  \"components.Settings.Notifications.encryptionTip\": \"I de flesta fall använder implicit TLS port 465 och STARTTLS använder port 587\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Använd alltid STARTTLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"Ingen\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Använd implicit TLS\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Använd STARTTLS om tillgängligt\",\n  \"components.Settings.Notifications.encryption\": \"Krypteringsmetod\",\n  \"components.Settings.Notifications.chatIdTip\": \"Starta en chatt med din bot, lägg till <GetIdBotLink>@get_id_bot</GetIdBotLink>, och kör kommandot <code>/my_id</code>\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Skapa en bot</CreateBotLink> för användning med Seerr\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Skapa en <WebhookLink>Inkommande Webhook</WebhookLink>-integration\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Din <UsersGroupsLink>användare eller gruppidentifierare</UsersGroupsLink> (30 tecken)\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Registrera en applikation</ApplicationRegistrationLink> för användning med Seerr\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Skapa en token från dina <PushbulletSettingsLink>kontoinställningar</PushbulletSettingsLink>\",\n  \"components.DownloadBlock.estimatedtime\": \"Beräknad {time}\",\n  \"components.Settings.webAppUrlTip\": \"Alternativt skicka användare till den lokala webbappen istället för den \\\"hostade\\\" webbappen\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Webbapp</WebAppLink>-URL\",\n  \"components.UserList.localLoginDisabled\": \"Inställningen <strong>Aktivera lokal inloggning</strong> är för närvarande inaktiverad.\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"För att kunna ta emot webbpushmeddelanden måste Seerr presenteras över HTTPS.\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Begärd\",\n  \"components.RequestCard.failedretry\": \"Något gick fel vid återförsök av förfrågan.\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Tillåt användare att logga in med sin e-postadress och lösenord\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Inledande behörigheter som tilldelas nya användare\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} per {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {säsong} other {säsonger}}\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {film} other {filmer}}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {dag} other {dagar}}\",\n  \"components.Settings.Notifications.validationTypes\": \"Du måste välja minst en meddelandetyp\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Du måste välja minst en meddelandetyp\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Du måste välja minst en meddelandetyp\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Du måste välja minst en meddelandetyp\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Du måste välja minst en meddelandetyp\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Få meddelanden när andra användare skickar nya medieförfrågningar som kräver godkännande.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Få meddelanden när medieförfrågningar misslyckas att läggas till i Radarr eller Sonarr.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Få meddelanden när dina medieförfrågningar nekas.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Få meddelanden när dina medieförfrågningar blir tillgängliga.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Få meddelanden när dina medieförfrågningar godkänns.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Få meddelanden när andra användare skickar nya medieförfrågningar som automatiskt godkänns.\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Visningsspråk\",\n  \"components.MovieDetails.showmore\": \"Visa mer\",\n  \"components.MovieDetails.showless\": \"Visa mindre\",\n  \"components.TvDetails.streamingproviders\": \"Streamas för närvarande på\",\n  \"components.MovieDetails.streamingproviders\": \"Streamas nu på\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Ändra jobb\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Ny frekvens\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Varje {jobScheduleHours, plural, one {timme} other {{jobScheduleHours} timmar}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Varje {jobScheduleMinutes, plural, one {minut} other {{jobScheduleMinutes} minuter}}\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Något gick fel när jobbet skulle sparas.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Jobbet har redigerats!\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Du kör <code>develop</code>-grenen av Seerr, vilket endast rekommenderas för de som bidrar till utveckling eller hjälper till med testning av den senaste versionen.\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Är du säker på att du vill ta bort den här kommentaren?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Ta bort kommentar\",\n  \"components.IssueDetails.IssueComment.edit\": \"Redigera kommentar\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Publicerad {relativeTime} av {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Publicerad {relativeTime} av {username} (redigerad)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Du måste skriva ett meddelande\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Ta bort ärende\",\n  \"components.IssueDetails.allepisodes\": \"Alla avsnitt\",\n  \"components.IssueDetails.closeissue\": \"Stäng ärende\",\n  \"components.IssueDetails.closeissueandcomment\": \"Stäng med kommentar\",\n  \"components.IssueDetails.IssueDescription.description\": \"Beskrivning\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Redigera beskrivning\",\n  \"components.IssueDetails.allseasons\": \"Alla säsonger\",\n  \"components.IssueDetails.comments\": \"Kommentarer\",\n  \"components.IssueDetails.episode\": \"Avsnitt {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Ärende\",\n  \"components.IssueDetails.issuetype\": \"Typ\",\n  \"components.IssueDetails.lastupdated\": \"Senast uppdaterad\",\n  \"components.IssueDetails.openinarr\": \"Öppna i {arr}\",\n  \"components.IssueDetails.problemepisode\": \"Berört avsnitt\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Något gick fel vid redigering av ärendebeskrivningen.\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Något gick fel vid borttagning av ärendet.\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Något gick fel vid uppdatering av ärendestatus.\",\n  \"components.IssueDetails.unknownissuetype\": \"Okänd\",\n  \"components.IssueDetails.openedby\": \"#{issueId} öppnades {relativeTime} av {username}\",\n  \"components.IssueDetails.openin4karr\": \"Öppna i 4K {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Spela i 4K på {mediaServerName}\",\n  \"components.IssueDetails.playonplex\": \"Spela på {mediaServerName}\",\n  \"components.IssueDetails.problemseason\": \"Berörd säsong\",\n  \"components.IssueDetails.reopenissue\": \"Återöppna ärende\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Återöppna med kommentar\",\n  \"components.IssueDetails.season\": \"Säsong {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Ärendebeskrivning redigerad!\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Säsong} other {Säsonger}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Okänd\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} av {user}\",\n  \"components.IssueList.IssueItem.viewissue\": \"Visa ärende\",\n  \"components.IssueList.showallissues\": \"Visa alla ärenden\",\n  \"components.IssueDetails.deleteissue\": \"Ta bort ärende\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Är du säker på att du vill ta bort det här ärendet?\",\n  \"components.IssueList.IssueItem.opened\": \"Öppnat\",\n  \"components.IssueDetails.leavecomment\": \"Kommentera\",\n  \"components.IssueList.issues\": \"Ärenden\",\n  \"components.IssueDetails.nocomments\": \"Inga kommentarer.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Ärendestatus uppdaterad!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Ärende borttaget!\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {avsnitt} other {avsnitt}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Status\",\n  \"components.IssueList.IssueItem.issuetype\": \"Typ\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Berört avsnitt\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Ärenderapport för <strong>{title}</strong> inskickad!\",\n  \"components.ManageSlideOver.tvshow\": \"serie\",\n  \"components.ManageSlideOver.openarr4k\": \"Öppna i 4K {arr}\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Rapportera ett problem\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Säsong {seasonNumber}\",\n  \"components.IssueModal.issueOther\": \"Övrigt\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Ge behörighet att hantera medieärenden.\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Något gick fel när ärendet skulle skickas.\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Skicka ärende\",\n  \"components.ManageSlideOver.movie\": \"film\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Vad är fel?\",\n  \"components.IssueModal.issueAudio\": \"Ljud\",\n  \"components.Layout.Sidebar.issues\": \"Ärenden\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Du måste ange en beskrivning\",\n  \"components.IssueModal.issueSubtitles\": \"Undertext\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Användar- eller gruppnyckel\",\n  \"components.ManageSlideOver.openarr\": \"Öppna i {arr}\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Hantera {mediaType}\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Markera som tillgänglig i 4K\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Få meddelanden när andra användare kommenterar ärenden.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Förfrågningar\",\n  \"components.PermissionEdit.manageissues\": \"Hantera ärenden\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Pushover-meddelandeinställningar kunde inte sparas.\",\n  \"components.ManageSlideOver.markavailable\": \"Markera som tillgänglig\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Ärendekommentar\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Skicka meddelanden när ärenden får nya kommentarer.\",\n  \"components.PermissionEdit.createissuesDescription\": \"Ge behörighet att skapa medieärenden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Din 30 tecken långa <UsersGroupsLink>användar- eller gruppidentifierare</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Registrera en applikation</ApplicationRegistrationLink> för användning med {applicationTitle}\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Ge behörighet att visa medieärenden skapade av andra användare.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Applikationens API-token\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover-meddelandeinställningar har sparats!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Du måste ange en giltig applikationstoken\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Du måste ange en giltig användar- eller gruppnyckel\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Berörd säsong\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Visa ärende\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Ärende skapat\",\n  \"components.PermissionEdit.createissues\": \"Skapa ärenden\",\n  \"components.PermissionEdit.viewissues\": \"Visa ärenden\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Detta kommer att ta bort all data för denna {mediaType} permanent, inklusive eventuella förfrågningar. Om detta objekt finns i ditt {mediaServerName}-bibliotek kommer mediainformationen att återskapas under nästa genomsökning.\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Inga förfrågningar.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Få meddelande när dina skapade ärenden har blivit lösta.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Åtkomsttoken\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Du måste ange en åtkomsttoken\",\n  \"components.IssueList.sortAdded\": \"Senaste\",\n  \"components.IssueList.sortModified\": \"Senast ändrat\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Alla avsnitt\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Alla säsonger\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Avsnitt {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Berört avsnitt\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Beskriv problemet i detalj.\",\n  \"components.ManageSlideOver.downloadstatus\": \"Nedladdningar\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Rensa data\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Skicka meddelanden när ärenden skapas.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Ärende löst\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Skicka meddelanden när ärenden blir lösta.\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Få meddelanden när ärenden du har skapat får nya kommentarer.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Få meddelanden när andra användare skapar ärenden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Skapa en token från dina <PushbulletSettingsLink>kontoinställningar</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Pushbullet-meddelandeinställningar kunde inte sparas.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet-meddelandeinställningar har sparats!\",\n  \"i18n.open\": \"Öppna\",\n  \"i18n.resolved\": \"Löst\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Öppna ärenden\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Extramaterial\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Få meddelanden när ärenden återöppnas av andra användare.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Ärende återöppnat\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Skicka meddelanden när ärenden återöppnas.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Få meddelanden när ärenden du har skapat återöppnas.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Få meddelanden när ärenden blir lösta av andra användare.\",\n  \"components.MovieDetails.productioncountries\": \"Produktions{countryCount, plural, one {land} other {länder}}\",\n  \"components.RequestModal.selectmovies\": \"Välj film(er)\",\n  \"components.IssueDetails.commentplaceholder\": \"Lägg till en kommentar…\",\n  \"components.RequestModal.approve\": \"Godkänn förfrågan\",\n  \"components.RequestModal.requestApproved\": \"Förfrågan för <strong>{title}</strong> godkänd!\",\n  \"components.RequestModal.requestmovies\": \"Begär {count} {count, plural, one {film} other {filmer}}\",\n  \"components.RequestModal.requestmovies4k\": \"Begär {count} {count, plural, one {film} other {filmer}} i 4K\",\n  \"components.RequestModal.requestseasons4k\": \"Begär {seasonCount} {seasonCount, plural, one {Säsong} other {Säsonger}} i 4K\",\n  \"components.Settings.RadarrModal.inCinemas\": \"På bio\",\n  \"components.Settings.RadarrModal.released\": \"Släppt\",\n  \"components.Settings.RadarrModal.announced\": \"Tillkännagiven\",\n  \"components.TvDetails.productioncountries\": \"Produktions{countryCount, plural, one {land} other {länder}}\",\n  \"components.Settings.Notifications.enableMentions\": \"Aktivera omnämnanden\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Aktivera Gotify\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify-meddelandeinställningar kunde inte sparas.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify-meddelandeinställningar har sparats!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify-testmeddelande kunde inte skickas.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Skickar testmeddelande via Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify-testmeddelande skickat!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Applikationstoken\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Server-URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Du måste ange en applikationstoken\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Du måste välja minst en meddelandetyp\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Du måste ange en giltig URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL:en får inte sluta med ett snedstreck\",\n  \"components.UserList.newplexsigninenabled\": \"Inställningen <strong>Aktivera ny Plex-inloggning</strong> är för närvarande aktiverad. Plex-användare med biblioteksåtkomst behöver inte importeras för att kunna logga in.\",\n  \"i18n.import\": \"Importera\",\n  \"i18n.importing\": \"Importerar…\",\n  \"components.ManageSlideOver.alltime\": \"Alla tider\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Avancerad\",\n  \"components.ManageSlideOver.playedby\": \"Spelad av\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Något gick fel när Tautulli-inställningarna skulle sparas.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Kanaltagg\",\n  \"components.Settings.urlBase\": \"URL-bas\",\n  \"components.Settings.validationApiKey\": \"Du måste ange en API-nyckel\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K-media\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Media\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Markera alla säsonger som tillgängliga i 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Markera alla säsonger som tillgängliga\",\n  \"components.ManageSlideOver.opentautulli\": \"Öppna i Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Senaste {days, number} dagarna\",\n  \"components.Settings.tautulliSettings\": \"Tautulli-inställningar\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli-inställningarna har sparats!\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL-basen måste ha ett inledande snedstreck\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {uppspelning} other {uppspelningar}}\",\n  \"components.Settings.validationUrl\": \"Du måste ange en giltig URL\",\n  \"components.Settings.externalUrl\": \"Extern URL\",\n  \"components.Settings.tautulliApiKey\": \"API-nyckel\",\n  \"components.Settings.tautulliSettingsDescription\": \"Valfritt: Konfigurera inställningarna för din Tautulli-server. Seerr hämtar visningshistorikdata för din Plex-media från Tautulli.\",\n  \"components.UserProfile.recentlywatched\": \"Nyligen sett\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"URL-basen får inte sluta med ett snedstreck\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL får inte sluta med ett snedstreck\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Du måste ange ett giltigt Discord användar-ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord användar-ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Det <FindDiscordIdLink>flersiffriga ID-numret</FindDiscordIdLink> som är kopplat till ditt Discord-användarkonto\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Datakatalog\",\n  \"components.RequestBlock.languageprofile\": \"Språkprofil\",\n  \"components.StatusChecker.reloadApp\": \"Ladda om {applicationTitle}\",\n  \"i18n.restartRequired\": \"Omstart krävs\",\n  \"components.Settings.deleteServer\": \"Radera {serverType}-instans\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} uppdaterad\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Klicka på knappen nedan för att ladda om applikationen.\",\n  \"components.StatusChecker.restartRequired\": \"Servern behöver startas om\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Starta om servern för att verkställa uppdaterade inställningar.\",\n  \"components.MovieDetails.digitalrelease\": \"Digital utgåva\",\n  \"components.MovieDetails.physicalrelease\": \"Fysisk utgåva\",\n  \"components.PermissionEdit.viewrecent\": \"Se nyligen tillagda\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Din bevakningslista\",\n  \"components.RequestCard.tmdbid\": \"TMDB-ID\",\n  \"components.Discover.plexwatchlist\": \"Din bevakningslista\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex bevakningslista\",\n  \"components.MovieDetails.reportissue\": \"Rapportera ett problem\",\n  \"components.AirDateBadge.airedrelative\": \"Sändes {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Sänds {relativeTime}\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Serieförfrågningar\",\n  \"components.RequestCard.approverequest\": \"Godkänn förfrågan\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB-ID\",\n  \"components.RequestBlock.approve\": \"Godkänn förfrågan\",\n  \"components.RequestBlock.decline\": \"Neka förfrågan\",\n  \"components.RequestBlock.delete\": \"Ta bort förfrågan\",\n  \"components.RequestBlock.edit\": \"Redigera förfrågan\",\n  \"components.RequestBlock.lastmodifiedby\": \"Senast ändrad av\",\n  \"components.RequestCard.declinerequest\": \"Neka förfrågan\",\n  \"components.RequestCard.cancelrequest\": \"Avbryt förfrågan\",\n  \"components.MovieDetails.theatricalrelease\": \"Biopremiär\",\n  \"components.PermissionEdit.autorequest\": \"Automatisk förfrågan\",\n  \"components.MovieDetails.managemovie\": \"Hantera film\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Filmförfrågningar\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes publiksiffror\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB-användarbetyg\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Förfrågan automatiskt skickad\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Få meddelanden när nya medieförfrågningar automatiskt skickas för objekt på din bevakningslista.\",\n  \"components.Discover.emptywatchlist\": \"Media som lagts till i din <PlexWatchlistSupportLink>Plex bevakningslista</PlexWatchlistSupportLink> visas här.\",\n  \"components.Layout.UserDropdown.requests\": \"Förfrågningar\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# avsnitt} other {# avsnitt}}\",\n  \"components.TvDetails.seasonstitle\": \"Säsonger\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Rensning av bildcache\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Bildcache\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Bilder cachade\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Total cache-storlek\",\n  \"components.Settings.experimentalTooltip\": \"Att aktivera denna inställning kan orsaka oväntade problem i applikationen\",\n  \"components.TitleCard.tmdbid\": \"TMDB-ID\",\n  \"components.PermissionEdit.autorequestDescription\": \"Ge behörighet att automatiskt skicka in förfrågningar för media som inte är 4K via Plex bevakningslista.\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Ge behörighet att automatiskt skicka in förfrågningar för serier som inte är 4K via Plex bevakningslista.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Automatisk förfrågan för serier\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB-ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB-ID\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Synkronisering av bevakningslista från Plex\",\n  \"components.Settings.advancedTooltip\": \"Om du konfigurerar den här inställningen felaktigt kan det leda till att saker inte fungerar korrekt\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr måste startas om för att ändringar som rör den här inställningen ska träda i kraft\",\n  \"components.TvDetails.reportissue\": \"Rapportera ett problem\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Automatisk förfrågan för serier\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Begär automatiskt serier på din <PlexWatchlistSupportLink>Plex bevakningslista</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Begär automatiskt filmer på din <PlexWatchlistSupportLink>Plex bevakningslista</PlexWatchlistSupportLink>\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Aktuell frekvens\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Ge behörighet att visa listan över nyligen tillagd media.\",\n  \"components.StatusBadge.managemedia\": \"Hantera {mediaType}\",\n  \"components.StatusBadge.playonplex\": \"Spela upp på {mediaServerName}\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB-ID\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Visa detaljer\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"När aktiverat i inställningarna kommer Seerr att använda proxy för och cachelagra bilder från förkonfigurerade externa källor. Cachelagrade bilder sparas i din konfigurationsmapp. Du hittar filerna i <code>{appDataPath}/cache/images</code>.\",\n  \"components.TitleCard.cleardata\": \"Rensa data\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} hittades inte\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB-användarbetyg\",\n  \"components.UserProfile.emptywatchlist\": \"Media som lagts till i din <PlexWatchlistSupportLink>Plex bevakningslista</PlexWatchlistSupportLink> visas här.\",\n  \"components.UserProfile.plexwatchlist\": \"Plex bevakningslista\",\n  \"components.TvDetails.Season.noepisodes\": \"Avsnittslistan är inte tillgänglig.\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Ge behörighet till att visa andra användares {mediaServerName} bevakningslistor.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Automatisk förfrågan för filmer\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Ge behörighet att automatiskt skicka in förfrågningar för filmer som inte är 4K via Plex bevakningslista.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Visa {mediaServerName} bevakningslista\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Vi kunde inte hitta någon matchning för denna serie.\",\n  \"components.RequestBlock.requestdate\": \"Datum för förfrågan\",\n  \"components.RequestBlock.requestedby\": \"Förfrågan av\",\n  \"components.RequestCard.editrequest\": \"Redigera förfrågan\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Begär samling i 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Begär samling\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Begär film i 4K\",\n  \"components.RequestModal.requestmovietitle\": \"Begär film\",\n  \"components.RequestModal.requestseries4ktitle\": \"Begär serie i 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Begär serie\",\n  \"components.StatusBadge.openinarr\": \"Öppna i {arr}\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Något gick fel när säsongsdata hämtades.\",\n  \"components.TvDetails.manageseries\": \"Hantera serie\",\n  \"components.TvDetails.rtaudiencescore\": \"Rotten Tomatoes Audience Score\",\n  \"components.TvDetails.seasonnumber\": \"Säsong {seasonNumber}\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Automatisk förfrågan för filmer\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmer\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popularitet stigande\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Serier\",\n  \"components.Discover.CreateSlider.nooptions\": \"Inga resultat.\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Sök studio…\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Skapa anpassat bläddringsfält\",\n  \"components.Discover.CreateSlider.addfail\": \"Det gick inte att skapa nytt bläddringsfält.\",\n  \"components.Discover.CreateSlider.addSlider\": \"Lägg till bläddringsfält\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Ange en sökfråga\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Du måste ange ett namn.\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Växla synlighet\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Rensa aktiva filter\",\n  \"components.Discover.FilterSlideover.genres\": \"Genrer\",\n  \"components.Discover.FilterSlideover.filters\": \"Filter\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Första sändningsdatum\",\n  \"components.Discover.FilterSlideover.from\": \"Från\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle}-filmer\",\n  \"components.Discover.moviegenres\": \"Filmgenrer\",\n  \"components.Discover.networks\": \"Nätverk\",\n  \"components.Settings.SettingsMain.apikey\": \"API-nyckel\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Applikationstitel\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Applikations-URL\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Dölj tillgänglig media\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Något gick fel när inställningarna skulle sparas.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Inställningarna har sparats!\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Du måste ange en applikationstitel\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Du måste ange en giltig URL\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB-filmstreamingtjänster\",\n  \"components.Discover.tmdbnetwork\": \"TMDB-nätverk\",\n  \"components.Discover.tmdbsearch\": \"TMDB-sök\",\n  \"components.Discover.tmdbstudio\": \"TMDB-studio\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB-seriegenre\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB-serienyckelord\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB-seriestreamingtjänster\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmer\",\n  \"components.Layout.Sidebar.browsetv\": \"Serier\",\n  \"components.Selector.searchKeywords\": \"Söknyckelord…\",\n  \"components.Selector.nooptions\": \"Inga resultat.\",\n  \"components.Selector.searchGenres\": \"Välj genrer…\",\n  \"components.Selector.searchStudios\": \"Sök studior…\",\n  \"components.Selector.showmore\": \"Visa mer\",\n  \"components.Selector.starttyping\": \"Börja skriva för att söka.\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Synkronisering av mediatillgänglighet\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Aktivera bildcachelagring\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Cachelagring av bilder från externa källor (kräver en betydande mängd diskutrymme)\",\n  \"components.Settings.SettingsMain.general\": \"Allmänt\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Allmänna inställningar\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Konfigurera globala och standardinställningar för Seerr.\",\n  \"components.Settings.SettingsMain.locale\": \"Visningsspråk\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Språk för Upptäck\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Filtrera innehållet efter originalspråk\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Tillåt partiella serieförfrågningar\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Något gick fel när API-nyckeln skulle genereras.\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Ny API-nyckel genererades!\",\n  \"components.Discover.resetwarning\": \"Återställer alla bläddringsfält till standard. Detta raderar också alla användarskapade fält!\",\n  \"components.Discover.stopediting\": \"Sluta redigera\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB-filmgenre\",\n  \"components.Discover.studios\": \"Studior\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB-filmnyckelord\",\n  \"components.Discover.tvgenres\": \"Seriegenrer\",\n  \"components.Discover.updatesuccess\": \"Anpassningsinställningarna för Upptäck har uppdaterats.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Varje {jobScheduleSeconds, plural, one {sekund} other {{jobScheduleSeconds} sekunder}}\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL får inte sluta med ett snedstreck\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# aktivt filter} other {# aktiva filter}}\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popularitet fallande\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Utgivningsdatum stigande\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Utgivningsdatum fallande\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Titel stigande\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Titel fallande\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB-betyg stigande\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB-betyg fallande\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Det gick inte att ta bort bläddringsfältet.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Bläddringsfältet har tagits bort.\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Ta bort\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# aktivt filter} other {# aktiva filter}}\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Första sändningsdatum stigande\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Första sändningsdatum fallande\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popularitet stigande\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popularitet fallande\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Titel stigande\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Titel fallande\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB-betyg stigande\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB-betyg fallande\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle}-serier\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# aktivt filter} other {# aktiva filter}}\",\n  \"components.Discover.FilterSlideover.keywords\": \"Nyckelord\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Originalspråk\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Betyg mellan {minValue} och {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Utgivningsdatum\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} minuters speltid\",\n  \"components.Discover.FilterSlideover.runtime\": \"Speltid\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB-användarbetyg\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Media som lagts till i din <PlexWatchlistSupportLink>Plex bevakningslista</PlexWatchlistSupportLink> visas här.\",\n  \"components.Discover.resetsuccess\": \"Anpassningarna för Upptäck har återställts.\",\n  \"components.Discover.resettodefault\": \"Återställ till standardinställningar\",\n  \"components.Discover.updatefailed\": \"Något gick fel när inställningarna för anpassning av Upptäck skulle uppdateras..\",\n  \"components.DownloadBlock.formattedTitle\": \"{titel}: säsong {seasonNumber}, avsnitt {episodeNumber}\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.RequestCard.unknowntitle\": \"Okänd titel\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Okänd titel\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Streamingtjänster\",\n  \"components.Discover.FilterSlideover.studio\": \"Studio\",\n  \"components.Discover.FilterSlideover.to\": \"Till\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Din bevakningslista\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Nyligen tillagda\",\n  \"components.Discover.createnewslider\": \"Skapa nytt bläddringsfält\",\n  \"components.Discover.customizediscover\": \"Anpassa Upptäck\",\n  \"components.Discover.resetfailed\": \"Något gick fel när anpassningarna för Upptäck skulle återställas.\",\n  \"components.Selector.showless\": \"Visa mindre\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Skapade nytt bläddringsfält och sparade inställningarna för anpassning av Upptäck.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Redigera bläddringsfält\",\n  \"components.Discover.CreateSlider.editfail\": \"Det gick inte att redigera bläddringsfältet.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Redigerat bläddringsfält och sparade inställningarna för anpassning av Upptäck.\",\n  \"components.Discover.CreateSlider.needresults\": \"Du måste ha minst 1 resultat.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Ange ett TMDB Genre-ID\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Ange ett TMDB nyckelords-ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Ange TMDB nätverks-ID\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Ange TMDB Studio-ID\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Sök genre…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Sökord…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Bläddringsfältets namn\",\n  \"components.Discover.CreateSlider.starttyping\": \"Börja skriva för att söka.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Du måste ange ett datavärde.\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Antal röster från TMDB-användare\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Antal röster mellan {minValue} och {maxValue}\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Tagga förfrågningar\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB-användarbetyg – röster: {formattedCount}\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Tagga förfrågningar\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Lägg automatiskt till en extra tagg med användarens ID och visningsnamn för den som gjort förfrågan\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Lägg automatiskt till en extra tagg med användarens ID och visningsnamn för den som gjort förfrågan\",\n  \"i18n.collection\": \"Samling\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Lösenord krävs.\",\n  \"components.Login.description\": \"Eftersom det här är första gången du loggar in på {applicationName}, krävs det att en giltig e-postadress läggs till.\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Ogiltig e-postadress.\",\n  \"components.Login.initialsignin\": \"Anslut\",\n  \"components.Login.initialsigningin\": \"Ansluter…\",\n  \"components.Login.save\": \"Lägg till\",\n  \"components.Login.saving\": \"Lägger till…\",\n  \"components.Login.signinwithjellyfin\": \"Använd ditt {mediaServerName}-konto\",\n  \"components.Login.title\": \"Lägg till e-postadress\",\n  \"components.Login.username\": \"Användarnamn\",\n  \"components.Login.validationEmailFormat\": \"Ogiltig e-postadress\",\n  \"components.Login.validationemailformat\": \"Giltig e-postadress krävs\",\n  \"components.Login.validationhostformat\": \"Giltig URL krävs\",\n  \"components.Login.validationhostrequired\": \"URL för {mediaServerName} krävs\",\n  \"components.Login.validationusernamerequired\": \"Användarnamn krävs\",\n  \"components.ManageSlideOver.removearr4k\": \"Ta bort från 4K {arr}\",\n  \"components.MovieDetails.downloadstatus\": \"Nedladdningsstatus\",\n  \"components.MovieDetails.openradarr\": \"Öppna film i Radarr\",\n  \"components.MovieDetails.openradarr4k\": \"Öppna film i 4K Radarr\",\n  \"components.MovieDetails.play4k\": \"Spela upp i 4K på {mediaServerName}\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Meddelandeljud\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName}-inställningar\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName}-inställningar\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Något gick fel när {mediaServerName}-inställningarna sparades.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName}-inställningarna sparades!\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName}-bibliotek\",\n  \"components.Settings.manualscanJellyfin\": \"Manuell biblioteksskanning\",\n  \"components.Settings.save\": \"Spara ändringar\",\n  \"components.Settings.saving\": \"Sparar…\",\n  \"components.Settings.syncing\": \"Synkroniserar\",\n  \"components.Settings.timeout\": \"Timeout\",\n  \"components.Setup.signin\": \"Logga in\",\n  \"components.Setup.signinWithPlex\": \"Ange dina uppgifter för Plex\",\n  \"components.TitleCard.addToWatchList\": \"Lägg till i bevakningslistan\",\n  \"components.TitleCard.watchlistCancel\": \"Bevakningslista för <strong>{title}</strong> avbruten.\",\n  \"components.TitleCard.watchlistError\": \"Något gick fel. Försök igen.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong>  har lagts till i bevakningslistan!\",\n  \"components.TvDetails.play4k\": \"Spela upp i 4K på {mediaServerName}\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName}-användare\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Det finns inga {mediaServerName}-användare att importera.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Spara ändringar\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Sparar…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Meddelandeljud\",\n  \"components.Login.credentialerror\": \"Användarnamnet eller lösenordet är felaktigt.\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Detta kommer oåterkalleligt att ta bort denna {mediaType} från {arr}, inklusive alla filer.\",\n  \"components.ManageSlideOver.removearr\": \"Ta bort från {arr}\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Konfigurera inställningarna för din {mediaServerName}-server. {mediaServerName} skannar dina {mediaServerName}-bibliotek för att se vilket innehåll som är tillgängligt.\",\n  \"components.UserList.importfromJellyfin\": \"Importera {mediaServerName}-användare\",\n  \"components.Layout.UserWarnings.emailRequired\": \"En e-postadress krävs.\",\n  \"components.Login.emailtooltip\": \"Adressen behöver inte vara kopplad till din {mediaServerName}-instans.\",\n  \"components.Login.validationEmailRequired\": \"Du måste ange en e-postadress\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"{mediaServerName}-biblioteken skannas efter titlar. Klicka på knappen nedan om inga bibliotek visas.\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Enhetsstandard\",\n  \"components.Settings.SonarrModal.seriesType\": \"Serie-typ\",\n  \"components.Setup.signinWithJellyfin\": \"Ange dina uppgifter för Jellyfin\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> har tagits bort från bevakningslistan!\",\n  \"components.TvDetails.play\": \"Spela upp på {mediaServerName}\",\n  \"components.UserList.importfromJellyfinerror\": \"Något gick fel när {mediaServerName}-användare skulle importeras.\",\n  \"components.UserList.newJellyfinsigninenabled\": \"Inställningen <strong>Aktivera ny {mediaServerName}-inloggning</strong> är för närvarande aktiverad. {mediaServerName}-användare med biblioteksåtkomst behöver inte importeras för att kunna logga in.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName}-användare\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Enhetens standard\",\n  \"components.MovieDetails.play\": \"Spela upp på {mediaServerName}\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalt kommer detta endast att köras en gång var 24:e timme. Seerr kommer att kontrollera din {mediaServerName}-servers nyligen tillagda innehåll mer intensivt. Om detta är första gången du konfigurerar Seerr, rekommenderas en engångsskanning av hela biblioteket!\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.syncJellyfin\": \"Synkronisera bibliotek\",\n  \"components.Setup.configuremediaserver\": \"Konfigurera Media Server\",\n  \"components.UserProfile.localWatchlist\": \"Bevakningslista för {username}\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Kräv användarens e-postadress\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-post\",\n  \"components.Login.back\": \"Gå tillbaka\",\n  \"components.Login.hostname\": \"{mediaServerName}-URL\",\n  \"components.Login.invalidurlerror\": \"Kunde inte ansluta till {mediaServerName} server.\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.servertype\": \"Typ av server\",\n  \"components.Login.urlBase\": \"Bas-URL\",\n  \"components.Login.validationPortRequired\": \"Du måste ange ett giltigt portnummer\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"URL-basen måste börja med ett snedstreck\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"URL-basen får inte sluta med ett avslutande snedstreck\",\n  \"components.Login.adminerror\": \"Du måste använda ett administratörskonto för att logga in.\",\n  \"components.Login.enablessl\": \"Använd SSL\",\n  \"components.Discover.FilterSlideover.status\": \"Status\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Kommande serier\",\n  \"components.Selector.inProduction\": \"Under produktion\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Specificerar villkor innan parameterändringar tillämpas. Varje fält måste valideras för att reglerna ska tillämpas (AND-operation). Ett fält anses vara verifierat om någon av dess egenskaper matchar (OR-operation).\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Anime-serietyp\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Något gick fel vid synkronisering av bibliotek\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Ange dina uppgifter för {mediaServerName} för att länka med {applicationName}.\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Du måste ange ett giltigt Discord-roll-ID\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Åsidosättningsregel uppdaterad!\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Du har inte några externa konton länkade till ditt konto.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Tråd-/ämnes-ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"Tråd-/ämnes-ID måste vara ett positivt heltal\",\n  \"components.Selector.canceled\": \"Avbruten\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"Tråd-/ämnes-ID måste vara ett positivt heltal\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Anger vilka inställningar som kommer att ändras när ovanstående villkor uppfylls.\",\n  \"components.Setup.configjellyfin\": \"Konfigurera Jellyfin\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Filtrera innehåll efter regional tillgänglighet\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"En annan användare har detta användarnamn. Du måste ange en e-postadress\",\n  \"components.Setup.librarieserror\": \"Valideringen misslyckades. För att fortsätta, slå av/på biblioteken igen.\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Tvinga Seerr att använda IPv4-adresser först, istället för IPv6\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Inställningarna sparade!\",\n  \"components.UserList.validationUsername\": \"Du måste ange ett användarnamn\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> togs bort från bevakningslistan!\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Konfigurera nätverksinställningar för din Seerr-instans.\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Tillåt Seerr att korrekt registrera klienters IP-adresser när Seerr körs bakom en proxy\",\n  \"components.Settings.apiKey\": \"API-nyckel\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Streamingregion\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Om din gruppchatt har ämnen aktiverade kan du ange ett tråd-/ämnes-ID här\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Valfritt: Konfigurera de interna och externa slutpunkterna för din {mediaServerName}-server. I de flesta fall skiljer sig den externa URL:en från den interna URL:en. En anpassad URL för återställning av lösenord kan också anges för {mediaServerName}-inloggning, om du vill omdirigera till en annan återställningssida för lösenord. Du kan även ändra API-nyckeln som tidigare genererades.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> har lagts till i bevakningslistan!\",\n  \"components.RequestList.RequestItem.profileName\": \"Profil\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Regioner för Upptäck\",\n  \"components.Login.loginwithapp\": \"Logga in med {appName}\",\n  \"components.Login.noadminerror\": \"Ingen användare med adminrättigheter hittades på servern.\",\n  \"components.Login.orsigninwith\": \"eller logga in med\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL får inte sluta med ett avslutande snedstreck\",\n  \"components.Login.validationservertyperequired\": \"Välj typ av server\",\n  \"components.MovieDetails.addtowatchlist\": \"Lägg till i bevakningslistan\",\n  \"components.MovieDetails.watchlistError\": \"Något gick fel. Försök igen.\",\n  \"components.MovieDetails.removefromwatchlist\": \"Ta bort från bevakningslistan\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> har lagts till i bevakningslistan!\",\n  \"components.RequestList.RequestItem.removearr\": \"Ta bort från {arr}\",\n  \"components.RequestList.sortDirection\": \"Växla sorteringsordning\",\n  \"components.Selector.ended\": \"Avslutad\",\n  \"components.Selector.pilot\": \"Pilot\",\n  \"components.Selector.planned\": \"Planerad\",\n  \"components.Selector.returningSeries\": \"Återkommande serie\",\n  \"components.Selector.searchStatus\": \"Välj status...\",\n  \"components.Selector.searchUsers\": \"Välj användare…\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Villkor\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Om din gruppchatt har ämnen aktiverade kan du ange ett tråd-/ämnes-ID här\",\n  \"components.Settings.Notifications.messageThreadId\": \"Tråd-/ämnes-ID\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Meddelanderoll-ID\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"Roll-ID att nämna i webhookmeddelandet. Lämna tomt för att inaktivera omnämnanden\",\n  \"components.Settings.OverrideRuleModal.create\": \"Skapa regel\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Ny åsidosättningsregel\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Redigera åsidosättningsregel\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Genrer\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Nyckelord\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Språk\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Inga taggar.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Rotmapp\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Åsidosättningsregel skapad!\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Välj kvalitetsprofil\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Välj rotmapp\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Välj tjänst\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Välj taggar\",\n  \"components.Settings.OverrideRuleModal.service\": \"Tjänst\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Tillämpa denna regel på den valda tjänsten.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Inställningar\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Taggar\",\n  \"components.Settings.OverrideRuleModal.users\": \"Användare\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Villkor\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Genre\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Nyckelord\",\n  \"components.Settings.OverrideRuleTile.language\": \"Språk\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Kvalitetsprofil\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Rotmapp\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Inställningar\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Taggar\",\n  \"components.Settings.OverrideRuleTile.users\": \"Användare\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex uppdateringstoken\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Användarnas avatarer\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Filtrera innehåll efter regional tillgänglighet\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Tillåt förfrågningar om specialavsnitt\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Streamingregion\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Visa streamingtjänster efter regional tillgänglighet\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Aktivera CSRF-skydd\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"Aktivera INTE denna inställning om du inte vet vad du gör!\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Ställ in skrivskyddad åtkomst till externt API (kräver HTTPS)\",\n  \"components.Settings.SettingsNetwork.docs\": \"dokumentation\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Tvinga IPv4 först\",\n  \"components.Settings.SettingsNetwork.network\": \"Nätverk\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Nätverksparametrar från container/system bör användas istället för dessa inställningar. Se {docs} för mer information.\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Nätverksinställningar\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Adresser som ignoreras av proxyn\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Använd ',' som avgränsare och '*.' som jokertecken för subdomäner\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Kringgå proxy för lokala adresser\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S)-proxy\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Proxy-värdnamn\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Proxy-lösenord\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Proxy-port\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Använd SSL för proxy\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Proxy-användarnamn\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Något gick fel när inställningarna skulle sparas.\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Aktivera proxystöd\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Du måste ange en giltig port\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Inloggningsmetoder\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Minst en inloggningsmetod måste väljas.\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Konfigurera inloggningsmetoder för användare.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Aktivera inloggning för {mediaServerName}\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Tillåt användare att logga in med sitt {mediaServerName}-konto\",\n  \"components.Settings.addrule\": \"Ny åsidosättningsregel\",\n  \"components.Settings.invalidurlerror\": \"Kunde inte ansluta till {mediaServerName}-server.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Glömt-lösenord-URL\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Inga bibliotek hittades\",\n  \"components.Settings.menuNetwork\": \"Nätverk\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Anpassad inloggning stöds inte med automatisk gruppering av mappar\",\n  \"components.Settings.overrideRules\": \"Åsidosättningsregler\",\n  \"components.Settings.overrideRulesDescription\": \"Åsidosättningsregler låter dig specificera egenskaper som kommer att ersättas om en förfråga matchar regeln.\",\n  \"components.Settings.scanbackground\": \"Skanningen kommer att köras i bakgrunden. Du kan fortsätta med installationen under tiden.\",\n  \"components.Settings.tip\": \"Tips\",\n  \"components.Setup.back\": \"Gå tillbaka\",\n  \"components.Setup.configemby\": \"Konfigurera Emby\",\n  \"components.Setup.configplex\": \"Konfigurera Plex\",\n  \"components.Setup.servertype\": \"Välj servertyp\",\n  \"components.Setup.signinWithEmby\": \"Ange dina uppgifter för Emby\",\n  \"components.Setup.subtitle\": \"Börja genom att välja din mediaserver\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> togs bort från bevakningslistan!\",\n  \"components.TvDetails.watchlistError\": \"Något gick fel. Försök igen.\",\n  \"components.TvDetails.addtowatchlist\": \"Lägg till i bevakningslistan\",\n  \"components.TvDetails.removefromwatchlist\": \"Ta bort från bevakningslistan\",\n  \"components.UserList.username\": \"Användarnamn\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Detta konto är redan länkat till en {applicationName}-användare\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Kunde inte ansluta till {mediaServerName} med dina uppgifter\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Ett okänt fel uppstod\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Lösenord\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Du måste ange ett lösenord\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Länka\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Lägger till…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Länka {mediaServerName}-konto\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Användarnamn\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Du måste ange ett användarnamn\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Region för Upptäck\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Visa streamingtjänster efter regional tillgänglighet\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Denna e-postadress används redan!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Giltig e-postadress krävs\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"E-postadress krävs\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Kunde inte radera länkat konto.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Ett okänt fel uppstod\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Länkade konton\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Dessa externa konton är länkade till ditt {applicationName}-konto.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Du har inte behörighet till att ändra denna användares länkade konton.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Detta konto är redan länkat till ett Plex-konto\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Kunde inte ansluta till Plex med dina uppgifter\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Länkade konton\",\n  \"i18n.specials\": \"Specialare\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {användare} other {användare}} importerade!\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Problembeskrivning\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Välj en metadataleverantör\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"DNS-cache\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Du måste ange en giltig URL\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Det gick inte att ladda certifieringarna\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Börja skriva för att söka.\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Användarnamn + lösenordsautentisering\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Seerr cachar DNS-sökningar för att optimera prestanda och undvika onödiga API-anrop.\",\n  \"components.Settings.SettingsJobsCache.size\": \"Storlek\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"Min TTL för DNS-cache\",\n  \"components.Discover.FilterSlideover.certification\": \"Innehållsklassificering\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Exkludera nyckelord\",\n  \"components.Selector.CertificationSelector.minRating\": \"Lägsta betyg\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Inga alternativ tillgängliga\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Välj en certifiering\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Välj ett land\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Prioritet\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Du måste ange ett prioritetsnummer\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Bädda in affischer\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Lösenord\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Token\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Ämne\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Användarnamn\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Du måste ange ett ämne\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Du måste ange en giltig URL\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Du måste välja minst en meddelandetyp\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Denna statistik aggregeras över alla DNS-cacheposter.\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Aktiv adress\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Ålder\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Träffar\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Missar\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Värdnamn\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Träffratio\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Träffar\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"Kopierade API-nyckel till urklipp.\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"Max TTL för DNS-cache\",\n  \"i18n.deleted\": \"Raderad\",\n  \"i18n.completed\": \"Slutförd\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Högsta betyg\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Aktivera agent\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Global DNS-cachestatus\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube-URL\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"DNS-cache\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Ntfy-meddelandeinställningar kunde inte sparas.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Ntfy-meddelandeinställningar har sparats!\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Ntfy-testmeddelande kunde inte skickas.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Skickar testmeddelande via ntfy…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Ntfy-testmeddelande skickat!\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Tokenbaserad autentisering\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Stödda URL-variabler\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"Testmeddelandets URL är inställd på {testUrl} i stället för den faktiska webhook-URL:en.\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Bädda in affisch\",\n  \"components.Settings.Notifications.embedPoster\": \"Bädda in affisch\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"Bas-URL för YouTube-videor om en självhostad YouTube-instans används.\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"Aktivera INTE detta om du upplever problem med DNS-uppslag\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Aktivera cachelagring av DNS-uppslag för att optimera prestanda och undvika onödiga API-anrop\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Alla valda metadata-leverantörer fungerar\",\n  \"components.Settings.animeMetadataProvider\": \"Metadataleverantör för anime\",\n  \"components.Settings.chooseProvider\": \"Välj metadataleverantörer för olika innehållstyper\",\n  \"components.Settings.clickTest\": \"Klicka på ”Test” för att kontrollera anslutningen till metadataleverantörerna\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Det gick inte att spara inställningarna för metadataleverantörer\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} är inte ett TMDB-nyckelord.\",\n  \"components.Settings.menuMetadataProviders\": \"Metadataleverantörer\",\n  \"components.Settings.metadataProviderSelection\": \"Val av metadataleverantörer\",\n  \"components.Settings.metadataProviderSettings\": \"Metadataleverantörer\",\n  \"components.Settings.metadataSettings\": \"Inställningar för metadataleverantör\",\n  \"components.Settings.metadataSettingsSaved\": \"Inställningarna för metadataleverantörer har sparats\",\n  \"components.Settings.noSpecialCharacters\": \"Konfigurationen måste vara en kommaseparerad lista med TMDB-nyckelords-ID:n och får inte börja eller sluta med ett kommatecken.\",\n  \"components.Settings.providerStatus\": \"Status för metadataleverantörer\",\n  \"components.Settings.seriesMetadataProvider\": \"Metadataleverantör för serier\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"TMDB-leverantören fungerar inte, välj en annan metadataleverantör\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"TVDB-leverantören fungerar inte, välj en annan metadataleverantör\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Inaktivera web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Något gick fel när web push skulle inaktiveras.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Aktivera web push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Något gick fel när web push skulle aktiveras.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Motor\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"Du har inga web push-prenumerationer att visa.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Något gick fel när användarens prenumeration skulle tas bort.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Web push har inaktiverats.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Web push har aktiverats.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Det gick inte att spara inställningarna för web push-meddelanden.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Inställningarna för web push-meddelanden har sparats!\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Serverns root URL\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Integrerad affisch\",\n  \"components.Settings.settings\": \"Inställningar\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Enhet\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Integrera affisch\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Tillgängliga variabler finns dokumenterade i webhook avsnittet om \\\"Template variables\\\"\",\n  \"components.Settings.connectionTestFailed\": \"Kunde inte ansluta\",\n  \"components.Settings.operational\": \"Fungerar\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Operativsystem\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"{hostname} dns cache rensat.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Varje {jobScheduleDays, plural, one {dag} other {{jobScheduleDays} dagar}}\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Misslyckanden\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Rensa DNS cache\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"IPv4-reserv\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Missar\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Dölj tillgänglig media från Upptäck-sidan men inte från sökresultat\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URL kan inte sluta med ett snedstreck\",\n  \"components.Settings.failed\": \"Fungerar inte\",\n  \"components.Settings.general\": \"Allmänt\",\n  \"components.Settings.no\": \"Nej\",\n  \"components.Settings.nooptions\": \"Inga resultat.\",\n  \"components.Settings.notTested\": \"Har inte testats\",\n  \"components.Settings.searchKeywords\": \"Sök efter nyckelord…\",\n  \"components.Settings.starttyping\": \"Börja skriva för att söka.\",\n  \"components.Settings.valueRequired\": \"Du måste ange ett värde.\",\n  \"components.Settings.yes\": \"Ja\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Webbläsare\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Skapad\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Ta bort prenumeration\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Hantera enheter\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Tog bort prenumerationer.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"typ\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Okänd\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"Om Seerr\",\n  \"components.Settings.SettingsAbout.contribute\": \"Bidra\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"Stötta Seerr\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"Du måste ange ett giltigt maximalt TTL-värde\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"Du måste ange ett giltigt minimalt TTL-värde\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"Aktiv prenumeration\",\n  \"i18n.removefromBlocklist\": \"Ta bort från blocklistan\",\n  \"component.BlocklistBlock.blocklistdate\": \"Blockeringsdatum\",\n  \"component.BlocklistBlock.blocklistedby\": \"Blockerad av\",\n  \"component.BlocklistModal.blocklisting\": \"Blockering\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> finns inte i blocklistan.\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"Hantera blockerade medier.\",\n  \"components.Blocklist.blocklistdate\": \"datum\",\n  \"components.Blocklist.blocklistedby\": \"{date} av {user}\",\n  \"components.Blocklist.blocklistsettings\": \"Blocklistinställningar\",\n  \"components.Blocklist.filterBlocklistedTags\": \"Blockerade taggar\",\n  \"components.Blocklist.filterManual\": \"Manuell\",\n  \"components.Blocklist.mediaName\": \"Namn\",\n  \"components.Blocklist.mediaTmdbId\": \"tmdb-id\",\n  \"components.Blocklist.mediaType\": \"Typ\",\n  \"components.Blocklist.showAllBlocklisted\": \"Visa alla blockerade medier\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"Kunde inte ansluta till {services}. Viss information kan vara otillgänglig.\",\n  \"components.Layout.Sidebar.blocklist\": \"Blocklista\",\n  \"components.PermissionEdit.blocklistedItems\": \"Blockera medier.\",\n  \"components.PermissionEdit.blocklistedItemsDescription\": \"Ge behörighet att blockera medier.\",\n  \"components.PermissionEdit.manageblocklist\": \"Hantera blocklista\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"Ge behörighet att hantera blockerade medier.\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"Visa blockerade medier.\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"Ge behörighet att visa blockerade medier.\",\n  \"components.RequestList.unableToConnect\": \"Kan inte ansluta till {services}. Viss information kan vara otillgänglig.\",\n  \"components.Settings.SettingsJobsCache.dnsNoCacheEntries\": \"Inga DNS-uppslag har cachelagrats ännu.\",\n  \"components.Settings.SettingsJobsCache.process-blocklisted-tags\": \"Bearbeta blockerade taggar\",\n  \"components.Settings.SettingsMain.blocklistedTags\": \"Blockera innehåll med taggar\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimit\": \"Begränsa blockerat innehåll per tagg\",\n  \"components.Settings.SettingsMain.blocklistedTagsLimitTip\": \"Jobbet ”Bearbeta blockerade taggar” blockerar så här många sidor i varje sortering. Högre värden ger en mer exakt blocklista, men använder mer lagringsutrymme.\",\n  \"components.Settings.SettingsMain.blocklistedTagsTip\": \"Lägg automatiskt till innehåll med taggar i blocklistan med hjälp av jobbet ”Bearbeta blockerade taggar”\",\n  \"components.Settings.SettingsMain.hideBlocklisted\": \"Dölj blockerade objekt\",\n  \"components.Settings.SettingsMain.hideBlocklistedTip\": \"Dölj blockerade objekt i Upptäck för alla användare med behörigheten ”Hantera blocklista”\",\n  \"components.Settings.SettingsNetwork.proxyEnabledTip\": \"Skicka ALLA utgående HTTP-/HTTPS-förfrågningar via en proxyserver (värd/port). Detta aktiverar INTE HTTPS, SSL eller certifikatkonfiguration.\",\n  \"components.Settings.blocklistedTagImportInstructions\": \"Klistra in konfigurationen för taggar i blocklistan nedan.\",\n  \"components.Settings.blocklistedTagImportTitle\": \"Importera konfiguration för taggar i blocklistan\",\n  \"components.Settings.blocklistedTagsText\": \"Blockerade taggar\",\n  \"components.Settings.clearBlocklistedTagsConfirm\": \"Är du säker på att du vill rensa taggarna i blocklistan?\",\n  \"components.Settings.copyBlocklistedTags\": \"Blockerade taggar har kopierats till urklipp.\",\n  \"components.Settings.copyBlocklistedTagsEmpty\": \"Inget att kopiera\",\n  \"components.Settings.copyBlocklistedTagsTip\": \"Kopiera konfiguration av blockerade taggar\",\n  \"components.Settings.importBlocklistedTagsTip\": \"Importera konfiguration av blockerade taggar\",\n  \"i18n.addToBlocklist\": \"Lägg till i blocklistan\",\n  \"i18n.blocklist\": \"Blocklista\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> finns redan i blocklistan.\",\n  \"i18n.blocklistError\": \"Något gick fel. Försök igen.\",\n  \"i18n.blocklistSuccess\": \"<strong>{title}</strong> har lagts till i blocklistan.\",\n  \"i18n.blocklisted\": \"Blockerad\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> har tagits bort från blocklistan.\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeout\": \"Tidsgräns för API-förfrågningar\",\n  \"components.Settings.SettingsNetwork.apiRequestTimeoutTip\": \"Maximal tid (i sekunder) att vänta på svar från externa tjänster som Radarr och Sonarr. Ange 0 för ingen tidsgräns.\",\n  \"components.Settings.SettingsNetwork.validationApiRequestTimeout\": \"Du måste ange ett giltigt värde för tidsgränsen\",\n  \"components.Settings.SonarrModal.monitorNewItems\": \"Bevaka nya säsonger\",\n  \"components.Settings.Notifications.NotificationsNtfy.priority\": \"Prioritet\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationPriorityRequired\": \"Du måste ange en prioritet mellan 1 och 5\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersValue\": \"Header-värde\",\n  \"components.Discover.timeWindowDay\": \"Dagligen\",\n  \"components.Discover.timeWindowWeek\": \"Veckovis\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeaders\": \"Anpassade headers\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAdd\": \"Lägg till header\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersAuthConflict\": \"Du kan inte använda både Authorization-headern och en egen Authorization-header. Ta bort en av dem.\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersIncomplete\": \"Alla headers måste ha både namn och värde\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersKey\": \"Headernamn\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersRemove\": \"Ta bort\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"Lägg till anpassade HTTP-headers som ska inkluderas i webhook-förfrågningar\"\n}\n"
  },
  {
    "path": "src/i18n/locale/tr.json",
    "content": "{\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMBD Derecelendirmesi (Artan)\",\n  \"components.Discover.moviegenres\": \"Film Türleri\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Slider düzenlendi ve keşfet özelleştirme ayarları kaydedildi.\",\n  \"components.Discover.FilterSlideover.studio\": \"Stüdyo\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Film\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex İzleme Listenize</PlexWatchlistSupportLink> eklenen içerikler burada gözükeceklerdir.\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Slider İsmi\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Yakın Zamanda Eklenenler\",\n  \"components.Discover.FilterSlideover.keywords\": \"Anahtar Kelimeler\",\n  \"components.Discover.FilterSlideover.ratingText\": \"{minValue} ile {maxValue} arasında ki değerlendirmeler\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"İlk Yayınlanma Tarihi (Yeni)\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Bağlanmış <code>{appDataPath}</code> dizini düzgün bir şekilde yapılandırılmamış. Tüm veriler konteyner yeniden başlatıldığında veya durdurulduğunda temizlenecektir.\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Dizileri\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Popülerlik (Azalan)\",\n  \"components.Discover.StudioSlider.studios\": \"Stüdyolar\",\n  \"components.AirDateBadge.airsrelative\": \"Yayınlanıyor {relativeTime}\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMBD Derecelendirmesi (Azalan)\",\n  \"components.Discover.customizediscover\": \"Keşfet'i Özelleştir\",\n  \"components.Discover.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex İzleme Listenize</PlexWatchlistSupportLink> eklenen içerikler burada gözükeceklerdir.\",\n  \"components.Discover.populartv\": \"Popüler Diziler\",\n  \"components.CollectionDetails.overview\": \"Özet\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"Filtrele\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMBD Derecelendirmesi (Artan)\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre} Dizileri\",\n  \"components.AirDateBadge.airedrelative\": \"Yayınlandı {relativeTime}\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Filtreleri Temizle\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Stüdyolarda Ara.…\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Çıkış Tarihi (Azalan)\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"TMDB Ağ Kimliğini Sağlayın\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Film Türleri\",\n  \"components.Discover.networks\": \"İnternet Yayınları\",\n  \"components.Discover.CreateSlider.addfail\": \"Slider oluşturulamadı.\",\n  \"components.CollectionDetails.requestcollection\": \"Koleksiyonu Talep Et\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Dizi Türleri\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre} Filmleri\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language} Filmler\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Dizi Türleri\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Filtre} other {# Filtre}}\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language} Diziler\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Popülerlik (Artan)\",\n  \"components.Discover.NetworkSlider.networks\": \"İnternet Yayınları\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Yayın Hizmetleri\",\n  \"components.Discover.CreateSlider.needresults\": \"Seçtiğin etiketler en az 1 adet sonuç göstermelidir.\",\n  \"components.Discover.popularmovies\": \"Popüler Filmler\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Filtre} other {# Filtre}}\",\n  \"components.Discover.plexwatchlist\": \"İzleme Listeniz\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Özel Slider Oluştur\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMBD Kullanıcı Skoru\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Popülerlik (Artan)\",\n  \"components.Discover.CreateSlider.editSlider\": \"Slider'ı düzenle\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"İsim (A-Z) (Artan)\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Bir veri değeri sağlamalısınız.\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"İlk Yayınlanma Tarihi (Eski)\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"İzleme Listeniz\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Çıkış Tarihi\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Diziler\",\n  \"components.Discover.recentlyAdded\": \"Yakın Zamanda Eklenenler\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Slider silinemedi.\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"TMBD'den Stüdyo etiketi seç\",\n  \"components.Discover.FilterSlideover.runtime\": \"Süre\",\n  \"components.Discover.FilterSlideover.from\": \"Tarihinden\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"İsim (Z-A) (Azalan)\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} Filmleri\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Popülerlik (Azalan)\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Türlerde ara…\",\n  \"components.Discover.CreateSlider.editfail\": \"Slider düzenlenirken hata oluştu.\",\n  \"components.Discover.CreateSlider.starttyping\": \"Aramak için yazmaya başla.\",\n  \"components.Discover.createnewslider\": \"Yeni Slider Oluştur\",\n  \"components.Discover.FilterSlideover.filters\": \"Filtreler\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex İzleme Listen\",\n  \"components.Discover.discover\": \"Keşfet\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Görünürlüğü Değiştir\",\n  \"components.Discover.CreateSlider.addSlider\": \"Slider'ı Ekle\",\n  \"components.CollectionDetails.requestcollection4k\": \"Koleksiyonu 4K Kalitesiyle Talep Et\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"İlk Yayın Tarihi\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Bir arama sorgusu girin\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} Dizileri\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"TMBD'den Anahtar Kelime etiketi seç\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} Filmleri\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} dakika oynatma süresi\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Bir başlık belirtmeniz gerekmektedir.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"İzleme Listeniz\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Çıkış Tarihi (Artan)\",\n  \"components.Discover.FilterSlideover.genres\": \"Türler\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Orijinal Dili\",\n  \"components.Discover.CreateSlider.nooptions\": \"Sonuç Bulunamadı.\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMBD Derecelendirmesi (Azalan)\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Anahtar Kelimeler ara…\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMBD Oy Kullanan Kullanıcı Sayısı\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Yeni slider oluşturuldu ve keşfet sekmesinin ayarları kaydedildi.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Slider başarıyla silindi.\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Filmler\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Film Türleri\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"İsim (A-Z) (Artan)\",\n  \"components.Discover.FilterSlideover.voteCount\": \"{minValue} ile {maxValue} sayıları arasında oya sahip olanlar\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"TMBD'den Tür etiketi seç\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"İsim (Z-A) (Azalan)\",\n  \"components.Discover.recentrequests\": \"Yakın Zamandaki Talepler\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Kaldır\",\n  \"components.Discover.FilterSlideover.to\": \"Tarihine\",\n  \"components.Discover.resetfailed\": \"Keşfet özelleştirme ayarlarını sıfırlarken bir sorun oluştu.\",\n  \"components.Discover.resetsuccess\": \"Keşfet ayarları başarıyla sıfırlandı.\",\n  \"components.Discover.resettodefault\": \"Varsayılana Dön\",\n  \"components.Discover.resetwarning\": \"Tüm Slider'ları varsayılana sıfırla. Bu aynı zamanda tüm özel Slider'ları da silecektir!\",\n  \"components.Discover.stopediting\": \"Vazgeç\",\n  \"components.Discover.studios\": \"Stüdyolar\",\n  \"components.Discover.tmdbmoviegenre\": \"TMBD Film Türleri\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB Film Anahtar Kelimeleri\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB Dijital Platform Filmleri\",\n  \"components.Discover.tmdbnetwork\": \"TMBD İnternet Yayınları\",\n  \"components.Discover.tmdbsearch\": \"TMBD Arama\",\n  \"components.Discover.tmdbstudio\": \"TMBD Stüdyolar\",\n  \"components.Discover.tmdbtvkeyword\": \"TMBD Dizi Anahtar Kelimeleri\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMBD Dijital Platform Dizileri\",\n  \"components.Discover.trending\": \"Popüler\",\n  \"components.Discover.tvgenres\": \"Dizi Türleri\",\n  \"components.Discover.upcoming\": \"Gösterime Girecek Filmler\",\n  \"components.Discover.upcomingmovies\": \"Gösterime Girecek Filmler\",\n  \"components.Discover.upcomingtv\": \"Yaklaşan Diziler\",\n  \"components.Discover.updatesuccess\": \"Keşfet ayarları güncellendi.\",\n  \"components.DownloadBlock.estimatedtime\": \"Tahmini Bitiş: {time}\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Sezon {seasonNumber} Bölüm {episodeNumber}\",\n  \"components.IssueDetails.IssueComment.delete\": \"Yorumu Sil\",\n  \"components.IssueDetails.IssueComment.edit\": \"Yorumu Düzenle\",\n  \"components.IssueDetails.IssueComment.postedby\": \"{relativeTime} Tarihinde, {username} tarafından gönderildi\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"{relativeTime} Tarihinde, {username} tarafından gönderildi (Düzenlenmiş)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Bir mesaj girmelisiniz\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Sorun Bildirimini Sil\",\n  \"components.IssueDetails.IssueDescription.description\": \"Açıklama\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Açıklamayı Düzenle\",\n  \"components.IssueDetails.allepisodes\": \"Tüm Bölümler\",\n  \"components.IssueDetails.allseasons\": \"Tüm Sezonlar\",\n  \"components.IssueDetails.closeissue\": \"Sorun Bildirimini Kapat\",\n  \"components.IssueDetails.commentplaceholder\": \"Yorum ekle…\",\n  \"components.IssueDetails.comments\": \"Yorumlar\",\n  \"components.IssueDetails.deleteissue\": \"Sorun Bildirimini Sil\",\n  \"components.IssueDetails.episode\": \"Bölüm {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Sorun\",\n  \"components.IssueDetails.issuetype\": \"Tür\",\n  \"components.IssueDetails.lastupdated\": \"En Son Güncelleme Zamanı\",\n  \"components.IssueDetails.leavecomment\": \"Yorum Ekle\",\n  \"components.IssueDetails.nocomments\": \"Yorum yok.\",\n  \"components.IssueDetails.openin4karr\": \"{arr} ile 4K Aç\",\n  \"components.IssueDetails.openinarr\": \"{arr} ile Aç\",\n  \"components.IssueDetails.play4konplex\": \"{mediaServerName} ile 4K Oynat\",\n  \"components.IssueDetails.playonplex\": \"{mediaServerName} ile Oynat\",\n  \"components.IssueDetails.problemepisode\": \"Sorundan Etkilenen Bölümler\",\n  \"components.IssueDetails.problemseason\": \"Sorundan Etkilenen Sezonlar\",\n  \"components.IssueDetails.reopenissue\": \"Sorun Bildirisini Yeniden Aç\",\n  \"components.IssueDetails.season\": \"Sezon {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Sorun açıklamasını düzenlerken beklenmedik bir hata oluştu.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Sorun açıklaması başarıyla düzenlendi!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Sorun açıklaması silinirken beklenmedik bir hata oluştu.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Sorun başarıyla güncellendi!\",\n  \"components.IssueDetails.unknownissuetype\": \"Bilinmiyor\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount} Bölüm\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Durum\",\n  \"components.IssueList.IssueItem.issuetype\": \"Tür\",\n  \"components.IssueList.IssueItem.opened\": \"Açıldı\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{user } tarafından, {date}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Sorundan Etkilenen Bölümler\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount} Sezon\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Bilinmiyor\",\n  \"components.IssueList.IssueItem.viewissue\": \"Sorunu Gör\",\n  \"components.IssueList.issues\": \"Sorunlar\",\n  \"components.IssueList.showallissues\": \"Tüm Sorunları Göster\",\n  \"components.IssueList.sortAdded\": \"En Son Eklenen\",\n  \"components.IssueList.sortModified\": \"En Son Düzenlenen\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Tüm Sezonlar\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Bölüm {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Ekstralar\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Sorundan Etkilenen Bölümler\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Sorundan Etkilenen Sezonlar\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Sezon {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Sorunu Bildir\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"<strong>{title}</strong> için oluşturduğunuz hata bildirisi gönderilmiştir!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Sorunu Gör\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Lütfen açıklamayı doldurunuz\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Sorun nedir?\",\n  \"components.IssueModal.issueAudio\": \"Ses\",\n  \"components.IssueModal.issueOther\": \"Diğer\",\n  \"components.IssueModal.issueSubtitles\": \"Altyazı\",\n  \"components.IssueModal.issueVideo\": \"Video\",\n  \"components.LanguageSelector.languageServerDefault\": \"Varsayılan ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Tüm Diller\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Film & Dizi Ara\",\n  \"components.Layout.Sidebar.browsemovies\": \"Filmler\",\n  \"components.Layout.Sidebar.browsetv\": \"Diziler\",\n  \"components.Layout.Sidebar.dashboard\": \"Keşfet\",\n  \"components.Layout.Sidebar.issues\": \"Sorunlar\",\n  \"components.Layout.Sidebar.requests\": \"Talepler\",\n  \"components.Layout.Sidebar.settings\": \"Ayarlar\",\n  \"components.Layout.Sidebar.users\": \"Kullanıcılar\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Film Talepleri\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Dizi Talepleri\",\n  \"components.Layout.UserDropdown.myprofile\": \"Profil\",\n  \"components.Layout.UserDropdown.requests\": \"Talepler\",\n  \"components.Layout.UserDropdown.settings\": \"Ayarlar\",\n  \"components.Layout.UserDropdown.signout\": \"Çıkış Yap\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Bir e-mail adresi gereklidir.\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Bir şifre girmeniz gerekmektedir.\",\n  \"components.Layout.VersionStatus.outofdate\": \"Eski Sürüm\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr Geliştirme Sürümü\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr Stabil Sürüm\",\n  \"components.Login.credentialerror\": \"Kullanıcı adı ya da şifre yanlış.\",\n  \"components.Login.description\": \"{applicationName} uygulamasına ilk defa giriş yaptığınız için geçerli bir e-mail adresi eklemeniz gerekmektedir.\",\n  \"components.Login.email\": \"E-mail Adresi\",\n  \"components.Login.forgotpassword\": \"Şifrenizi mi unuttunuz?\",\n  \"components.Login.initialsignin\": \"Bağlan\",\n  \"components.Login.initialsigningin\": \"Bağlanıyor…\",\n  \"components.Login.password\": \"Şifre\",\n  \"components.Login.save\": \"Ekle\",\n  \"components.Login.saving\": \"Ekleniyor…\",\n  \"components.Login.signin\": \"Oturum Aç\",\n  \"components.Login.signingin\": \"Oturum Açılıyor…\",\n  \"components.Login.signinwithjellyfin\": \"{mediaServerName} hesabını kullan\",\n  \"components.Login.signinwithoverseerr\": \"{applicationTitle} hesabını kullan\",\n  \"components.Login.signinwithplex\": \"Plex hesabını kullan\",\n  \"components.Login.title\": \"E-mail Ekle\",\n  \"components.Login.username\": \"Kullanıcı Adı\",\n  \"components.Login.validationEmailFormat\": \"Geçersiz e-mail\",\n  \"components.Login.validationemailformat\": \"Geçerli bir e-mail adresi gereklidir\",\n  \"components.Login.validationemailrequired\": \"Geçerli bir e-mail adresi sağlamalısınız\",\n  \"components.Login.validationhostformat\": \"Geçerli bir URl gereklidir\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL'si gereklidir\",\n  \"components.Login.validationusernamerequired\": \"Kullanıcı Adı girmeniz gereklidir\",\n  \"components.ManageSlideOver.alltime\": \"Tüm Zamanlar\",\n  \"components.ManageSlideOver.downloadstatus\": \"İndirilenler\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Gelişmiş\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Veriyi Temizle\",\n  \"components.Discover.tmdbtvgenre\": \"TMBD Dizi Türleri\",\n  \"components.Discover.updatefailed\": \"Keşfet ayarları güncellenirken beklenmedik bir hata oluştu.\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Bu yorumu silmek istediğinize emin misiniz?\",\n  \"components.IssueDetails.closeissueandcomment\": \"Yorum ekleyerek Kapat\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Bu hata bildirisini silmek istediğinize emin misiniz?\",\n  \"components.IssueDetails.openedby\": \"#{issueId} {relativeTime} tarihinde {username} tarafından açıldı\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Bir Yorumla beraber Yeniden Aç\",\n  \"components.IssueDetails.toastissuedeleted\": \"Sorun Bildirisi başarıyla silindi!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Sorun açıklaması güncellenirken beklenmedik bir hata oluştu.\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Tüm Bölümler\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Lütfen karşılaştığınız hatayı detaylı bir biçimde açıklayınız.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Sorun Bildir\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Görüntüleme Dili\",\n  \"components.Login.validationpasswordrequired\": \"Bir şifre girmeniz gereklidir\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Sorunu bildirirken beklenmedik bir hata oluştu.\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"E-mail adresi geçersiz.\",\n  \"components.Login.signinheader\": \"Devam etmek için oturum aç\",\n  \"components.Login.validationEmailRequired\": \"Bir e-mail adresi girmelisiniz\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} behind\",\n  \"components.Login.emailtooltip\": \"E-mail adresi {mediaServerName} uygulamasıyla ilişik olmak zorunda değildir.\",\n  \"components.Login.loginerror\": \"Oturum açarken bir hata oluştu.\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Bu işlem geri döndürülemez bir biçimde {mediaType} ile alakalı her türlü talepte dahil olmak üzere tüm verileri silecektir. Eğer ki bu öğe {mediaServerName} kütüphanenizde bulunuyorsa, tüm medya bilgileri bir sonra ki taramada yeniden oluşturulucaktır.\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Sorun Bildir\",\n  \"components.ManageSlideOver.manageModalMedia\": \"İçerik\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K İçerik\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Hiç talep yok.\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Bu işlem geri döndürülemez bir biçimde {arr}'dan {mediaType} öğesini ve dosyalarını kaldıracaktır.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Talepler\",\n  \"components.ManageSlideOver.manageModalTitle\": \"{mediaType} içeriğini yönet\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Tüm Sezonları 4K Oynatılabilir Olarak İşaretle\",\n  \"components.ManageSlideOver.mark4kavailable\": \"4K Oynatılabilir Olarak İşaretle\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Tüm Sezonları Oynatılabilir Olarak İşaretle\",\n  \"components.ManageSlideOver.markavailable\": \"Oynatılabilir Olarak İşaretle\",\n  \"components.ManageSlideOver.movie\": \"Film\",\n  \"components.ManageSlideOver.openarr\": \"{arr}'da Aç\",\n  \"components.ManageSlideOver.openarr4k\": \"{arr}'da 4K Olarak Aç\",\n  \"components.ManageSlideOver.opentautulli\": \"Tautuli'de Aç\",\n  \"components.ManageSlideOver.pastdays\": \"{days, number} Gün Geçti\",\n  \"components.ManageSlideOver.playedby\": \"Tarafından Oynatıldı\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> oynatma\",\n  \"components.ManageSlideOver.removearr\": \"{arr}'dan Kaldır\",\n  \"components.ManageSlideOver.tvshow\": \"dizi\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Daha Fazla\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Tüm Oyuncular\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Tüm Ekip\",\n  \"components.MovieDetails.budget\": \"Bütçe\",\n  \"components.MovieDetails.cast\": \"Oyuncular\",\n  \"components.MovieDetails.digitalrelease\": \"Dijital Sürüm\",\n  \"components.MovieDetails.downloadstatus\": \"İndirme Durumu\",\n  \"components.MovieDetails.managemovie\": \"Filmi Yönet\",\n  \"components.MovieDetails.mark4kavailable\": \"4K Oynatılabilir Olarak İşaretle\",\n  \"components.MovieDetails.markavailable\": \"Oynatılabilir Olarak İşaretle\",\n  \"components.MovieDetails.openradarr\": \"Filmi Radarr'da Aç\",\n  \"components.MovieDetails.openradarr4k\": \"Filmi 4K Radarr'da Aç\",\n  \"components.MovieDetails.originallanguage\": \"Orijinal Dil\",\n  \"components.MovieDetails.originaltitle\": \"Orijinal Başlık\",\n  \"components.MovieDetails.overview\": \"Özet\",\n  \"components.MovieDetails.physicalrelease\": \"Fiziksel Sürüm\",\n  \"components.MovieDetails.play\": \"İçeriği {mediaServerName} üzerinde oynat\",\n  \"components.MovieDetails.play4k\": \"İçeriği {mediaServerName} üzerinde 4K oynat\",\n  \"components.MovieDetails.recommendations\": \"Önerilenler\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Yayın Tarihi} other {Yayın Tarihleri}}\",\n  \"components.MovieDetails.reportissue\": \"Sorun Bildir\",\n  \"components.MovieDetails.revenue\": \"Hasılat\",\n  \"components.MovieDetails.rtaudiencescore\": \"Rotten Tomatoes İzleyici Puanı\",\n  \"components.MovieDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.MovieDetails.runtime\": \"{minutes} dakika\",\n  \"components.MovieDetails.showmore\": \"Daha Fazla Göster\",\n  \"components.MovieDetails.showless\": \"Daha Az Göster\",\n  \"components.MovieDetails.similar\": \"Benzer İçerikler\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Stüdyo} other {Stüdyolar}}\",\n  \"components.MovieDetails.theatricalrelease\": \"Sinemaya Çıkışı\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMBD Kullanıcı Skoru\",\n  \"components.MovieDetails.viewfullcrew\": \"Tüm Ekibi Gör\",\n  \"components.MovieDetails.watchtrailer\": \"Fragmanı İzle\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Sorun bildirileri kullanıcılar tarafından tekrardan açıldığında bildirim gönder.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Sorun bildirileri kullanıcılar tarafından çözüldüğünde bildirim gönder.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Sorun Bildirim Yorumları\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Sorunlar bildirildiğinde bildirim gönder.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Sorun Yeniden Açıldı\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Sorun Çözüldü\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Sorunlar çözüldüğünde bildirim gönder.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Otomatik Kabul Edilen Talepler\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Kullanıcıların içerik talepleri otomatik olarak kabul edilenler için bildirim gönder.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Kabul Edilen Talepler\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Talep Otomatik Olarak Gönderildi\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Kullanıcıların otomatik içerik talepleri eğer ki sizin İzleme Listenizden bir içerik içeriyor ise bildirim gönder.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"İzlenebilir İçerik\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"İçerik izlenebilir olduğunda bildirim gönder.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Reddedilen Talepler\",\n  \"components.NotificationTypeSelector.mediafailed\": \"İşlemdeyken İptal Olan Talepler\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"İçerik talepleri Sonarr'a ya da Radarr'a eklenirken hata oluşursa bildirim gönder.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Doğrulama Bekleyen Talepler\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Bildirim Türleri\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Gönderdiğiniz hata bildirimine yorum geldiğinde bildirim gönder.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Diğer kullanıcılar hata bildirdiklerinde bildirim gönder.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Gönderdiğiniz hata bildirimi yeniden açıldığında bildirim gönder.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Gönderdiğiniz hata bildirimi çözüldüğünde bildirim gönder.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Gönderdiğiniz içerik talepleri kabul edildiğinde bildirim gönder.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Gönderdiğiniz içerik talepleri izlenebilir olduğunda bildirim gönder.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Gönderdiğiniz içerik talepleri reddedildiğinde bildirim gönder.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Diğer kullanıcılar doğrulama gerektiren içerik talepleri gönderdiğinde bildirim gönder.\",\n  \"components.PermissionEdit.admin\": \"Yönetici\",\n  \"components.PermissionEdit.adminDescription\": \"Tam yönetici erişimi. Diğer tüm izin denetlemelerini görmezden gelir.\",\n  \"components.PermissionEdit.advancedrequest\": \"Gelişmiş Talepler\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Gelişmiş talep ayarlarını düzenleyebilme izni ver.\",\n  \"components.PermissionEdit.autoapprove\": \"Otomatik Onay\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"4K Filmler İçin Otomatik Onay\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"4K Film taleplerinin otomatik onaylanmasına izin ver.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"4K Diziler İçin Otomatik Onay\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"4K Dizi taleplerinin otomatik onaylanmasına izin ver.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"4K olmayan içerik taleplerinin otomatik onaylanması iznini ver.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Filmler İçin Otomatik Onay\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Diziler İçin Otomatik Onay\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"4K olmayan dizi taleplerinin otomatik onaylanması iznini ver.\",\n  \"components.PermissionEdit.autorequest\": \"Otomatize Talep\",\n  \"components.PermissionEdit.autorequestMovies\": \"Filmleri Otomatize Talep Ett\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Kullanıcının Plex İzleme listesinde olan ve 4K olmayan filmler için otomatik olarak talep etme iznini ver.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Dizileri Otomatize Talep Ett\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Kullanıcının Plex İzleme listesinde olan ve 4K olmayan diziler için otomatik olarak talep etme iznini ver.\",\n  \"components.PermissionEdit.createissues\": \"Sorun Bildirme\",\n  \"components.PermissionEdit.manageissues\": \"Sorunları Yönetme\",\n  \"components.PermissionEdit.manageissuesDescription\": \"İçeriklerde ki hataları yönetme iznini ver.\",\n  \"components.PermissionEdit.managerequests\": \"Talepleri Yönet\",\n  \"components.PermissionEdit.request\": \"Talep\",\n  \"components.PermissionEdit.request4k\": \"4K Talep Etme\",\n  \"components.PermissionEdit.request4kDescription\": \"4K içerik talep edilmesine izin ver.\",\n  \"components.PermissionEdit.request4kMovies\": \"4K Filmleri Talep Etme\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"4K film talep edilmesine izin ver.\",\n  \"components.PermissionEdit.request4kTv\": \"4K Dizi Talep Etme\",\n  \"components.PermissionEdit.request4kTvDescription\": \"4K dizi talep edilmesine izin ver.\",\n  \"components.PermissionEdit.requestDescription\": \"4K olmayan içeriklerin talep edilmesine izin ver.\",\n  \"components.PermissionEdit.requestMovies\": \"Film Talep Etme\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"4K olmayan filmlerin talep edilmesine izin ver.\",\n  \"components.PermissionEdit.requestTv\": \"Dizi Talep Etme\",\n  \"components.PermissionEdit.requestTvDescription\": \"4K olmayan dizilerin talep edilmesine izin ver.\",\n  \"components.PermissionEdit.users\": \"Kullanıcıları Yönetme\",\n  \"components.PermissionEdit.viewissues\": \"Sorunları Görme\",\n  \"components.PermissionEdit.viewissuesDescription\": \"İçeriklerle alakalı dieğr kullanıcıların raporladığı hataları görme iznini ver.\",\n  \"components.PermissionEdit.viewrequests\": \"Talepleri Görme\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Diğer kullanıcılar tarafından istenen içerikleri görme iznini ver.\",\n  \"components.PermissionEdit.viewwatchlists\": \"{mediaServerName} İzleme Listelerini Görme\",\n  \"components.PersonDetails.alsoknownas\": \"Nam-ı Diğer: {names}\",\n  \"components.PersonDetails.appearsin\": \"Yer Aldığı İçerikler\",\n  \"components.PersonDetails.ascharacter\": \"{character} rolüyle\",\n  \"components.PersonDetails.birthdate\": \"Doğumu {birthdate}\",\n  \"components.PersonDetails.crewmember\": \"Bilinen İşleri\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.days\": \"{count} gün\",\n  \"components.QuotaSelector.movies\": \"{count} film\",\n  \"components.QuotaSelector.seasons\": \"{count} sezon\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{sezon} per {quotaDays} {gün}</quotaUnits>\",\n  \"components.QuotaSelector.unlimited\": \"Sınırsız\",\n  \"components.RegionSelector.regionDefault\": \"Tüm Bölgeler\",\n  \"components.RegionSelector.regionServerDefault\": \"Varsayılan ({region})\",\n  \"components.RequestBlock.approve\": \"Talebi Kabul Et\",\n  \"components.RequestBlock.decline\": \"Talebi Reddet\",\n  \"components.RequestBlock.delete\": \"Talebi Sil\",\n  \"components.RequestBlock.edit\": \"Talebi Düzenle\",\n  \"components.RequestBlock.languageprofile\": \"Dil Seçeneği\",\n  \"components.RequestBlock.profilechanged\": \"Kalite Seçeneği\",\n  \"components.RequestBlock.requestdate\": \"Talep Etme Tarihi\",\n  \"components.RequestBlock.requestedby\": \"Talep Eden\",\n  \"components.RequestBlock.requestoverrides\": \"Geçersiz Talep\",\n  \"components.RequestBlock.rootfolder\": \"Ana Klasör\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Sezon} other {Sezon}}\",\n  \"components.RequestBlock.server\": \"Hedef Sunucu\",\n  \"components.RequestButton.approverequest\": \"Talebi Kabul Et\",\n  \"components.RequestButton.approverequest4k\": \"4K Talebi Kabul Et\",\n  \"components.RequestButton.approverequests\": \"{requestCount, plural, one {Talebi} other {{requestCount} Talebi}} Kabul Et\",\n  \"components.RequestButton.declinerequest\": \"Talebi Reddet\",\n  \"components.RequestButton.declinerequest4k\": \"4K Talebi Reddet\",\n  \"components.RequestButton.declinerequests\": \"{requestCount, plural, one {Talebi} other {{requestCount} Talebi}} Reddet\",\n  \"components.RequestButton.requestmore4k\": \"Daha Fazla 4K Talep Et\",\n  \"components.RequestButton.viewrequest\": \"Talepleri Gör\",\n  \"components.RequestButton.viewrequest4k\": \"4K Talepleri Gör\",\n  \"components.RequestCard.approverequest\": \"Talebi Kabul Et\",\n  \"components.RequestCard.cancelrequest\": \"Talebi İptal Et\",\n  \"components.RequestCard.declinerequest\": \"Talebi Reddet\",\n  \"components.RequestCard.deleterequest\": \"Talebi Sil\",\n  \"components.RequestCard.failedretry\": \"Tekrardan talep gönderirken bir hata oluştu.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} Bulunamadı\",\n  \"components.RequestCard.seasons\": \"{seasonCount} Sezon\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID'si\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID'si\",\n  \"components.RequestCard.unknowntitle\": \"Bilinmeyen İçerik\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Talebi Sil\",\n  \"components.RequestList.RequestItem.editrequest\": \"Talebi Düzenle\",\n  \"components.RequestList.RequestItem.failedretry\": \"Tekrardan talep gönderirken bir hata oluştu.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} Bulunamadı\",\n  \"components.RequestList.RequestItem.modified\": \"Son Düzenleme:\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{user } tarafından, {date}\",\n  \"components.RequestList.RequestItem.requested\": \"Talep Edilme:\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Sezon} other {Sezon}}\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID'si\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID'si\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Bilinmeyen İçerik\",\n  \"components.RequestList.requests\": \"Talepler\",\n  \"components.RequestList.showallrequests\": \"Tüm Talepleri Göster\",\n  \"components.RequestList.sortAdded\": \"En Son Eklenen\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Gelişmiş\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Bu dizi bir animedir.\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (Varsayılan)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Hedef Sunucu\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Dil Seçeneği\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Etiket yok.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Kalite Seçeneği\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Ana Klasör\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Etiketleri seç\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Etiketler\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"Film\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {Film} other {Film}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Sezon isteteme limitiniz yetmemektedir\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Talep limitlerinizin özetini <ProfileLink>profil sayfanızda</ProfileLink> görüntüleyebilirsiniz.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{type} {remaining, plural, one {talep} other {talep}} limitin {remaining, plural, =0 {kalmadı} other {<strong>#</strong>}}\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Bu kullanıcının bu dizinin <strong>{sezonlarını}</strong> talep edebilmesi için en az {seasons, plural, one {sezon talebi} other {sezon talebi}} kadar talep göndermesi gerekiyor.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"Sezon\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {sezon} other {sezon}}\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Bu dizi için uygun bir eşleşme bulamadık.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Bu diziyi otomatik olarak eşleştiremedik, lütfen aşağıdan bir eşleşme seçin.\",\n  \"components.RequestModal.alreadyrequested\": \"Zaten Talep Edildi\",\n  \"components.RequestModal.approve\": \"Talebi Kabul Et\",\n  \"components.RequestModal.autoapproval\": \"Otomatik Kabul\",\n  \"components.RequestModal.cancel\": \"Talebi İptal Et\",\n  \"components.RequestModal.edit\": \"Talebi Düzenle\",\n  \"components.RequestModal.errorediting\": \"Talep düzenlenirken beklenmedik bir hatayla karşılaşıldı.\",\n  \"components.RequestModal.numberofepisodes\": \"# Bölümleri\",\n  \"components.RequestModal.pending4krequest\": \"4K Talep Beklemede\",\n  \"components.RequestModal.pendingapproval\": \"Gönderdiğiniz talep onaylama aşamasında.\",\n  \"components.RequestModal.pendingrequest\": \"Talep Beklemede\",\n  \"components.RequestModal.requestCancel\": \"<strong>{title}</strong> için gönderdiğiniz talep reddedildi.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> başarıyla talep edildi!\",\n  \"components.RequestModal.requestcancelled\": \"<strong>{title}</strong> için gönderdiğiniz talep reddedildi.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Koleksiyonu 4K Kalitesiyle Talep Et\",\n  \"components.RequestModal.requestcollectiontitle\": \"Koleksiyonu Talep Et\",\n  \"components.RequestModal.requestedited\": \"<strong>{title}</strong> için gönderilen talep başarıyla düzenlendi!\",\n  \"components.RequestModal.requestfrom\": \"{username} kullanıcısının talepleri onay bekliyor.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Filmi 4K Talep Et\",\n  \"components.RequestModal.requestmovies\": \"{count} Filmi Talep Et\",\n  \"components.RequestModal.requestmovietitle\": \"Filmi Talep Et\",\n  \"components.RequestModal.requestseasons4k\": \"{seasonCount} Sezonu 4K Talep Et\",\n  \"components.RequestModal.requestseries4ktitle\": \"Diziyi 4K Talep Et\",\n  \"components.RequestModal.requestseriestitle\": \"Diziyi Talep Et\",\n  \"components.RequestModal.season\": \"Sezon\",\n  \"components.RequestModal.seasonnumber\": \"{number}. Sezon\",\n  \"components.RequestModal.selectmovies\": \"Film(leri) Seç\",\n  \"components.RequestModal.selectseason\": \"Dizi(leri) Seç\",\n  \"components.ResetPassword.confirmpassword\": \"Şifreyi Doğrula\",\n  \"components.ResetPassword.email\": \"E-mail Adresi\",\n  \"components.ResetPassword.emailresetlink\": \"E-mail Kurtarma Linki\",\n  \"components.ResetPassword.password\": \"Şifre\",\n  \"components.ResetPassword.passwordreset\": \"Şifreyi Sıfırla\",\n  \"components.ResetPassword.resetpassword\": \"Şifrenizi sıfırlayın\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Şifre sıfırlama başarılı!\",\n  \"components.ResetPassword.validationemailrequired\": \"Geçerli bir e-mail adresi sağlamalısınız\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Girdiğiniz şifreler uyuşmuyor\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Girdiğiniz şifre çok kısa, en az 8 karakterden oluşmalıdır\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Bir şifre girmeniz gereklidir\",\n  \"components.Search.search\": \"Ara\",\n  \"components.Search.searchresults\": \"Arama Sonuçları\",\n  \"components.Selector.nooptions\": \"Sonuç Bulunamadı.\",\n  \"components.Selector.searchGenres\": \"Türleri seç…\",\n  \"components.Selector.searchKeywords\": \"Anahtar kelimeleri arat…\",\n  \"components.Selector.searchStudios\": \"Stüdyolarda ara…\",\n  \"components.Selector.showless\": \"Daha Az Göster\",\n  \"components.Selector.showmore\": \"Daha Fazla Göster\",\n  \"components.Selector.starttyping\": \"Aramak için yazmaya başla.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify bildirim ayarları kaydedilemedi.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify bildirim ayarları kaydedildi!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify deneme bildirimi gönderilemedi.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify deneme bildirimi gönderildi!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Uygulama Token'i\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Sunucu URL'si\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Bir uygulama Token'i girmeniz gerekmektedir\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Geçerli bir URL girmelisiniz\",\n  \"components.ManageSlideOver.removearr4k\": \"4K {arr}'dan Kaldır\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Diğer kullanıcılar hata bildirilerine yorum yaptıklarında bildirim gönder.\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Talep reddedildiğinde bildirim gönder.\",\n  \"components.PermissionEdit.createissuesDescription\": \"İçeriklerde ki hataları bildirme iznini ver.\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Yakın zamanda eklenen içerikleri görme iznini ver.\",\n  \"components.RequestBlock.lastmodifiedby\": \"Son Düzenlenleyen\",\n  \"components.RequestButton.decline4krequests\": \"{requestCount, plural, one {4K Talebi} Reddet other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.requestmore\": \"Daha Fazla Talep Et\",\n  \"components.RequestCard.editrequest\": \"Talebi Düzenle\",\n  \"components.RequestModal.requestApproved\": \"<strong>{title}</strong> için gönderdiğiniz talep onaylandı!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Gotify deneme bildirimi gönderiliyor…\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"En azından bir adet bildirim türü seçmelisiniz\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB Kullanıcı Puanı\",\n  \"components.MovieDetails.overviewunavailable\": \"Özet mevcut değil.\",\n  \"components.MovieDetails.productioncountries\": \"Yapımcı {countryCount, plural, one {Ülke} other {Ülkeler}}\",\n  \"components.MovieDetails.streamingproviders\": \"İçeriğin Erişilebilir Olduğu Platformlar\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Sorun bildirilerine yeni yorum geldiğinde bildirim gönder.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Sorun Bildirimleri\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Sorunlar yeniden açıldığında bildirim gönder.\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Kullanıcıların içerik talepleri elle kabul edildiğinde bildirim gönder.\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Kullanıcılar doğrulama gerektiren içerik talepleri gönderdiğinde bildirim gönder.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Diğer kullanıcılar otomatize içerik talepleri gönderdiğinde bildirim gönder.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Gönderdiğiniz içerik talepleri Sonarr ya da Radarr'a eklenemediğinde bildirim gönder.\",\n  \"components.PermissionEdit.autoapprove4k\": \"4K İçin Otomatik Onay\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"4K İçerik taleplerinin otomatik onaylanması iznini ver.\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"4K olmayan film taleplerinin otomatik onaylanması iznini ver.\",\n  \"components.PermissionEdit.autorequestDescription\": \"Kullanıcının Plex İzleme listesinde olan içerikler için otomatik olarak talep etme iznini ver.\",\n  \"components.PermissionEdit.managerequestsDescription\": \"İçerik taleplerini yönetme iznini ver. Bu izne sahip kullanıcının gönderdiği tüm talepler otomatik olarak kabul edilir.\",\n  \"components.PermissionEdit.viewrecent\": \"Yakın Zamanda Eklenenleri Görme\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Talep Eden:\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"<strong>{limit}</strong> {type} talep etme limitin var, her <strong>{days}</strong> günde bir bu limit yenilenecektir.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Bu kullanıcının <strong>{limit}</strong> {type} talep etme limiti var, her <strong>{days}</strong> günde bir bu limit yenilenecektir.\",\n  \"components.PermissionEdit.usersDescription\": \"Kullanıcıları yönetme iznini ver. Bu izne sahip kullanıcılar Yönetici yetkisine sahip kişileri düzenleyemezler ya da Yönetici yetkisi veremezler.\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Diğer kullanıcıların {mediaServerName} İzleme Listelerini görme iznini ver.\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Talebi İptal Et\",\n  \"components.RequestList.sortModified\": \"En Son Düzenlenen\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Bu kullanıcının talep limitlerinin özetini <ProfileLink>profil sayfasında</ProfileLink> görüntüleyebilirsiniz.\",\n  \"components.RequestModal.requesterror\": \"Talebi gönderirken beklenmedik bir hata oluştu.\",\n  \"components.RequestModal.requestseasons\": \"{seasonCount} Sezonu Talep Et\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Aracıyı Etkinleştir\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{Film} per {quotaDays} {gün}</quotaUnits>\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Talep Edildi\",\n  \"components.RequestModal.requestadmin\": \"Bu talep otomatik olarak onaylanacaktır.\",\n  \"components.RequestButton.approve4krequests\": \"{requestCount, plural, one {4K Talebi} Kabul Et other {{requestCount} 4K Requests}}\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Bu dizinin <strong>{sezonlarını}</strong> istetebilmek için en azından {seasons, plural, one {sezon talebi} other {sezon talepleri}} kadar talep göndermeniz gerekiyor.\",\n  \"components.RequestModal.requestmovies4k\": \"{count} Filmi 4K Talep Et\",\n  \"components.ResetPassword.gobacklogin\": \"Oturum Açma Sayfasına Dön\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Eğer ki girilen e-mail adresi gerçek bir kişiyle ilişkiliyse şifre sıfırlama linki gönderilecektir.\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL'nizin sonunda slash (eğik çizgi) olmamalıdır\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Erişim Token'i\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"<PushbulletSettingsLink>Hesap Ayarlarınızdan</PushbulletSettingsLink> bir token oluşturun\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Aracıyı Etkinleştir\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Kanal Etiketi\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbullet bildirim ayarları kaydedilemedi.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet bildirim ayarları kaydedildi!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Pushbullet deneme bildirimi gönderiliyor…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet deneme bildirimi gönderildi!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Bir erişim token'i sağlamalısınız\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"En azından bir adet bildirim türü seçmelisiniz\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Uygulama API'sinin Token'i\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet deneme bildirimi gönderilemedi.\",\n  \"components.Settings.RadarrModal.released\": \"Yayınlandı\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Ana Klasör\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Aracıyı Etkinleştir\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Cihaz Varsayılanı\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushover bildirim ayarları kaydedilemedi.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover bildirim ayarları kaydedildi!\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Bildirim Sesi\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover deneme bildirimi gönderilemedi.\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"Seerr ile kullanılmak üzere <ApplicationRegistrationLink>bir uygulama kaydedin</ApplicationRegistrationLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover deneme bildirimi gönderildi!\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Geçerli bir uygulama token'i sağlamalısınız\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"En azından bir adet bildirim türü seçmelisiniz\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Kullanıcı ya da Grup Kimliği\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Geçerli bir kullanıcı ya da grup kimliği sağlamalısınız\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Aracıyı Etkinleştir\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Slack bildirim ayarları kaydedilemedi.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slacxk deneme bildirimi gönderilemedi.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Slack deneme bildirimi gönderiliyor…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack deneme bildirimi gönderildi!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"En azından bir adet bildirim türü seçmelisiniz\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Geçerli bir URL girmelisiniz\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook URL'si\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Aracıyı Etkinleştir\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Web push bildirimlerini alabilmek için Seerr'in HTTPS üzerinden sunulması gerekir.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Web deneme bildirimi gönderilemedi.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Web deneme bildirimi gönderiliyor…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Web deneme bildirimi gönderildi!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Web bildirim ayarları kaydedildi!\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Aracıyı Etkinleştir\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Yetkilendirme Üstbilgisi (Header'ı)\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON Payload'I\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Varsayılan Ayarlara Sıfırla\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON Payload'ı başarıyla sıfırlandı!\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Şablon Değişkeni İçin Yardım\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Webhook deneme bildirimi gönderiliyor…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook deneme bildirimi gönderildi!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Geçerli bir JSON Payload'ı sağlamalısınız\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"En azından bir adet bildirim türü seçmelisiniz\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook URL'si\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Webhook bildirim ayarları kaydedilemedi.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Webhook bildirim ayarları kaydedildi!\",\n  \"components.Settings.Notifications.agentenabled\": \"Aracıyı Etkinleştir\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Kendinden İmzalı Sertifikaları Kabul Et\",\n  \"components.Settings.Notifications.authPass\": \"SMPT Şifresi\",\n  \"components.Settings.Notifications.botAPI\": \"Bot Yetkilendirme Token'i\",\n  \"components.Settings.Notifications.botApiTip\": \"Seerr ile kullanılmak üzere <CreateBotLink>bir bot oluşturun</CreateBotLink>\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Bot Profil Resmi URL'si\",\n  \"components.Settings.Notifications.botUsername\": \"Bot Kullanıcı Adı\",\n  \"components.Settings.Notifications.chatId\": \"Sohbet ID'si\",\n  \"components.Settings.Notifications.chatIdTip\": \"Botunuzla sohbet etmek için <GetIdBotLink>@get_id_bot</GetIdBotLink> isimiyle ekleyin, <code>/my_id</code> komutunu kullanın ve sohbeti başlatın\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discord bildirim ayarları kaydedilemedi.\",\n  \"components.Settings.Notifications.emailsender\": \"Gönderen Adresi\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"E-mail bildirim ayarları kaydedilemedi.\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"E-mail bildirim ayarları kaydedildi!\",\n  \"components.Settings.Notifications.enableMentions\": \"Bahsetmeleri Etkinleştirin\",\n  \"components.Settings.Notifications.encryption\": \"Şifreleme Yöntemi\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Mümkünse STARTTLS kullan\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Örtülü (Implict) TLS Kullan\",\n  \"components.Settings.Notifications.encryptionNone\": \"Hiçbiri\",\n  \"components.Settings.Notifications.encryptionTip\": \"Genel olarak Örtülü (Implict) TLS 465 numaralı portu kullanır, STARTTLS ise 587 numaralı portu kullanır\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP Şifresi\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP Gizli Anahtar\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"<OpenPgpLink>OpenPGP</OpenPgpLink> kullanarak e-mailleri imzala ve şifrele\",\n  \"components.Settings.Notifications.sendSilently\": \"Sessizce Gönder\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Bildirimler sessiz gönderilir\",\n  \"components.Settings.Notifications.senderName\": \"Gönderen İsmi\",\n  \"components.Settings.Notifications.smtpHost\": \"SMPT Sunucu Adresi\",\n  \"components.Settings.Notifications.smtpPort\": \"SMPT Port'u\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegram bildirim ayarları kaydedilemedi.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram bildirim ayarları kaydedildi!\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord deneme bildirimi gönderildi!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"E-mail deneme bildirimi gönderilemedi.\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"E-mail deneme bildirimi gönderildi!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram test bildirimi gönderilemedi.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Telegram deneme bildirimi gönderiliyor…\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram deneme bildirimi gönderildi!\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Kullanıcı e-mail'ini zorunlu tut\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Geçerli bir sohbet ID'si sağlamalısın\",\n  \"components.Settings.Notifications.validationEmail\": \"Geçerli bir e-mail adresi sağlamalısın\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Bir PGP şifresi sağlamalısın\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Geçerli bir PGP gizli anahtarı sağlamalısın\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Geçerli bir port numarası girmelisin\",\n  \"components.Settings.Notifications.validationTypes\": \"En azından bir adet bildirim türü seçmelisiniz\",\n  \"components.Settings.Notifications.validationUrl\": \"Geçerli bir URL girmelisiniz\",\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook URL'si\",\n  \"components.Settings.RadarrModal.add\": \"Sunucu Ekle\",\n  \"components.Settings.RadarrModal.announced\": \"Duyurulmuş\",\n  \"components.Settings.RadarrModal.apiKey\": \"API Anahtarı\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Temel URL Adresi\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Yeni Bir 4K Radarr Sunucusu Ekle\",\n  \"components.Settings.RadarrModal.createradarr\": \"Yeni Bir Radarr Sunucusu Ekle\",\n  \"components.Settings.RadarrModal.default4kserver\": \"Varsayılan 4K Sunucu\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Varsayılan Sunucu\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"4K Radarr Sunucusunu Düzenle\",\n  \"components.Settings.RadarrModal.editradarr\": \"Radarr Sunucusunu Düzenle\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Otomatik Aramayı Etkinleştir\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Harici URL\",\n  \"components.Settings.RadarrModal.hostname\": \"Domain ya da IP Adresi\",\n  \"components.Settings.RadarrModal.inCinemas\": \"Sinemalarda\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Etiketler yükleniyor…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Ana klasör yükleniyor…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Asgari Erişilebilirlik Ayarı\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Etiket yok.\",\n  \"components.Settings.RadarrModal.port\": \"Port\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Kalite Seçeneği\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Kaliteyi seç\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Ana klasörü seç\",\n  \"components.Settings.RadarrModal.selecttags\": \"Etiketleri seç\",\n  \"components.Settings.RadarrModal.server4k\": \"4K Sunucu\",\n  \"components.Settings.RadarrModal.servername\": \"Sunucu İsmi\",\n  \"components.Settings.RadarrModal.ssl\": \"SSL Kullan\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Taramayı Etkinleştir\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Etiket Talepleri\",\n  \"components.Settings.RadarrModal.tags\": \"Etiketler\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Kalite seçeneklerini görüntülemek için bağlantıyı test et\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Ana klasörleri görüntülemek için bağlantıyı test et\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Etiketleri görüntülemek için bağlantıyı test et\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Radarr'a bağlanılamadı.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr'a başarıyla bağlanıldı!\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Geçerli bir URL adresi girmelisiniz\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL'nizin sonunda slash (eğik çizgi) olmamalıdır\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL'nizin başında slash (eğik çizgi) olmalıdır\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Temel URL slash (eğik çizgi) ile bitmemelidir\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Asgari erişilebilirlik ayarı seçmelisin\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Bir sunucu ismi girmelisin\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Geçerli bir port numarası girmelisin\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Bir kalite seçeneği seçmelisin\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Bir ana klasör seçmelisin\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Mevcut Sürüm\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Güncel Sürüm\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Yayınlanan Sürümler\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} Sürüm Notları\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Sürüm Notlarını Gör\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Github'da Görüntüle\",\n  \"components.Settings.SettingsAbout.about\": \"Hakkında\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Veri Dizini\",\n  \"components.Settings.SettingsAbout.documentation\": \"Dökümantasyon\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Destek Al\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub Tartışmaları\",\n  \"components.Settings.SettingsAbout.timezone\": \"Zaman Dilimi\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Toplam İçerik\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Toplam Talep\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Güncel\",\n  \"components.Settings.SettingsAbout.version\": \"Sürüm\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"İçerik Kullanılabilirliğini Eşitle\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Önbelleğe Al\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr, performansı optimize etmek ve gereksiz API çağrıları yapmaktan kaçınmak için harici API uç noktalarına gelen istekleri önbelleğe alır.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} önbelleği temizlendi.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Tutulan\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Toplam Anahtar\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Anahtar Boyutu\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Kayıplar\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Önbellek İsmi\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"İşlemi Durdur\",\n  \"components.Settings.SettingsJobsCache.command\": \"Komut\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"İndirilenleri Eşitle\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"İndirilenler Eşitlemesini Sıfırla\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"İşlemi Düzenle\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Mevcut Crontab\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Yeni Crontab\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Her {jobScheduleMinutes, plural, one {dakikada} other {{jobScheduleMinutes} dakika}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Her {jobScheduleSeconds, plural, one {saniyede} other {{jobScheduleSeconds} saniye}}\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Önbelleği Temizle\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Görüntü Önbellek Temizleme\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Görüntü Önbelleği\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Önbelleğe Alınan Görüntüler\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Toplam Önbellek Boyutu\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Tam Jellyfin Kütüphane Taraması\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Jellyfin En Son Eklenenler Taraması\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Anime Ana Dizini\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"İşlem başarıyla düzenlendi!\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname} iptal edildi.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"İşlem İsmi\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"İşlemler & Önbellek\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} başladı.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Tür\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Bir Sonraki İşlem\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Tam Plex Kütüphane Taraması\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plex En Son Eklenenler Taraması\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex İzleme Listesi Senkronizasyonu\",\n  \"components.Settings.SettingsJobsCache.process\": \"Süreç\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr Taraması\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Şimdi Başlat\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr Taraması\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Bilinmeyen İşlem\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Loglar panoya kopyalandı.\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Panoya Kopyala\",\n  \"components.Settings.SettingsLogs.extraData\": \"İlave Veri\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Sorun Ayıkla\",\n  \"components.Settings.SettingsLogs.filterError\": \"Sorun\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Bilgilendirme\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Uyarı\",\n  \"components.Settings.SettingsLogs.label\": \"Etiket\",\n  \"components.Settings.SettingsLogs.level\": \"Önem Derecesi\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Log Detayları\",\n  \"components.Settings.SettingsLogs.logs\": \"Loglar\",\n  \"components.Settings.SettingsLogs.message\": \"Mesaj\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Durdur\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Devam Ettir\",\n  \"components.Settings.SettingsLogs.showall\": \"Tüm Logları Göster\",\n  \"components.Settings.SettingsLogs.time\": \"Tarih Bilgisi\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Detayları Görüntüle\",\n  \"components.Settings.SettingsMain.apikey\": \"API Anahtarı\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Uygulama Başlığı\",\n  \"components.Settings.SettingsMain.applicationurl\": \"Uygulama URL'si\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Resim Önbelleğe Alma'yı Etkinleştir\",\n  \"components.Settings.SonarrModal.apiKey\": \"API Anahtarı\",\n  \"components.Settings.SettingsMain.general\": \"Genel\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Genel Ayarlar\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Kullanılabilir İçerikleri Gizle\",\n  \"components.Settings.SettingsMain.locale\": \"Uygulama Dili\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Keşfet Dili\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"İçerikleri orijinal dillerine göre filtrele\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Kısmi Dizi Taleplerini Kabul Et\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Yeni API anahtarı denenirken beklenmedik bir hata oluştu.\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Ayarlar kaydedilirken beklenmedik bir hata oluştu.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Ayarlar başarıyla kaydedildi!\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Bir uygulama başlığı girmelisiniz\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Geçerli bir URL adresi girmelisiniz\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL'nizin sonunda slash (eğik çizgi) olmamalıdır\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Öntanımlı İzinler\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Yeni kayıt yapmış kullanıcılara verilen izinler\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Local (Yerel) Oturum Açmayı Etkinleştir\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Genel Film Talep Etme Sınırı\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"{mediaServerName}'den Kayıtsız Oturum Açmayı Etkinleştir\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"{mediaServerName} kullanıcılarının içe aktarılmadan oturum açmalarına izin ver\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Ayarlar kaydedilirken beklenmedik bir hata oluştu.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Kullanıcı ayarları başarıyla kaydedildi!\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Genel Dizi Talep Etme Sınırı\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Kullanıcı Ayarları\",\n  \"components.Settings.SettingsUsers.users\": \"Kullanıcılar\",\n  \"components.Settings.SonarrModal.add\": \"Sunucu Ekle\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Anime Dizisi Türü\",\n  \"components.Settings.SonarrModal.animeTags\": \"Anime Etiketleri\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Anime Dil Seçenekleri\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Anime Kalite Seçenekleri\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Yeni 4K Sonarr Sunucusu Ekle\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Yeni Sonarr Sunucusu Ekle\",\n  \"components.Settings.SonarrModal.default4kserver\": \"Varsayılan 4K Sunucu\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Varsayılan Sunucu\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"4K Sonarr Sunucusunu Düzenle\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Otomatik Aramayı Etkinleştir\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Harici URL\",\n  \"components.Settings.SonarrModal.hostname\": \"Domain ya da IP Adresi\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Dil Seçeneği\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Etiketler yükleniyor…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Kalite seçenekleri yükleniyor…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Ana klasör yükleniyor…\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Etiket yok.\",\n  \"components.Settings.SonarrModal.port\": \"Port\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Kalite Seçeneği\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Ana Klasör\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Sezon Klasörleri\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Dil seçeneğini seç\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Kaliteyi seç\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Ana klasörü seç\",\n  \"components.Settings.SonarrModal.selecttags\": \"Etiketleri seç\",\n  \"components.Settings.SonarrModal.seriesType\": \"Dizinin Türü\",\n  \"components.Settings.SonarrModal.server4k\": \"4K Sunucu\",\n  \"components.Settings.SonarrModal.ssl\": \"SSL Kullan\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Taramayı Etkinleştir\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Etiket Talepleri\",\n  \"components.Settings.SonarrModal.tags\": \"Etiketler\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Dil seçeneklerini görmek için bağlantıyı test et\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Kalite seçeneklerini görmek için bağlantıyı test et\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Ana klasörleri yüklemek için bağlantıyı test et\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Etiketleri yüklemek için bağlantıyı test et\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Sonarr'a bağlanılamadı.\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Bir API anahtarı girmelisiniz\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Geçerli bir URL adresi girmelisiniz\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL'nizin sonunda slash (eğik çizgi) olmamalıdır\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Temel URL'nizin başında slash (eğik çizgi) olmalıdır\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Geçerli bir sunucu adresi girmelisin\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Bir dil seçeneği seçmelisin\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Geçerli bir port numarası girmelisin\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Bir kalite seçeneği girmelisin\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Bir ana klasör seçmelisin\",\n  \"components.Settings.activeProfile\": \"Etkin Profil\",\n  \"components.Settings.addradarr\": \"Radarr Sunucusu Ekle\",\n  \"components.Settings.address\": \"Adres\",\n  \"components.Settings.addsonarr\": \"Sonarr Sunucusu Ekle\",\n  \"components.Settings.cancelscan\": \"Taramayı İptal Et\",\n  \"components.Settings.currentlibrary\": \"Mevcut Kütüphane: {name}\",\n  \"components.Settings.default\": \"Öntanımlı\",\n  \"components.Settings.default4k\": \"Öntanımlı 4K\",\n  \"components.Settings.deleteServer\": \"{serverType} Sunucusunu Sil\",\n  \"components.Settings.deleteserverconfirm\": \"Bu sunucuyu silmek istediğinize emin misiniz?\",\n  \"components.Settings.email\": \"E-mail\",\n  \"components.Settings.enablessl\": \"SSL Kullan\",\n  \"components.Settings.externalUrl\": \"Harici URL\",\n  \"components.Settings.hostname\": \"Domain ya da IP Adresi\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName} Ayarları\",\n  \"components.Settings.jellyfinSettingsFailure\": \"{mediaServerName} ayarları kaydedilirken beklenmedik bir hata oluştu.\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName} ayarları başarıyla kaydedildi!\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName} Kütüphaneler\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"{mediaServerName} medya sunucunuzda içerik taraması yapılacak. Eğer hiç bir kütüphane listelenmediyse 'Kütüphaneleri Eşitle' butonunu kullanın.\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName} Ayarları\",\n  \"components.Settings.jellyfinsettingsDescription\": \"{mediaServerName} sunucunuz için ayarları düzenleyin. {mediaServerName} sunucunuzun kütüphaneleri içlerinde ki içerikleri tespiti için taranacaktır.\",\n  \"components.Settings.librariesRemaining\": \"Kalan Kütüphaneler: {count}\",\n  \"components.Settings.manualscan\": \"Kütüphaneleri Manuel Tara\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Normalde rutin olarak bu işlem 24 saatte bir yapılır. Seerr {mediaServerName} sunucunuzun en son eklenenlerini sıklıkla kontrol eder. Eğer ki bu Seerr'ı ilk yapılandırışınız ise tek seferlik manuel kütüphane taraması yapmanız önerilir!\",\n  \"components.Settings.mediaTypeMovie\": \"Film\",\n  \"components.Settings.menuAbout\": \"Hakkında\",\n  \"components.Settings.menuGeneralSettings\": \"Genel\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.menuLogs\": \"Loglar\",\n  \"components.Settings.menuNotifications\": \"Bildirimler\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Servisler\",\n  \"components.Settings.menuUsers\": \"Kullanıcılar\",\n  \"components.Settings.mediaTypeSeries\": \"dizi\",\n  \"components.Settings.noDefaultServer\": \"Talebin işlenebilmesi için en azından bir {serverType} sunucusunun {mediaType} içerikleri için öntanımlı olarak işaretlenmesi gerekmektedir.\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Bildirim aracılarını yapılandırın ve etkinleştirin\",\n  \"components.Settings.notifications\": \"Bildirimler\",\n  \"components.Settings.notificationsettings\": \"Bildirim Ayarları\",\n  \"components.Settings.notrunning\": \"Çalışmıyor\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.plexlibraries\": \"Plex Kütüphaneler\",\n  \"components.Settings.plexlibrariesDescription\": \"Seerr'in başlıklar için taradığı kütüphaneler. Plex bağlantı ayarlarınızı kurun ve kaydedin, ardından hiçbir kütüphane listelenmemişse aşağıdaki düğmeye tıklayın.\",\n  \"components.Settings.plexsettings\": \"Plex Ayarları\",\n  \"components.Settings.port\": \"Port\",\n  \"components.Settings.radarrsettings\": \"Radarr Ayarları\",\n  \"components.Settings.restartrequiredTooltip\": \"Bu ayarda yapılan değişikliklerin etkili olması için Seerr'in yeniden başlatılması gerekir\",\n  \"components.Settings.save\": \"Değişiklikleri Kaydet\",\n  \"components.Settings.saving\": \"Kaydediliyor…\",\n  \"components.Settings.scan\": \"Kütüphaneleri Eşitle\",\n  \"components.Settings.scanning\": \"Eşitleniyor…\",\n  \"components.Settings.serverLocal\": \"local (yerel)\",\n  \"components.Settings.serverRemote\": \"remote (uzak)\",\n  \"components.Settings.serverSecure\": \"güvenli\",\n  \"components.Settings.serverpreset\": \"Sunucu\",\n  \"components.Settings.serverpresetLoad\": \"Kullanılabilir suncuuları yüklemek için butona bas\",\n  \"components.Settings.serverpresetManualMessage\": \"Özel ayarlamalar\",\n  \"components.Settings.serverpresetRefreshing\": \"Sunucular getiriliyor…\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack bildirim ayarları kaydedildi!\",\n  \"components.Settings.Notifications.authUser\": \"SMPT Kullanıcı Adı\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"<OpenPgpLink>OpenPGP</OpenPgpLink> kullanarak e-mailleri imzala ve şifrele\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord test bildirimi gönderilemedi.\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Asgari erişilebilirlik ayarını seç\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Geçerli bir sunucu adresi girmelisin\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Dış kaynaklardan alınan resimleri önbelleğe al (depolama kullanımını arttıracaktır)\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"<WebhookLink>Bir Webhook</WebhookLink> entegrasyonu oluştur\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord bildirim ayarları kaydedildi!\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Her daim STARTTLS kullan\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Discord deneme bildirimi gönderiliyor…\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Sunucunuz için bir <DiscordWebhookLink>Webhook</DiscordWebhookLink> entegrasyonu oluştur\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Eski Sürüm\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Seerr'in yalnızca geliştirmeye katkıda bulunan veya en son testlere yardımcı olan kişiler için önerilen <code>develop</code> dalını çalıştırıyorsunuz.\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Değer Boyutu\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Ayarlarda etkinleştirildiğinde, Seerr önceden yapılandırılmış harici kaynaklardan gelen görüntüleri proxy'leyecek ve önbelleğe alacaktır. Önbelleğe alınan görüntüler yapılandırma klasörünüze kaydedilir. Dosyaları <code>{appDataPath}/cache/images</code> konumunda bulabilirsiniz.\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Genel ve varsayılan kullanıcı ayarlarını yapılandırın.\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Sonarr Sunucusunu Düzenle\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Otomatik olarak isteyenin kullanıcı adını ek etiketlere ekle\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr'a başarıyla bağlanıldı!\",\n  \"components.Settings.experimentalTooltip\": \"Bu ayarı etkinleştirmek uygulamanın beklenmedik davranışlarda bulunmasına sebep olabilir\",\n  \"components.Settings.noDefaultNon4kServer\": \"Eğer ki hem 4K hem de 4K-olmayan içerikler için tek tip bir {serverType} sunucusu kullanıyorsan (ya da sadece 4K içerikleri indiriyorsan) {serverType} sunucunu <strong>KESİNLİKLE</strong> 4K olarak ayarlamaman gerekmektedir.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Web bildirim ayarları kaydedilemedi.\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Bir bot yetkilendirme token'i sağlamalısın\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Kalite seçenekleri yükleniyor…\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Otomatik olarak isteyenin kullanıcı adını ek etiketlere ekle\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Bir API anahtarı girmelisiniz\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Çıkışıyla ilgili veri henüz mevcut değildir.\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Her {jobScheduleHours, plural, one {saatte} other {{jobScheduleHours} hours}}\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"İşlem kaydedilirken beklenmedik bir hata oluştu.\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"İşlemler\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Seerr için genel ve varsayılan ayarları yapılandırın.\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Bir sunucu ismi girmelisin\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Talep Etğe bağlı olarak {mediaServerName} medya sunucunuz için dahili ve harici uç noktaları yapılandırabilirsiniz. Çoğu durumda, harici URL dahili URL'den farklıdır. Farklı bir parola sıfırlama sayfasına yönlendirmek istemeniz durumunda {mediaServerName} medya sunucunuz için özel bir parola sıfırlama URL'si de ayarlanabilir. Ayrıca, daha önce otomatik olarak oluşturulan Jellyfin API anahtarını da değiştirebilirsiniz..\",\n  \"components.Settings.noDefault4kServer\": \"Kullanıcıların 4K {mediaType} talepleri yapabilmesi için 4K {serverType} sunucusu öntanımlı olarak işaretlenmelidir.\",\n  \"components.Settings.plexsettingsDescription\": \"Plex sunucunuz için ayarları yapılandırın. Seerr, içerik kullanılabilirliğini belirlemek için Plex kitaplıklarınızı tarar.\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Geçerli bir URL girmelisiniz\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Kullanıcıların botunuzla sohbet başlatmalarına ve kendi bildirimlerini yapılandırmalarına izin verin\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Geçerli bir sunucu adresi girmelisin\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Kullanıcıların e-posta adreslerini ve parolalarını kullanarak oturum açmalarına izin verin\",\n  \"components.Settings.advancedTooltip\": \"Bu ayarın yanlış yapılandırılması işlevselliğin bozulmasına neden olabilir\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Pushover deneme bildirimi gönderiliyor…\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"30 karakterlik <UsersGroupsLink>kullanıcı ya da grup kimliği</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Webhook deneme bildirimi gönderilemedi.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"E-mail deneme bildirimi gönderiliyor…\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Yeni API anahtarı başarıyla oluşturuldu!\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr, belirli bakım görevlerini düzenli olarak zamanlanmış işler olarak gerçekleştirir, ancak bunlar aşağıda manuel olarak da tetiklenebilir. Bir işi manuel olarak çalıştırmak, zamanlamasını değiştirmez.\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Bu günlükleri doğrudan <code>stdout</code> üzerinden veya <code>{appDataPath}/logs/seerr.log</code> dizininde görüntüleyebilirsiniz.\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Temel URL Adresi\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Dil seçenekleri yükleniyor…\",\n  \"components.Settings.SonarrModal.servername\": \"Sunucu İsmi\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Temel URL slash (eğik çizgi) ile bitmemelidir\",\n  \"components.Settings.manualscanDescription\": \"Normalde, bu yalnızca her 24 saatte bir çalıştırılır. Seerr, Plex sunucunuzun son eklenenlerini sık sık kontrol edecektir. Plex'i ilk kez yapılandırıyorsanız, tek seferlik tam manuel kütüphane taraması önerilir!\",\n  \"components.Settings.manualscanJellyfin\": \"Kütüphaneleri Elle Tara\",\n  \"components.Settings.menuJobs\": \"İşlemler & Önbellek\",\n  \"components.Settings.serviceSettingsDescription\": \"{serverType} sunucu(lar)ınızı aşağıdan yapılandırın. Birden fazla {serverType} sunucusuna bağlanabilirsiniz, ancak sadece iki tanesi varsayılan olarak tanımlanabilir (bir adet 4K ve bir adet 4K dışı). Yöneticiler sunucuları her daim mutlak bir biçimde yönetebilirler.\",\n  \"components.Settings.services\": \"Servisler\",\n  \"components.Settings.settingUpPlexDescription\": \"Plex'i kurmak için, ayrıntıları manuel olarak girebilir veya <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink> adresinden alınan bir sunucuyu seçebilirsiniz. Kullanılabilir sunucuların listesini almak için açılır menünün sağındaki düğmeyi kullanın.\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Taramaya Başla\",\n  \"components.Settings.syncJellyfin\": \"Kütüphaneleri Eşitle\",\n  \"components.Settings.tautulliApiKey\": \"API Anahtarı\",\n  \"components.Settings.tautulliSettings\": \"Tautulli Ayarları\",\n  \"components.Settings.timeout\": \"Zaman Aşımı\",\n  \"components.Settings.toastPlexConnecting\": \"Plex'e yeniden bağlanılıyor…\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Plex'e bağlanılamadı.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex'e başarıyla bağlanıldı!\",\n  \"components.Settings.toastPlexRefresh\": \"Plex'den sunucu listesi alınıyor…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Plex'ten sunucu listesi alınamadı.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Plex'ten sunucu listesi başarıyla alınıldı!\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Tautulli ayarlarınızı kaydederken beklenmedik bir hatayla karşılaşıldı.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli ayarları başarıyla kaydedildi!\",\n  \"components.Settings.urlBase\": \"Temel URL Adresi\",\n  \"components.Settings.validationHostnameRequired\": \"Geçerli bir sunucu adresi girmelisin\",\n  \"components.Settings.validationPortRequired\": \"Geçerli bir port numarası girmelisin\",\n  \"components.Settings.validationUrl\": \"Geçerli bir URL adresi girmelisiniz\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"Temel URL slash (eğik çizgi) ile bitmemelidir\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL'nizin sonunda slash (eğik çizgi) olmamalıdır\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>Web Uygulaması</WebAppLink> Linki\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.webpush\": \"Web Bildirimi\",\n  \"components.Setup.configuremediaserver\": \"Medya Sunucusunu Düzenleyin\",\n  \"components.Setup.configureservices\": \"Servisleri Düzenleyin\",\n  \"components.Setup.continue\": \"Devam Et\",\n  \"components.Setup.finish\": \"Kurulumu Bitir\",\n  \"components.Setup.finishing\": \"Son Adımlar…\",\n  \"components.Setup.setup\": \"Kurulum\",\n  \"components.Setup.signin\": \"Oturum Açın\",\n  \"components.Setup.signinMessage\": \"Oturum açarak devam edin\",\n  \"components.Setup.signinWithPlex\": \"Plex bilgilerinizi girin\",\n  \"components.Setup.welcome\": \"Jellyseer'a Hoşgeldiniz\",\n  \"components.StatusBadge.managemedia\": \"{mediaType} içeriğini yönet\",\n  \"components.StatusBadge.openinarr\": \"{arr}'da Aç\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}B{episodeNumber}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Güncellendi\",\n  \"components.StatusChecker.reloadApp\": \"{applicationTitle}'ı Yenile\",\n  \"components.StatusChecker.restartRequired\": \"Sunucuyu Yeniden Başlatmalısınız\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Güncellenen ayarların etkinleşmesi için sunucuyu yeniden başlatın.\",\n  \"components.TitleCard.addToWatchList\": \"İzleme listesine ekle\",\n  \"components.TitleCard.cleardata\": \"Veriyi Temizle\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} Bulunamadı\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID'si\",\n  \"components.TitleCard.watchlistCancel\": \"<strong>{title}</strong> için olan izleme listesi iptal edildi.\",\n  \"components.TitleCard.watchlistError\": \"Bir şeyler ters gitti. Lütfen tekrar deneyin.\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> izleme listesine başarıyla eklendi!\",\n  \"components.TvDetails.Season.noepisodes\": \"Bölüm listesi mevcut değil.\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Sezon verisi alınırken bir şeyler ters gitti.\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Dizinin Tüm Oyuncuları\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Dizinin Tam Ekibi\",\n  \"components.TvDetails.anime\": \"Anime\",\n  \"components.TvDetails.cast\": \"Oyuncular\",\n  \"components.TvDetails.episodeRuntime\": \"Bölümün Süresi\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} dakika\",\n  \"components.TvDetails.firstAirDate\": \"İlk Yayın Tarihi\",\n  \"components.TvDetails.manageseries\": \"Diziyi Düzenle\",\n  \"components.TvDetails.nextAirDate\": \"Sonraki Çıkış tarihi\",\n  \"components.TvDetails.originallanguage\": \"Orijinal Dili\",\n  \"components.TvDetails.originaltitle\": \"Orijinal Başlık\",\n  \"components.TvDetails.overview\": \"Özet\",\n  \"components.TvDetails.play\": \"{mediaServerName} ile Oynat\",\n  \"components.TvDetails.play4k\": \"İçeriği {mediaServerName} içinde 4K oynat\",\n  \"components.TvDetails.recommendations\": \"Önerilenler\",\n  \"components.TvDetails.reportissue\": \"Sorun Bildir\",\n  \"components.TvDetails.rtaudiencescore\": \"Rotten Tomatoes İzleyici Puanı\",\n  \"components.TvDetails.rtcriticsscore\": \"Rotten Tomatoes Tomatometer\",\n  \"components.TvDetails.seasonnumber\": \"Sezon {seasonNumber}\",\n  \"components.TvDetails.network\": \"{networkCount} Yayın Platformu\",\n  \"components.TvDetails.seasons\": \"{seasonCount} # Sezon\",\n  \"components.TvDetails.tmdbuserscore\": \"TMBD Kullanıcı Skoru\",\n  \"components.TvDetails.viewfullcrew\": \"Tüm Ekibi Gör\",\n  \"components.TvDetails.watchtrailer\": \"Fragmanı İzle\",\n  \"components.UserList.accounttype\": \"Tür\",\n  \"components.UserList.admin\": \"Yönetici\",\n  \"components.UserList.autogeneratepassword\": \"Rastgele Bir Parola Oluştur\",\n  \"components.UserList.bulkedit\": \"Toplu Düzenle\",\n  \"components.UserList.create\": \"Oluştur\",\n  \"components.UserList.created\": \"Katılma\",\n  \"components.UserList.createlocaluser\": \"Yerel Kullanıcı Oluştur\",\n  \"components.UserList.creating\": \"Oluşturuluyor…\",\n  \"components.UserList.deleteuser\": \"Kullanıcıyı Sil\",\n  \"components.UserList.edituser\": \"Kullanıcının İzinlerini Düzenle\",\n  \"components.UserList.email\": \"E-mail Adresi\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} kullanıcısı başarıyla içeri aktarıldı!\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex kullanıcısı başarıyla içeri aktarıldı!\",\n  \"components.UserList.importfromJellyfin\": \"{mediaServerName} Kullanıcılarını İçe Aktar\",\n  \"components.UserList.importfrommediaserver\": \"{mediaServerName} Kullanıcılarını İçeri Aktar\",\n  \"components.UserList.importfromplex\": \"Plex Kullanıcılarını İçeri Aktar\",\n  \"components.UserList.importfromplexerror\": \"Plex kullanıcıları içeri aktarılırken bir şeyler ters gitti.\",\n  \"components.UserList.localLoginDisabled\": \"<strong>Yerel Oturum Açma</strong> seçeneği şu anda etin değil.\",\n  \"components.UserList.localuser\": \"Yerel Kullanıcı\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName} Kullanıcısı\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> İzleme listenizden başarıyla çıkarıldı!\",\n  \"components.Settings.sonarrsettings\": \"Sonarr Ayarları\",\n  \"components.Settings.syncing\": \"Eşitleniyor\",\n  \"components.Settings.tautulliSettingsDescription\": \"İsteğe bağlı olarak Tautulli sunucunuz için ayarları yapılandırın. Seerr, Plex medyanız için izleme geçmişi verilerini Tautulli'den alır.\",\n  \"components.Settings.validationApiKey\": \"Bir API anahtarı girmelisiniz\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"URL'nizin başında slash (eğik çizgi) olmalıdır\",\n  \"components.Settings.webAppUrlTip\": \"İsteğe bağlı olarak kullanıcıları \\\"hosted\\\" web uygulaması yerine sunucunuzdaki web uygulamasına yönlendirin\",\n  \"components.Setup.signinWithJellyfin\": \"Jellyfin bilgilerinizi girin\",\n  \"components.StatusBadge.playonplex\": \"{mediaServerName} ile Oynat\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Lütfen aşağıda ki butona tıklayarak uygulamayı yenileyin.\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID'si\",\n  \"components.TvDetails.similar\": \"Benzer Diziler\",\n  \"components.TvDetails.overviewunavailable\": \"Özet mevcut değil.\",\n  \"components.TvDetails.seasonstitle\": \"Sezonlar\",\n  \"components.UserList.autogeneratepasswordTip\": \"Kullanıcıya otomatik oluşturulmuş parolayı e-mail olarak gönder\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount} # Bölüm\",\n  \"components.UserList.importfromJellyfinerror\": \"{mediaServerName} kullanıcıları içeri aktarılırken bir şeyler ters gitti.\",\n  \"components.TvDetails.showtype\": \"Dizinin Türü\",\n  \"components.TvDetails.productioncountries\": \"Yapımcı {countryCount, plural, one {Ülke} other {Ülkeler}}\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.UserList.deleteconfirm\": \"Bu kullanıcıyı silmek istediğinizden emin misiniz? Tüm talep verisi temelli olarak silinecektir.\",\n  \"components.TvDetails.streamingproviders\": \"İçertiğin Erişilebilir Olduğu Platformlar\",\n  \"components.UserList.newplexsigninenabled\": \"<strong>Yeni Plex Kullanıcılarının Oturum Açmasına İzin Ver</strong> ayarı etkin durumdadır. Plex kullanıcılarından kütüphane erişimine sahip olanlarının oturum açabilmesi için içeri aktarılması gerekmez.\",\n  \"components.UserList.newJellyfinsigninenabled\": \"<strong>Yeni {mediaServerName} Kullanıcılarının Oturum Açmasına İzin Ver</strong> ayarı etkin durumdadır. {mediaServerName} kullanıcılarından kütüphane erişimine sahip olanlarının oturum açabilmesi için içeri aktarılması gerekmez.\",\n  \"components.UserList.noJellyfinuserstoimport\": \"İçeri aktarılacak {mediaServerName} kullanıcısı mevcut değil.\",\n  \"components.UserList.nouserstoimport\": \"İçeri aktarılacak Plex kullanıcısı mevcut değil.\",\n  \"components.UserList.owner\": \"Sahip\",\n  \"components.UserList.password\": \"Şifre\",\n  \"components.UserList.passwordinfodescription\": \"Bir uygulama URL'si ayarlayın ve otomatik şifre oluşturulabilmesi için e-mail bildirimlerini aktif edin.\",\n  \"components.UserList.plexuser\": \"Plex Kullanıcısı\",\n  \"components.UserList.role\": \"Rol\",\n  \"components.UserList.sortCreated\": \"Katılım Tarihi\",\n  \"components.UserList.sortDisplayName\": \"Görünen İsmi\",\n  \"components.UserList.sortRequests\": \"Talep Sayısı\",\n  \"components.UserList.totalrequests\": \"Talepler\",\n  \"components.UserList.user\": \"Kullanıcı\",\n  \"components.UserList.usercreatedsuccess\": \"Kullanıcı başarıyla oluşturuldu!\",\n  \"components.UserList.userdeleted\": \"Kullanıcı başarıyla silindi!\",\n  \"components.UserList.userdeleteerror\": \"Kullanıcıyı silerken bir şeyler ters gitti.\",\n  \"components.UserList.userfail\": \"Kullanıcının izinleri kaydedilirken bir şeyler ters gitti.\",\n  \"components.UserList.userlist\": \"Kullanıcı Listesi\",\n  \"components.UserList.users\": \"Kullanıcılar\",\n  \"components.UserList.userssaved\": \"Kullanıcının izni başarıyla kaydedildi!\",\n  \"components.UserList.validationpasswordminchars\": \"Girdiğiniz şifre çok kısa, en az 8 karakterden oluşmalıdır\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"{joindate} tarihinde katıldı\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Profili Görüntüle\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Ayarları Düzenle\",\n  \"components.UserProfile.ProfileHeader.userid\": \"Kullanıcı Kimliği: {userid}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Hesabın Türü\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Yönetici\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord Kullanıcı Kimliği\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Görünen İsmi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Genel Limiti Geçersiz Kıl\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Genel\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Genel Ayarlar\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"Varsayılan ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Yerel Kullanıcı\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName} Kullanıcısı\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Film Talep Etme Limiti\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Keşfet Dili\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"İçerikleri orijinal dillerine göre filtrele\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Sahip\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex Kullanıcısı\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Filmleri Otomatize Talep Ett\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Dizileri Otomatize Talep Ett\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"<PlexWatchlistSupportLink>Plex İzleme Listenizde</PlexWatchlistSupportLink>'ki dizileri otomatik olarak istet\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Keşfet Bölgesi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"İçerikleri bölgesel erişilebilirliklerine göre filtrele\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Değişiklikleri Kaydet\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Dizi Talep Etme Limiti\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Ayarlar kaydedilirken beklenmedik bir hata oluştu.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Ayarlar başarıyla kaydedildi!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Kullanıcı\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Cihaz Varsayılanı\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"Kullanıcı Kimliği\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Discord bildirim ayarları kaydedilemedi.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord bildirim ayarları kaydedildi!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"E-mail\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"E-mail bildirim ayarları kaydedilemedi.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"E-mail bildirim ayarları kaydedildi!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Bildirimler\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Bildirim Ayarları\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Açık (Public) PGP Anahtarı\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"E-mail mesajlarını <OpenPgpLink>OpenPGP</OpenPgpLink> kullanarak şifrele\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Erişim Token'i\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"<PushbulletSettingsLink>Hesap Ayarlarınızdan</PushbulletSettingsLink> bir token oluşturun\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Pushbullet bildirim ayarları kaydedilemedi.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Uygulama API'sinin Token'i\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"{applicationTitle} ile kullanabilmeniz için bir uygulama <ApplicationRegistrationLink>oluşturun</ApplicationRegistrationLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Kullanıcı ya da Grup Kimliği\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Pushover bildirim ayarları kaydedilemedi.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover bildirim ayarları kaydedildi!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Sessizce Gönder\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Bildirimler sessiz gönderilir\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Bildirim Sesi\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"Sohbet ID'si\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Bildirimler\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Telegram bildirim ayarları kaydedilemedi.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram bildirim ayarları kaydedildi!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Geçerli bir kullanıcı kimliği sağlamalısınız\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Geçerli bir PGP açık (public) anahtarı sağlamalısın\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Bir erişim token'i sağlamalısınız\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Geçerli bir kullanıcı ya da grup kimliği sağlamalısınız\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Geçerli bir sohbet ID'si sağlamalısın\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Web Bildirimi\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Şifreyi Doğrula\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Kullandığınız Şifre\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Yeni Şifre\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"Hesabın ayarlanmış bir şifreye sahip değil. Aşağıdan e-mail adresinizi kullanarak bir şifre belirlerseniz \\\"yerel kullanıcı\\\" olarak oturum açabilirsiniz.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"Bu kullanıcının şifresini değiştirme yetkisine sahip değilsin.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Şifre\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Şifre kaydedilirken bir hata oluştu, şu anda kullandığınız şifreyi doğru girdiğinizden emin olun.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Şifre başarıyla kaydedildi!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Yeni şifreyi doğrulamanız gerekmektedir\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Girdiğiniz şifreler uyuşmuyor\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Mevcut olarak kullandığınız şifrenizi girmediniz\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Yeni bir şifre girmediniz\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"İzinler\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Ayarlar kaydedilirken beklenmedik bir hata oluştu.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"İzinler başarıyla kaydedildi!\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Kendi izinlerini düzenleyemezsin.\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Şifre\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Genel\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"Bu kullanıcının ayarlarını düzenleme yetkin yok.\",\n  \"components.UserProfile.limit\": \"{limit} limitinizden {remaining} adet kaldı\",\n  \"components.UserProfile.localWatchlist\": \"{username} kullanıcısının İzleme Listesi\",\n  \"components.UserProfile.movierequests\": \"Film Talepleri\",\n  \"components.UserProfile.pastdays\": \"{type} (Yenilenmesine {days} gün kaldı)\",\n  \"components.UserProfile.plexwatchlist\": \"Plex İzleme Listen\",\n  \"components.UserProfile.recentlywatched\": \"Yakın Zamanda İzlendi\",\n  \"components.UserProfile.recentrequests\": \"Yakın Zamandaki Talepler\",\n  \"components.UserProfile.requestsperdays\": \"{limit}ı\",\n  \"components.UserProfile.seriesrequest\": \"Dizi Talepleri\",\n  \"components.UserProfile.totalrequests\": \"Toplam Talep\",\n  \"components.UserProfile.unlimited\": \"Sınırsız\",\n  \"i18n.advanced\": \"Gelişmiş\",\n  \"i18n.all\": \"Hepsi\",\n  \"i18n.approve\": \"Kabul Et\",\n  \"i18n.areyousure\": \"Emin misiniz?\",\n  \"i18n.available\": \"Kullanılabilir\",\n  \"i18n.back\": \"Geri\",\n  \"i18n.cancel\": \"İptal Et\",\n  \"i18n.canceling\": \"İptal Ediliyor…\",\n  \"i18n.close\": \"Kapat\",\n  \"i18n.collection\": \"Koleksiyon\",\n  \"i18n.decline\": \"Reddet\",\n  \"i18n.declined\": \"Reddedildi\",\n  \"i18n.delete\": \"Sil\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.edit\": \"Düzenle\",\n  \"i18n.experimental\": \"Deneysel\",\n  \"i18n.failed\": \"Başarısız\",\n  \"i18n.import\": \"İçe Aktar\",\n  \"i18n.importing\": \"İçe Aktarılıyor…\",\n  \"i18n.loading\": \"Yükleniyor…\",\n  \"i18n.movie\": \"Film\",\n  \"i18n.movies\": \"Filmler\",\n  \"i18n.next\": \"Sonraki\",\n  \"i18n.noresults\": \"Sonuç Bulunamadı.\",\n  \"i18n.open\": \"Açık\",\n  \"i18n.partiallyavailable\": \"Kısmen Mevcut\",\n  \"i18n.pending\": \"Beklemede\",\n  \"i18n.previous\": \"Önceki\",\n  \"i18n.processing\": \"İşleniyor\",\n  \"i18n.request\": \"Talep Et\",\n  \"i18n.request4k\": \"4K Talep Et\",\n  \"i18n.requested\": \"Talep Edildi\",\n  \"i18n.requesting\": \"Talep Ediliyor…\",\n  \"i18n.resolved\": \"Çözüldü\",\n  \"i18n.resultsperpage\": \"Sayfa'da {pageSize} sonuç gösteriliyor\",\n  \"i18n.retry\": \"Yeniden Dene\",\n  \"i18n.retrying\": \"Yeniden Deneniyor…\",\n  \"i18n.save\": \"Değişiklikleri Kaydet\",\n  \"i18n.saving\": \"Kaydediliyor…\",\n  \"i18n.settings\": \"Ayarlar\",\n  \"i18n.showingresults\": \"<strong>{from}</strong> ile <strong>{to}</strong> arasından toplam <strong>{total}</strong> sonuç var\",\n  \"i18n.status\": \"Durum\",\n  \"i18n.test\": \"Test Et\",\n  \"i18n.testing\": \"Test Ediliyor…\",\n  \"i18n.tvshow\": \"Dizi\",\n  \"i18n.tvshows\": \"Diziler\",\n  \"i18n.unavailable\": \"Mevcut Değil\",\n  \"i18n.usersettings\": \"Kullanıcı Ayarları\",\n  \"i18n.view\": \"Görüntüle\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"Dahili Sunucu Sorunsı\",\n  \"pages.oops\": \"Eyvah\",\n  \"pages.pagenotfound\": \"Sayfa Bulunamadı\",\n  \"pages.returnHome\": \"Anasayfaya Dön\",\n  \"pages.serviceunavailable\": \"Hizmet Erişilebilir Değil\",\n  \"pages.somethingwentwrong\": \"Bir Şeyler Ters Gitti\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Geçerli bir Discord ID'si sunmalısın\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Şifre kaydedilirken bir şeyler ters gitti.\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"İzinler\",\n  \"i18n.approved\": \"Kabul Edildi\",\n  \"i18n.deleting\": \"Siliniyor…\",\n  \"i18n.notrequested\": \"Talep Edilmedi\",\n  \"components.UserList.usercreatedfailed\": \"Kullanıcı oluşturulurken bir şeyler ters gitti.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Verilen e-mail adresi halihazırda başka bir kulllanıcı tarafından kullanılmaktadır.\",\n  \"components.UserList.validationEmail\": \"E-posta gerekli\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Uygulama Dili\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"<PlexWatchlistSupportLink>Plex İzleme Listenizde</PlexWatchlistSupportLink>'ki filmleri otomatik olarak talep Et\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Rolü\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Kaydediliyor…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"Hesabınız ile bağıntılı <FindDiscordIdLink>numaralardan oluşan kullanıcı ID'niz</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"30 karakterlik <UsersGroupsLink>kullanıcı ya da grup kimliği</UsersGroupsLink>\",\n  \"components.UserProfile.emptywatchlist\": \"<PlexWatchlistSupportLink>Plex İzleme Listenize</PlexWatchlistSupportLink> eklenen içerikler burada gözükeceklerdir.\",\n  \"i18n.restartRequired\": \"Yeniden Başlatma Gereklidir\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"Discord kullanıcı hesabınızla ilişkili <FindDiscordIdLink>çok haneli kimlik numarası</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet bildirim ayarları kaydedildi!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Bir sohbet başlatın</TelegramBotLink> ve <GetIdBotLink>@get_id_bot</GetIdBotLink> ID'li botunuzu ekleyin. Son olarak <code>/my_id</code> komutunu kullanın\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Geçerli bir uygulama token'i sağlamalısınız\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"Bu kullanıcının henüz ayarlanmış bir şifresi yok. Aşağıdan bir şifre ayarlayarak bu hesabın \\\"yerel kullanıcı\\\" olarak oturum açabilmesini sağlayın.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Girdiğiniz şifre çok kısa, en az 8 karakterden oluşmalıdır\",\n  \"components.MovieDetails.addtowatchlist\": \"İzleme Listeme Ekle\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> İzleme listesinden başarıyla kaldırıldı!\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> izleme listesine başarıyla eklendi!\",\n  \"components.MovieDetails.removefromwatchlist\": \"İzleme Listesinden Kaldır\",\n  \"components.TvDetails.addtowatchlist\": \"İzleme Listeme Ekle\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Geçerli bir e-posta gerekli\",\n  \"components.RequestList.RequestItem.profileName\": \"Profil\",\n  \"components.TvDetails.removefromwatchlist\": \"İzleme Listesinden Kaldır\",\n  \"components.Login.adminerror\": \"Oturum açmak için bir yönetici hesabı kullanmalısınız.\",\n  \"components.Login.enablessl\": \"SSL Kullan\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.invalidurlerror\": \"{mediaServerName} sunucusuna bağlanılamıyor.\",\n  \"components.Login.port\": \"Port\",\n  \"components.Login.urlBase\": \"URL Tabanı\",\n  \"components.Login.validationPortRequired\": \"Geçerli bir port numarası sağlamalısınız\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"URL tabanının başında eğik çizgi olmalıdır\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"URL tabanı eğik çizgiyle bitmemelidir\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL, eğik çizgiyle bitmemelidir\",\n  \"components.MovieDetails.watchlistError\": \"Bir şeyler ters gitti. Lütfen tekrar deneyin.\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> izleme listesine başarıyla eklendi!\",\n  \"components.Settings.invalidurlerror\": \"{mediaServerName} sunucusuna bağlanılamıyor.\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Parola Sıfırlama URL'si\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Otomatik Kitaplık Gruplandırması ile özel kimlik doğrulaması desteklenmiyor\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Kütüphaneler senkronize edilirken bir hata oluştu\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Hiç kütüphane bulunamadı\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> İzleme listesinden başarıyla kaldırıldı!\",\n  \"components.TvDetails.watchlistError\": \"Bir şeyler ters gitti. Lütfen tekrar deneyin.\",\n  \"components.UserList.username\": \"Kullanıcı adı\",\n  \"components.UserList.validationUsername\": \"Kullanıcı adınızı sağlamalısınız\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"E-posta gerekli\",\n  \"components.Login.back\": \"Geri git\",\n  \"components.Login.servertype\": \"Sunucu Türü\",\n  \"components.Setup.configemby\": \"Emby İle Devam Et\",\n  \"components.Login.validationservertyperequired\": \"Lütfen bir sunucu türü seçin\",\n  \"components.Selector.canceled\": \"İptal Edilen\",\n  \"components.Selector.returningSeries\": \"Geri Dönecek Diziler\",\n  \"components.Setup.back\": \"Geri Dön\",\n  \"components.Selector.ended\": \"Biten\",\n  \"components.Selector.inProduction\": \"Çekimde\",\n  \"components.Selector.pilot\": \"Pilot\",\n  \"components.Selector.planned\": \"Planlanan\",\n  \"components.Selector.searchStatus\": \"Durum seçin...\",\n  \"components.Setup.configjellyfin\": \"Jellyfin İle Devam Et\",\n  \"components.Setup.configplex\": \"Plex İle Devam Et\",\n  \"components.Setup.servertype\": \"Sunucu Türünü Seçin\",\n  \"components.Setup.signinWithEmby\": \"Emby bilgilerinizi girin\",\n  \"components.Setup.subtitle\": \"Medya sunucunuzu seçerek başlayın\",\n  \"components.StatusBadge.seasonnumber\": \"S{seasonNumber}\",\n  \"components.Discover.FilterSlideover.status\": \"Durum\",\n  \"components.Settings.Notifications.webhookRoleId\": \"Bildirim Rol Kimliği\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex Token'ını Yenile\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Keşfet Bölgesi\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"İçeriği bölgesel kullanılabilirliğe göre filtrele\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Dijital Yayın Bölgesi\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Bölgesel kullanılabilirliğe göre dijital yayınları göster\",\n  \"components.Settings.apiKey\": \"API anahtarı\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Keşfet Bölgesi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Dijital Yayın Bölgesi\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Bölgesel kullanılabilirliğe göre dijital yayınları göster\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Başka bir kullanıcı zaten bu kullanıcı adına sahip. Bir e-posta ayarlamalısınız\",\n  \"i18n.specials\": \"Özel Bölümler\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"Webhook mesajında bahsedilecek rol kimliği. Bahsetmeleri devre dışı bırakmak için boş bırakın\",\n  \"components.RequestList.RequestItem.removearr\": \"{arr}'dan kaldır\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Kullanıcıların Avatarları\",\n  \"components.Settings.scanbackground\": \"Tarama arka planda devam edecek. Kurulum sürecine devam edebilirsiniz.\",\n  \"components.Settings.tip\": \"İpucu\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Bu e-posta zaten alınmış!\",\n  \"components.RequestList.sortDirection\": \"Sıralama Yönünü Değiştir\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Geçerli bir Discord Rol Kimliği sağlamalısınız\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"İçeriği bölgesel kullanılabilirliğe göre filtrele\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Ayarlar kaydedilirken bir sorun oluştu.\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Parametre değişikliklerini uygulamadan önce koşulları belirtir. Kuralların uygulanması için her alan doğrulanmalıdır (VE işlem). Bir alan, özelliklerinden herhangi biri eşleşirse doğrulanmış kabul edilir (VEYA işlem).\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Kullanılan kimlik bilgileriniz ile Plex'e bağlanılamıyor\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Grup sohbetinizde konular etkinleştirilmişse, burada bir konu başlığı/konu kimliği belirtebilirsiniz\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Seerr'in proxy arkasındaki istemci IP adreslerini doğru şekilde kaydetmesine izin ver\",\n  \"components.Selector.searchUsers\": \"Kullanıcıları seçin…\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Bu harici hesaplar {applicationName} hesabınıza bağlıdır.\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Yaklaşan Diziler\",\n  \"components.Login.loginwithapp\": \"{appName} ile giriş yapın\",\n  \"components.Login.noadminerror\": \"Sunucuda yönetici kullanıcısı bulunamadı.\",\n  \"components.Login.orsigninwith\": \"veya giriş yapın\",\n  \"components.Settings.Notifications.messageThreadId\": \"Konu/Konu Kimliği\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"Konu/konu kimliği pozitif bir tam sayı olmalıdır\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Koşullar\",\n  \"components.Settings.OverrideRuleModal.create\": \"Kural oluştur\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Yeni Geçersiz Kılma Kuralı\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Geçersiz Kılma Kuralını Düzenle\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Türler\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Anahtar kelimeler\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Diller\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Etiket yok.\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Kalite Profili\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Kök Klasör\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Geçersiz kılma kuralı başarıyla oluşturuldu!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Geçersiz kılma kuralı başarıyla güncellendi!\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Kök klasörü seç\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Kalite profilini seç\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Etiket seç\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Bu kuralı seçili servise uygula.\",\n  \"components.Settings.OverrideRuleModal.service\": \"Servis\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Servis seç\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Ayarlar\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Yukarıdaki koşullar sağlandığında hangi ayarların değiştirileceğini belirtir.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Etiketler\",\n  \"components.Settings.OverrideRuleModal.users\": \"Kullanıcılar\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Koşullar\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Tür\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Anahtar kelimeler\",\n  \"components.Settings.OverrideRuleTile.language\": \"Dil\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Kalite Profili\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Kök Klasör\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Ayarlar\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Etiketler\",\n  \"components.Settings.OverrideRuleTile.users\": \"Kullanıcılar\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Özel Bölüm Taleplerine İzin Ver\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"CSRF Korumasını Etkinleştir\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"Ne yaptığınızı bilmiyorsanız bu ayarı ETKİNLEŞTİRMEYİN!\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Harici API erişimini salt okunur olarak ayarlayın (HTTPS gerektirir)\",\n  \"components.Settings.SettingsNetwork.docs\": \"belgeleme\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Seerr'in IPv6 yerine öncelikli olarak IPv4 adreslerine bağlanmasını zorunlu kılın\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Öncelike IPv4 Bağlantısını Zorla\",\n  \"components.Settings.SettingsNetwork.network\": \"Ağ\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Bu ayarlar yerine konteynerinizden/sisteminizden gelen ağ parametreleri kullanılmalıdır. Daha fazla bilgi için {docs}'a bakın.\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Ağ Ayarları\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Seerr örneğiniz için ağ ayarlarını yapılandırın.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Alt etki alanları için ayırıcı olarak ',' ve joker karakter olarak '*.' kullanın\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Yerel Adresler için Proxy Kullanma\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) Proxy\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Proxy Ana Bilgisayar Adı\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Proxy Şifresi\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Proxy Bağlantı Noktası\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Proxy İçin SSL Kullanın\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Proxy Kullanıcı Adı\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Proxy Tarafından Yoksayılan Adresler\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Ayarlar başarıyla kaydedildi!\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Proxy Desteğini Etkinleştir\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Geçerli bir bağlantı noktası sağlamalısınız\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"En az bir kimlik doğrulama yöntemi seçilmelidir.\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Giriş Yöntemleri\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Kullanıcılar için oturum açma yöntemlerini yapılandırın.\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"{mediaServerName} ile Oturum Açmayı Etkinleştir\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Kullanıcıların {mediaServerName} hesaplarını kullanarak oturum açmalarına izin ver\",\n  \"components.Settings.addrule\": \"Yeni Geçersiz Kılma Kuralı\",\n  \"components.Settings.menuNetwork\": \"Ağ\",\n  \"components.Settings.overrideRules\": \"Geçersiz Kılma Kuralları\",\n  \"components.Settings.overrideRulesDescription\": \"Geçersiz kılma kuralları, bir talep kuralla eşleşirse değiştirilecek özellikleri belirtmenize olanak tanır.\",\n  \"components.Setup.librarieserror\": \"Doğrulama başarısız oldu. Devam etmek için lütfen kütüphaneleri tekrar değiştirin.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Hesabınızı {applicationName} ile bağlamak için {mediaServerName} kimlik bilgilerinizi girin.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Bu hesap zaten bir {applicationName} kullanıcısına bağlı\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Kullanılan kimlik bilgileriniz ile {mediaServerName} sunucusuna bağlanılamadı\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Bilinmeyen bir hata oluştu\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Şifre\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Bağlantı\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Ekleniyor…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"{mediaServerName} Hesabını Bağla\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Kullanıcı adı\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Kullanıcı adı sağlamalısınız\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Bağlantılı hesap silinemiyor.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Bilinmeyen bir hata oluştu\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Bağlantılı Hesaplar\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"Hesabınıza bağlı herhangi bir harici hesabınız bulunmamaktadır.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"Bu kullanıcının bağlantılı hesaplarını değiştirme yetkiniz yok.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Bu hesap zaten bir Plex kullanıcısına bağlı\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"Konu/Konu Kimliği\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Grup sohbetinizde konular etkinleştirilmişse, burada bir konu başlığının/konunun kimliğini belirtebilirsiniz\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"Konu/konu kimliği pozitif bir tam sayı olmalıdır\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Bağlantılı Hesaplar\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Şifre sağlamanız gerekiyor\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/uk.json",
    "content": "{\n  \"components.AirDateBadge.airedrelative\": \"Ефір {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Ефір {relativeTime}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Підключення тома <code>{appDataPath}</code> налаштовано неправильно. Всі дані будуть видалені при зупинці або перезапуску контейнера.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} фільмів\",\n  \"components.CollectionDetails.overview\": \"Огляд\",\n  \"components.CollectionDetails.requestcollection\": \"Запит на Колекцію\",\n  \"components.CollectionDetails.requestcollection4k\": \"Запит на Колекцію в 4К\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Фільми в жанрі \\\"{genre}\\\"\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Фільми мовою \\\"{language}\\\"\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"Серіали {network}\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"Фільми {studio}\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"Серіали в жанрі {genre}\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"Серіали мовою {language}\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"Ваш список перегляду Plex\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Список перегляду Plex\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"Фільми за жанрами\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"Фільми за жанрами\",\n  \"components.Discover.NetworkSlider.networks\": \"Телеканали\",\n  \"components.Discover.StudioSlider.studios\": \"Студії\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"Серіали за жанрами\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"Серіали за жанрами\",\n  \"components.Discover.discover\": \"Знайти щось нове\",\n  \"components.Discover.emptywatchlist\": \"Тут з’являться медіафайли, додані до вашого <PlexWatchlistSupportLink>списку спостереження Plex</PlexWatchlistSupportLink>.\",\n  \"components.Discover.plexwatchlist\": \"Ваш список перегляду Plex\",\n  \"components.Discover.popularmovies\": \"Популярні фільми\",\n  \"components.Discover.populartv\": \"Популярні серіали\",\n  \"components.Discover.recentlyAdded\": \"Нещодавно додані\",\n  \"components.Discover.recentrequests\": \"Останні запити\",\n  \"components.Discover.trending\": \"У трендах\",\n  \"components.Discover.upcoming\": \"Майбутні фільми\",\n  \"components.Discover.upcomingmovies\": \"Майбутні фільми\",\n  \"components.Discover.upcomingtv\": \"Майбутні серіали\",\n  \"components.DownloadBlock.estimatedtime\": \"Приблизно {time}\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: Сезон {seasonNumber} Епізод {episodeNumber}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"Ви впевнені, що хочете видалити цей коментар?\",\n  \"components.IssueDetails.IssueComment.delete\": \"Видалити коментар\",\n  \"components.IssueDetails.IssueComment.edit\": \"Редагувати коментар\",\n  \"components.IssueDetails.IssueComment.postedby\": \"Опубліковано {relativeTime} користувачем {username}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"Опубліковано {relativeTime} користувачем {username} (змінено)\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"Ви повинні ввести повідомлення\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"Видалити проблему\",\n  \"components.IssueDetails.IssueDescription.description\": \"Опис\",\n  \"components.IssueDetails.IssueDescription.edit\": \"Редагувати опис\",\n  \"components.IssueDetails.allepisodes\": \"Всі епізоди\",\n  \"components.IssueDetails.allseasons\": \"Всі сезони\",\n  \"components.IssueDetails.closeissue\": \"Закрити проблему\",\n  \"components.IssueDetails.closeissueandcomment\": \"Закрити з коментарем\",\n  \"components.IssueDetails.commentplaceholder\": \"Додати коментар…\",\n  \"components.IssueDetails.comments\": \"Коментарі\",\n  \"components.IssueDetails.deleteissue\": \"Видалити проблему\",\n  \"components.IssueDetails.deleteissueconfirm\": \"Ви впевнені, що хочете видалити цю проблему?\",\n  \"components.IssueDetails.episode\": \"Епізод {episodeNumber}\",\n  \"components.IssueDetails.issuepagetitle\": \"Проблема\",\n  \"components.IssueDetails.issuetype\": \"Тип\",\n  \"components.IssueDetails.lastupdated\": \"Останнє оновлення\",\n  \"components.IssueDetails.leavecomment\": \"Коментар\",\n  \"components.IssueDetails.nocomments\": \"Коментарів немає.\",\n  \"components.IssueDetails.openedby\": \"#{issueId} відкрита {relativeTime} користувачем {username}\",\n  \"components.IssueDetails.openin4karr\": \"Відкрити в 4К {arr}\",\n  \"components.IssueDetails.openinarr\": \"Відкрити в {arr}\",\n  \"components.IssueDetails.play4konplex\": \"Відтворити в {mediaServerName} у 4К\",\n  \"components.IssueDetails.playonplex\": \"Відтворити в {mediaServerName}\",\n  \"components.IssueDetails.problemepisode\": \"Зачеплений епізод\",\n  \"components.IssueDetails.problemseason\": \"Зачеплений сезон\",\n  \"components.IssueDetails.reopenissue\": \"Знову відкрити проблему\",\n  \"components.IssueDetails.reopenissueandcomment\": \"Знову відкрити з коментарем\",\n  \"components.IssueDetails.season\": \"Сезон {seasonNumber}\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"Щось пішло не так при редагуванні опису проблеми.\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Опис проблеми успішно відредаговано!\",\n  \"components.IssueDetails.toastissuedeleted\": \"Проблема успішно видалена!\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"Щось пішло не так при видаленні проблеми.\",\n  \"components.IssueDetails.toaststatusupdated\": \"Статус проблеми успішно оновлено!\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"Щось пішло не так при оновленні статусу проблеми.\",\n  \"components.IssueDetails.unknownissuetype\": \"Невідомий\",\n  \"components.IssueList.IssueItem.episodes\": \"{episodeCount, plural, one {Епізод} other {Епізоди}}\",\n  \"components.IssueList.IssueItem.issuestatus\": \"Статус\",\n  \"components.IssueList.IssueItem.issuetype\": \"Тип\",\n  \"components.IssueList.IssueItem.opened\": \"Відкрито\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} користувачем {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"Зачеплений епізод\",\n  \"components.IssueList.IssueItem.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезони}}\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"Невідомий\",\n  \"components.IssueList.IssueItem.viewissue\": \"Переглянути проблему\",\n  \"components.IssueList.issues\": \"Проблеми\",\n  \"components.IssueList.showallissues\": \"Показати всі проблеми\",\n  \"components.IssueList.sortAdded\": \"За датою додавання\",\n  \"components.IssueList.sortModified\": \"За датою зміни\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"Всі епізоди\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"Всі сезони\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"Епізод {episodeNumber}\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"Додатково\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"Зачеплений епізод\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"Зачеплений сезон\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"Будь ласка, надайте детальний опис проблеми, з якою ви зіткнулися.\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"Повідомити про проблему\",\n  \"components.IssueModal.CreateIssueModal.season\": \"Сезон {seasonNumber}\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"Надіслати проблему\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"Щось пішло не так під час надсилання проблеми.\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"Звіт про проблему для <strong>{title}</strong> успішно надіслано!\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"Переглянути проблему\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"Ви повинні надати опис\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"Що не так?\",\n  \"components.IssueModal.issueAudio\": \"Аудіо\",\n  \"components.IssueModal.issueOther\": \"Інше\",\n  \"components.IssueModal.issueSubtitles\": \"Субтитри\",\n  \"components.IssueModal.issueVideo\": \"Відео\",\n  \"components.LanguageSelector.languageServerDefault\": \"За замовчуванням ({language})\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"Всі мови\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"Мова інтерфейсу\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"Пошук фільмів та серіалів\",\n  \"components.Layout.Sidebar.dashboard\": \"Знайти щось нове\",\n  \"components.Layout.Sidebar.issues\": \"Проблеми\",\n  \"components.Layout.Sidebar.requests\": \"Запити\",\n  \"components.Layout.Sidebar.settings\": \"Налаштування\",\n  \"components.Layout.Sidebar.users\": \"Користувачі\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"Запити на фільми\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"Запити на сезони\",\n  \"components.Layout.UserDropdown.myprofile\": \"Профіль\",\n  \"components.Layout.UserDropdown.requests\": \"Запити\",\n  \"components.Layout.UserDropdown.settings\": \"Налаштування\",\n  \"components.Layout.UserDropdown.signout\": \"Вихід\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"{commitsBehind} {commitsBehind, plural, one {комміт} other {коммітів}} позаду\",\n  \"components.Layout.VersionStatus.outofdate\": \"Застаріла\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Версія Seerr для розробки\",\n  \"components.Layout.VersionStatus.streamstable\": \"Стабільна версія Seerr\",\n  \"components.Login.email\": \"Адреса електронної пошти\",\n  \"components.Login.forgotpassword\": \"Забули пароль?\",\n  \"components.Login.loginerror\": \"Щось пішло не так при спробі виконати вхід.\",\n  \"components.Login.password\": \"Пароль\",\n  \"components.Login.signin\": \"Увійти\",\n  \"components.Login.signingin\": \"Виконується вхід...\",\n  \"components.Login.signinheader\": \"Увійдіть, щоб продовжити\",\n  \"components.Login.signinwithoverseerr\": \"Використовуйте ваш обліковий запис {applicationTitle}\",\n  \"components.Login.signinwithplex\": \"Використовуйте ваш обліковий запис Plex\",\n  \"components.Login.validationemailrequired\": \"Ви повинні вказати дійсну адресу електронної пошти\",\n  \"components.Login.validationpasswordrequired\": \"Ви повинні надати пароль\",\n  \"components.ManageSlideOver.alltime\": \"Весь час\",\n  \"components.ManageSlideOver.downloadstatus\": \"Завантаження\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"Просунутий\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"Очистити дані\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* Це призведе до незворотного видалення всіх даних для цього {mediaType}а, включаючи будь-які запити. Якщо цей елемент існує у вашій бібліотеці {mediaServerName}, мультимедійна інформація про нього буде відтворена під час наступного сканування.\",\n  \"components.ManageSlideOver.manageModalIssues\": \"Відкриті проблеми\",\n  \"components.ManageSlideOver.manageModalMedia\": \"Media\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K Media\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"Запитів немає.\",\n  \"components.ManageSlideOver.manageModalRequests\": \"Запити\",\n  \"components.ManageSlideOver.manageModalTitle\": \"Управління {mediaType}ом\",\n  \"components.ManageSlideOver.mark4kavailable\": \"Позначити як доступний у 4К\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"Позначити всі сезони як доступні в 4K\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"Позначити всі сезони як доступні\",\n  \"components.ManageSlideOver.markavailable\": \"Позначити як доступний\",\n  \"components.ManageSlideOver.movie\": \"фільм\",\n  \"components.ManageSlideOver.openarr\": \"Відкрити в {arr}\",\n  \"components.ManageSlideOver.openarr4k\": \"Відкрити в 4К {arr}\",\n  \"components.ManageSlideOver.opentautulli\": \"Відкрити в Tautulli\",\n  \"components.ManageSlideOver.pastdays\": \"Останні {days, number} днів\",\n  \"components.ManageSlideOver.playedby\": \"Переглядає\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> {playCount, plural, one {перегляд} other {переглядів}}\",\n  \"components.ManageSlideOver.tvshow\": \"серіал\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"Подивитися більше\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"Повний акторський склад\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"Повна знімальна група\",\n  \"components.MovieDetails.budget\": \"Бюджет\",\n  \"components.MovieDetails.cast\": \"У ролях\",\n  \"components.MovieDetails.digitalrelease\": \"Цифровий випуск\",\n  \"components.MovieDetails.managemovie\": \"Керувати фільмом\",\n  \"components.MovieDetails.mark4kavailable\": \"Позначити як доступний у 4К\",\n  \"components.MovieDetails.markavailable\": \"Позначити як доступний\",\n  \"components.MovieDetails.originallanguage\": \"Мова оригіналу\",\n  \"components.MovieDetails.originaltitle\": \"Назва оригіналу\",\n  \"components.MovieDetails.overview\": \"Огляд\",\n  \"components.MovieDetails.overviewunavailable\": \"Огляд недоступний.\",\n  \"components.MovieDetails.physicalrelease\": \"Фізичний реліз\",\n  \"components.MovieDetails.productioncountries\": \"{countryCount, plural, one {Країна} other {Країни}} виробництва\",\n  \"components.MovieDetails.recommendations\": \"Рекомендації\",\n  \"components.MovieDetails.releasedate\": \"{releaseCount, plural, one {Дата релізу} other {Дати релізу}}\",\n  \"components.MovieDetails.reportissue\": \"Повідомити про проблему\",\n  \"components.MovieDetails.revenue\": \"Дохід\",\n  \"components.MovieDetails.rtaudiencescore\": \"Оцінка аудиторії Rotten Tomatoes\",\n  \"components.MovieDetails.rtcriticsscore\": \"Томатометр Rotten Tomatoes\",\n  \"components.MovieDetails.runtime\": \"{minutes} хвилин\",\n  \"components.MovieDetails.showless\": \"Згорнути\",\n  \"components.MovieDetails.showmore\": \"Розгорнути\",\n  \"components.MovieDetails.similar\": \"Схожі фільми\",\n  \"components.MovieDetails.streamingproviders\": \"Зараз транслюється\",\n  \"components.MovieDetails.studio\": \"{studioCount, plural, one {Студія} other {Студії}}\",\n  \"components.MovieDetails.theatricalrelease\": \"Вихід у кінотеатр\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB Оцінка користувача\",\n  \"components.MovieDetails.viewfullcrew\": \"Подивитися повну знімальну групу\",\n  \"components.MovieDetails.watchtrailer\": \"Дивитись трейлер\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"Отримувати повідомлення, коли інші користувачі надсилають коментарі до проблем.\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"Отримувати повідомлення, коли проблеми відкриті заново іншими користувачами.\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"Отримувати повідомлення, коли проблеми вирішені іншими користувачами.\",\n  \"components.NotificationTypeSelector.issuecomment\": \"Коментар до проблеми\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"Надсилати повідомлення, коли до проблем з'являються нові коментарі.\",\n  \"components.NotificationTypeSelector.issuecreated\": \"Проблема опублікована\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"Надсилати повідомлення, коли з'являються повідомлення про проблеми.\",\n  \"components.NotificationTypeSelector.issuereopened\": \"Проблема відкрита знову\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"Надсилати повідомлення, коли проблеми відкриті заново.\",\n  \"components.NotificationTypeSelector.issueresolved\": \"Проблема вирішена\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"Надсилати повідомлення, коли проблеми отримують рішення.\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"Автоматичне схвалення медіазапитів\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"Надсилати повідомлення, коли користувачі надсилають нові медіазапити, які схвалюються автоматично.\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"Схвалення медіазапитів\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"Надсилати повідомлення, коли медіазапити схвалюються вручну.\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"Запит надіслано автоматично\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"Отримуйте сповіщення, коли нові медіазапити автоматично надсилаються для елементів у вашому списку перегляду Plex.\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"Доступні нові медіафайли\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"Надсилати повідомлення, коли запитані медіафайли стають доступними.\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"Відхилення медіазапитів\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"Надсилати повідомлення, коли медіазапити відхиляються.\",\n  \"components.NotificationTypeSelector.mediafailed\": \"Помилки при додаванні медіазапитів\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"Відправляти повідомлення, коли медіазапити не вдається додати до Radarr або Sonarr.\",\n  \"components.NotificationTypeSelector.mediarequested\": \"Запити медіафайлів\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"Надсилати повідомлення, коли користувачі надсилають нові медіазапити, які вимагають схвалення.\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"Типи повідомлень\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"Отримувати повідомлення, коли до проблем, про які ви повідомили, з'являються нові коментарі.\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"Отримувати повідомлення, коли інші користувачі повідомляють про проблеми.\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"Отримувати повідомлення, коли проблеми, про які ви повідомили, будуть відкриті заново.\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"Отримувати повідомлення, коли проблеми, про які ви повідомили, отримують рішення.\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"Отримувати повідомлення, коли інші користувачі надсилають нові медіазапити, які схвалюються автоматично.\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"Отримувати повідомлення, коли ваші медіазапити отримують схвалення.\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"Отримувати сповіщення, коли медіа, на які ви створили запит, стають доступними.\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"Отримувати повідомлення, коли медіазапити відхиляються.\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"Отримувати повідомлення, коли медіазапити не вдається додати до Radarr або Sonarr.\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"Отримувати повідомлення, коли інші користувачі надсилають нові медіазапити, які вимагають схвалення.\",\n  \"components.PermissionEdit.admin\": \"Адміністратор\",\n  \"components.PermissionEdit.adminDescription\": \"Адміністратор має повний доступ. Ігнорує всі інші налаштування дозволів.\",\n  \"components.PermissionEdit.advancedrequest\": \"Розширені запити\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"Надати дозвіл на зміну додаткових параметрів запиту.\",\n  \"components.PermissionEdit.autoapprove\": \"Автоматичне схвалення\",\n  \"components.PermissionEdit.autoapprove4k\": \"Автоматичне схвалення 4К\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"Надати дозвіл на автоматичне схвалення всіх 4К медіазапитів.\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"Автоматичне схвалення фільмів 4K\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"Надати дозвіл на автоматичне схвалення 4К фільмів.\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"Автоматичне схвалення 4К серіалів\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"Надати дозвіл на автоматичне схвалення 4К серіалів.\",\n  \"components.PermissionEdit.autoapproveDescription\": \"Надати дозвіл на автоматичне схвалення всіх медіазапитів, відмінних від 4К.\",\n  \"components.PermissionEdit.autoapproveMovies\": \"Автоматичне схвалення фільмів\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"Надати дозвіл на автоматичне схвалення всіх фільмів, відмінних від 4К.\",\n  \"components.PermissionEdit.autoapproveSeries\": \"Автоматичне схвалення серіалів\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"Надати дозвіл на автоматичне схвалення всіх серіалів, відмінних від 4K.\",\n  \"components.PermissionEdit.autorequest\": \"Автоматичний запит\",\n  \"components.PermissionEdit.autorequestDescription\": \"Надайте дозвіл на автоматичне надсилання запитів на медіафайли, відмінні від 4K, через список перегляду Plex.\",\n  \"components.PermissionEdit.autorequestMovies\": \"Автоматичний запит фільмів\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"Надайте дозвіл на автоматичне надсилання запитів на фільми, відмінні від 4K, через список перегляду Plex.\",\n  \"components.PermissionEdit.autorequestSeries\": \"Автоматичний запит Серіалів\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"Надайте дозвіл на автоматичне надсилання запитів на серіали, відмінні від 4K, через список перегляду Plex.\",\n  \"components.PermissionEdit.createissues\": \"Повідомлення про проблеми\",\n  \"components.PermissionEdit.createissuesDescription\": \"Надати дозвіл на повідомлення про проблеми з медіафайлами.\",\n  \"components.PermissionEdit.manageissues\": \"Управління проблемами\",\n  \"components.PermissionEdit.manageissuesDescription\": \"Надати дозвіл на керування проблемами з медіафайлами.\",\n  \"components.PermissionEdit.managerequests\": \"Керування запитами\",\n  \"components.PermissionEdit.managerequestsDescription\": \"Надати дозвіл на керування медіазапитами. Всі запити користувача, що має цю роздільну здатність, будуть схвалюватися автоматично.\",\n  \"components.PermissionEdit.request\": \"Запити\",\n  \"components.PermissionEdit.request4k\": \"Запити 4K\",\n  \"components.PermissionEdit.request4kDescription\": \"Надати дозвіл на надсилання запитів медіафайлів у 4К.\",\n  \"components.PermissionEdit.request4kMovies\": \"Запити фільмів у 4К\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"Надати дозвіл на надсилання запитів фільмів у 4К.\",\n  \"components.PermissionEdit.request4kTv\": \"Запити серіалів у 4К\",\n  \"components.PermissionEdit.request4kTvDescription\": \"Надати дозвіл на надсилання запитів серіалів у 4К.\",\n  \"components.PermissionEdit.requestDescription\": \"Надати дозвіл на надсилання запитів усіх медіафайлів, відмінних від 4К.\",\n  \"components.PermissionEdit.requestMovies\": \"Запити фільмів\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"Надати дозвіл на надсилання запитів усіх фільмів, відмінних від 4К.\",\n  \"components.PermissionEdit.requestTv\": \"Запити серіалів\",\n  \"components.PermissionEdit.requestTvDescription\": \"Надати дозвіл на надсилання запитів усіх серіалів, відмінних від 4К.\",\n  \"components.PermissionEdit.users\": \"Керування користувачами\",\n  \"components.PermissionEdit.usersDescription\": \"Надати дозвіл на керування користувачами. Користувачі з цим дозволом не можуть надавати права адміністратора та редагувати користувачів, які є адміністраторами.\",\n  \"components.PermissionEdit.viewissues\": \"Перегляд проблем\",\n  \"components.PermissionEdit.viewissuesDescription\": \"Надати дозвіл на перегляд проблем з медіафайлами, про які повідомили інші користувачі.\",\n  \"components.PermissionEdit.viewrecent\": \"Переглянути нещодавно додані\",\n  \"components.PermissionEdit.viewrecentDescription\": \"Надайте дозвіл на перегляд списку нещодавно доданих медіа.\",\n  \"components.PermissionEdit.viewrequests\": \"Перегляд запитів\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"Надати дозвіл на перегляд медіазапитів, надісланих іншими користувачами.\",\n  \"components.PermissionEdit.viewwatchlists\": \"Перегляд списків переглядів Plex\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"Надайте дозвіл на перегляд списків перегляду Plex інших користувачів.\",\n  \"components.PersonDetails.alsoknownas\": \"Також відомий(а) як: {names}\",\n  \"components.PersonDetails.appearsin\": \"Появи у фільмах та серіалах\",\n  \"components.PersonDetails.ascharacter\": \"в ролі {character}\",\n  \"components.PersonDetails.birthdate\": \"Народжений {birthdate}\",\n  \"components.PersonDetails.crewmember\": \"У складі знімальної групи\",\n  \"components.PersonDetails.lifespan\": \"{birthdate} – {deathdate}\",\n  \"components.QuotaSelector.days\": \"{count, plural, one {день} other {днів}}\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} на {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.movies\": \"{count, plural, one {фільм} other {фільми}}\",\n  \"components.QuotaSelector.seasons\": \"{count, plural, one {сезон} other {сезони}}\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} на {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.unlimited\": \"Необмежено\",\n  \"components.RegionSelector.regionDefault\": \"Всі регіони\",\n  \"components.RegionSelector.regionServerDefault\": \"За замовчуванням ({region})\",\n  \"components.RequestBlock.approve\": \"Підтвердити запит\",\n  \"components.RequestBlock.decline\": \"Відхилити запит\",\n  \"components.RequestBlock.delete\": \"Видалити запит\",\n  \"components.RequestBlock.edit\": \"Редагувати запит\",\n  \"components.RequestBlock.languageprofile\": \"Мовний профіль\",\n  \"components.RequestBlock.lastmodifiedby\": \"Востаннє змінено\",\n  \"components.RequestBlock.profilechanged\": \"Профіль якості\",\n  \"components.RequestBlock.requestdate\": \"Дата запиту\",\n  \"components.RequestBlock.requestedby\": \"З проханням\",\n  \"components.RequestBlock.requestoverrides\": \"Перевизначення запиту\",\n  \"components.RequestBlock.rootfolder\": \"Кореневий каталог\",\n  \"components.RequestBlock.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезони}}\",\n  \"components.RequestBlock.server\": \"Сервер-одержувач\",\n  \"components.RequestButton.approve4krequests\": \"Схвалити {requestCount, plural, one {4К запит} other {{requestCount} 4К запиту(ів)}}\",\n  \"components.RequestButton.approverequest\": \"Схвалити запит\",\n  \"components.RequestButton.approverequest4k\": \"Схвалити 4К запит\",\n  \"components.RequestButton.approverequests\": \"Схвалити {requestCount, plural, one {запит} other {{requestCount} запиту(ів)}}\",\n  \"components.RequestButton.decline4krequests\": \"Відхилити {requestCount, plural, one {4К запит}} other {{requestCount} 4К запиту(ів)}}\",\n  \"components.RequestButton.declinerequest\": \"Відхилити запит\",\n  \"components.RequestButton.declinerequest4k\": \"Відхилити 4К запит\",\n  \"components.RequestButton.declinerequests\": \"Відхилити {requestCount, plural, one {запит} other {{requestCount} запиту(ів)}}\",\n  \"components.RequestButton.requestmore\": \"Створити більше запитів\",\n  \"components.RequestButton.requestmore4k\": \"Створити більше запитів у 4К\",\n  \"components.RequestButton.viewrequest\": \"Подивитися запит\",\n  \"components.RequestButton.viewrequest4k\": \"Подивитися 4К запит\",\n  \"components.RequestCard.approverequest\": \"Підтвердити запит\",\n  \"components.RequestCard.cancelrequest\": \"Скасувати запит\",\n  \"components.RequestCard.declinerequest\": \"Відхилити запит\",\n  \"components.RequestCard.deleterequest\": \"Видалити запит\",\n  \"components.RequestCard.editrequest\": \"Редагувати запит\",\n  \"components.RequestCard.failedretry\": \"Щось пішло не так при спробі повторити запит.\",\n  \"components.RequestCard.mediaerror\": \"{mediaType} Не знайдено\",\n  \"components.RequestCard.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезони}}\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestCard.unknowntitle\": \"Невідома назва\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"Скасувати запит\",\n  \"components.RequestList.RequestItem.deleterequest\": \"Видалити запит\",\n  \"components.RequestList.RequestItem.editrequest\": \"Редагувати запит\",\n  \"components.RequestList.RequestItem.failedretry\": \"Щось пішло не так при спробі повторити запит.\",\n  \"components.RequestList.RequestItem.mediaerror\": \"{mediaType} Не знайдено\",\n  \"components.RequestList.RequestItem.modified\": \"Змінено\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{date} користувачем {user}\",\n  \"components.RequestList.RequestItem.requested\": \"Запрошений\",\n  \"components.RequestList.RequestItem.requesteddate\": \"Запрошений\",\n  \"components.RequestList.RequestItem.seasons\": \"{seasonCount, plural, one {Сезон} other {Сезони}}\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"Невідома назва\",\n  \"components.RequestList.requests\": \"Запити\",\n  \"components.RequestList.showallrequests\": \"Показати всі запити\",\n  \"components.RequestList.sortAdded\": \"За датою\",\n  \"components.RequestList.sortModified\": \"Остання зміна\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"Розширені налаштування\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"* Цей серіал - аніме.\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name} (за замовчуванням)\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"Сервер-одержувач\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path} ({space})\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"Мовний профіль\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"Тегів немає.\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"Профіль якості\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"Запитати як\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"Кореневий каталог\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"Вибрати теги\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"Теги\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"Вам дозволено запитувати <strong>{limit}</strong> {type} кожні <strong>{days}</strong> днів.\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"Цьому користувачеві дозволено запитувати <strong>{limit}</strong> {type} кожні <strong>{days}</strong> днів.\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"фільм\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"{limit, plural, one {фільм} other {фільмів}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"Залишилося недостатньо запитів на сезони\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"Ви можете переглянути зведення ваших обмежень на кількість запитів на <ProfileLink>сторінці вашого профілю</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"Ви можете переглянути зведення обмежень на кількість запитів цього користувача на <ProfileLink>сторінці його профілю</ProfileLink>.\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {Запитів на {type} не залишилося} other {Залишилось <strong>#</strong> запити(ів) на {type}}}\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"Вам необхідно мати принаймні <strong>{seasons}</strong> {seasons, plural, one {запит на сезони} other {запити(ів) на сезони}} для того, щоб надіслати запит на цей серіал.\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"Цьому користувачеві необхідно мати принаймні <strong>{seasons}</strong> {seasons, plural, one {запит на сезони} other {запити(ів) на сезони}} для того, щоб надіслати запит на цей серіал.\",\n  \"components.RequestModal.QuotaDisplay.season\": \"сезон\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"{limit, plural, one {сезон} other {сезонів}}\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"Нам не вдалося знайти відповідність для цього серіалу.\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"Нам не вдалося автоматично знайти цей серіал. Будь ласка, виберіть правильний збіг зі списку нижче.\",\n  \"components.RequestModal.alreadyrequested\": \"Вже запрошений\",\n  \"components.RequestModal.approve\": \"Схвалити запит\",\n  \"components.RequestModal.autoapproval\": \"Автоматичне схвалення\",\n  \"components.RequestModal.cancel\": \"Скасувати запит\",\n  \"components.RequestModal.edit\": \"Редагувати запит\",\n  \"components.RequestModal.errorediting\": \"Щось пішло не так під час редагування запиту.\",\n  \"components.RequestModal.numberofepisodes\": \"# епізодів\",\n  \"components.RequestModal.pending4krequest\": \"Очікуючий запит в 4К\",\n  \"components.RequestModal.pendingapproval\": \"Ваш запит чекає схвалення.\",\n  \"components.RequestModal.pendingrequest\": \"Очікуючий запит\",\n  \"components.RequestModal.requestApproved\": \"Запит на <strong>{title}</strong> схвалений!\",\n  \"components.RequestModal.requestCancel\": \"Запит на <strong>{title}</strong> скасовано.\",\n  \"components.RequestModal.requestSuccess\": \"<strong>{title}</strong> успішно запрошений!\",\n  \"components.RequestModal.requestadmin\": \"Цей запит буде схвалено автоматично.\",\n  \"components.RequestModal.requestcancelled\": \"Запит на <strong>{title}</strong> скасовано.\",\n  \"components.RequestModal.requestcollection4ktitle\": \"Запит на колекцію в 4K\",\n  \"components.RequestModal.requestcollectiontitle\": \"Збір запитів\",\n  \"components.RequestModal.requestedited\": \"Запит на <strong>{title}</strong> успішно відредаговано!\",\n  \"components.RequestModal.requesterror\": \"Щось пішло не так під час надсилання запиту.\",\n  \"components.RequestModal.requestfrom\": \"Запит користувача {username} очікує схвалення.\",\n  \"components.RequestModal.requestmovie4ktitle\": \"Надіслати запит на фільм у 4K\",\n  \"components.RequestModal.requestmovies\": \"Запит {count} {count, plural, one {фільма} other {фільмів}}\",\n  \"components.RequestModal.requestmovies4k\": \"Запит {count} {count, plural, one {фільма} other {фільмів}} у 4К\",\n  \"components.RequestModal.requestmovietitle\": \"Запит на фільм\",\n  \"components.RequestModal.requestseasons\": \"Запит {seasonCount} {seasonCount, plural, one {сезон} other {сезони(ів)}}\",\n  \"components.RequestModal.requestseasons4k\": \"Запит {seasonCount} {seasonCount, plural, one {сезону} other {сезонів}} у 4К\",\n  \"components.RequestModal.requestseries4ktitle\": \"Запит на серіал у 4K\",\n  \"components.RequestModal.requestseriestitle\": \"Запит на серіал\",\n  \"components.RequestModal.season\": \"Сезон\",\n  \"components.RequestModal.seasonnumber\": \"Сезон {number}\",\n  \"components.RequestModal.selectmovies\": \"Виберіть фільм(и)\",\n  \"components.RequestModal.selectseason\": \"Виберіть сезон(и)\",\n  \"components.ResetPassword.confirmpassword\": \"Підтвердити пароль\",\n  \"components.ResetPassword.email\": \"Адреса електронної пошти\",\n  \"components.ResetPassword.emailresetlink\": \"Надіслати посилання для відновлення електронною поштою\",\n  \"components.ResetPassword.gobacklogin\": \"Повернутися до сторінки входу\",\n  \"components.ResetPassword.password\": \"Пароль\",\n  \"components.ResetPassword.passwordreset\": \"Скинути пароль\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"Посилання для скидання пароля буде надіслано на вказану адресу електронної пошти, якщо вона пов'язана з дійсним користувачем.\",\n  \"components.ResetPassword.resetpassword\": \"Скидання пароля\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"Пароль скинутий успішно!\",\n  \"components.ResetPassword.validationemailrequired\": \"Ви повинні вказати дійсну адресу електронної пошти\",\n  \"components.ResetPassword.validationpasswordmatch\": \"Паролі повинні збігатися\",\n  \"components.ResetPassword.validationpasswordminchars\": \"Пароль занадто короткий: він повинен містити не менше 8 символів\",\n  \"components.ResetPassword.validationpasswordrequired\": \"Ви повинні надати пароль\",\n  \"components.Search.search\": \"Пошук\",\n  \"components.Search.searchresults\": \"Результати пошуку\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"Увімкнути агента\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Не вдалося зберегти налаштування сповіщень Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Налаштування сповіщень Gotify успішно збережено!\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Не вдалося надіслати тестове сповіщення Gotify.\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Надсилання тестового сповіщення Gotify…\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Тестове сповіщення Gotify надіслано!\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"Маркер програми\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"Сервер URL\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"Ви повинні надати маркер програми\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"Необхідно вибрати принаймні один тип сповіщення\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"Ви повинні надати дійсну URL-адресу\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"URL-адреса не має закінчуватися косою рискою\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"Токен доступу\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"Створіть токен у <PushbulletSettingsLink>налаштуваннях облікового запису</PushbulletSettingsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"Активувати службу\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"Тег каналу\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Не вдалося зберегти налаштування сповіщень Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Налаштування сповіщень Pushbullet успішно збережено!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Не вдалося надіслати тестове повідомлення до Pushbullet.\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"Надсилання тестового повідомлення в Pushbullet…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Тестове повідомлення надіслано в Pushbullet!\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"Ви повинні надати токен доступу\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"Ви повинні вибрати хоча б один тип повідомлень\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"Токен API програми\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>Зареєструйте програму</ApplicationRegistrationLink> для використання з Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"Активувати службу\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Не вдалося зберегти налаштування сповіщень Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Параметри сповіщень Pushover успішно збережені!\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Не вдалося надіслати тестове повідомлення Pushover.\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"Надсилання тестового повідомлення Pushover…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Тестове повідомлення надіслано в Pushover!\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"Ключ користувача або групи\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"Ваш тридцятизначний <UsersGroupsLink>ідентифікатор користувача або групи</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"Ви повинні надати дійсний токен програми\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"Ви повинні вибрати хоча б один тип повідомлень\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"Ви повинні надати дійсний ключ користувача або групи\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"Активувати службу\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Не вдалося зберегти налаштування повідомлень Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Налаштування повідомлень Slack успішно збережено!\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Не вдалося надіслати тестове повідомлення до Slack.\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"Надсилання тестового повідомлення у Slack…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Тестове повідомлення надіслано до Slack!\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"Ви повинні вибрати хоча б один тип повідомлень\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"Ви повинні вказати дійсну URL-адресу\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"URL веб-перехоплювача\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"Створіть інтеграцію <WebhookLink>вхідного веб-перехоплювача</WebhookLink>\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"Активувати службу\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Щоб отримувати веб-push-сповіщення, Seerr повинен обслуговуватися за протоколом HTTPS.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"Не вдалося надіслати тестове веб-push-сповіщення.\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"Надсилання тестового веб-push-сповіщення…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"Тестове веб-повідомлення надіслано!\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"Не вдалося зберегти налаштування веб-повідомлень.\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"Налаштування веб-повідомлень успішно збережено!\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"Активувати службу\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Заголовок авторизації\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"Корисне навантаження JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"Скинути до стандартних налаштувань\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"Корисне навантаження JSON успішно скинуто до стандартних налаштувань!\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"Допомога за змінними шаблону\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Не вдалося надіслати тестове повідомлення веб-перехоплювачу.\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"Надсилання тестового повідомлення веб-перехоплювачу…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Тестове повідомлення веб-перехоплювачу надіслано!\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"Ви повинні надати допустиме корисне навантаження JSON\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"Ви повинні вибрати хоча б один тип повідомлень\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"Ви повинні вказати дійсну URL-адресу\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"URL веб-перехоплювача\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Не вдалося зберегти налаштування повідомлень веб-перехоплювача.\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Налаштування повідомлень веб-перехоплювача успішно збережено!\",\n  \"components.Settings.Notifications.agentenabled\": \"Активувати службу\",\n  \"components.Settings.Notifications.allowselfsigned\": \"Дозволити самозавірені сертифікати\",\n  \"components.Settings.Notifications.authPass\": \"Пароль SMTP\",\n  \"components.Settings.Notifications.authUser\": \"Ім'я користувача SMTP\",\n  \"components.Settings.Notifications.botAPI\": \"Токен авторизації бота\",\n  \"components.Settings.Notifications.botApiTip\": \"<CreateBotLink>Створіть бота</CreateBotLink> для використання з Seerr\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"URL аватара бота\",\n  \"components.Settings.Notifications.botUsername\": \"Ім'я бота\",\n  \"components.Settings.Notifications.botUsernameTip\": \"Дозволити користувачам починати чат з вашим ботом і налаштовувати власні повідомлення\",\n  \"components.Settings.Notifications.chatId\": \"ID чату\",\n  \"components.Settings.Notifications.chatIdTip\": \"Почніть чат зі своїм ботом, додайте <GetIdBotLink>@get_id_bot</GetIdBotLink> і виконайте команду <code>/my_id</code>\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Не вдалося зберегти налаштування повідомлень Discord.\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Налаштування повідомлень Discord успішно збережено!\",\n  \"components.Settings.Notifications.emailsender\": \"Адреса відправника\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"Не вдалося зберегти налаштування повідомлень електронною поштою.\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"Налаштування повідомлень електронною поштою успішно збережено!\",\n  \"components.Settings.Notifications.enableMentions\": \"Увімкнути згадування\",\n  \"components.Settings.Notifications.encryption\": \"Метод шифрування\",\n  \"components.Settings.Notifications.encryptionDefault\": \"Використовувати STARTTLS, якщо доступно\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"Використовувати неявний TLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"Без шифрування\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"Завжди використовувати STARTTLS\",\n  \"components.Settings.Notifications.encryptionTip\": \"У більшості випадків неявний TLS використовує порт 465, а STARTTLS - порт 587\",\n  \"components.Settings.Notifications.pgpPassword\": \"Пароль PGP\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"Підписувати зашифровані повідомлення електронної пошти за допомогою <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"Закритий ключ PGP\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"Підписувати зашифровані повідомлення електронної пошти за допомогою <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.Settings.Notifications.sendSilently\": \"Надсилати без звуку\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"Надсилати повідомлення без звуку\",\n  \"components.Settings.Notifications.senderName\": \"Ім'я відправника\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP-хост\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP порт\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Не вдалося зберегти налаштування сповіщень Telegram.\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Налаштування сповіщень Telegram успішно збережено!\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Не вдалося надіслати тестове повідомлення до Discord.\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"Надсилання тестового повідомлення в Discord…\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Тестове повідомлення надіслано до Discord!\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"Не вдалося надіслати тестове повідомлення електронною поштою.\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"Надсилання тестового повідомлення електронною поштою…\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"Тестове повідомлення надіслано електронною поштою!\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Не вдалося надіслати тестове повідомлення до Telegram.\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"Надсилання тестового повідомлення в Telegram…\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Тестове повідомлення надіслано до Telegram!\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"Ви повинні надати токен авторизації бота\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"Ви повинні надати дійсний ID чату\",\n  \"components.Settings.Notifications.validationEmail\": \"Ви повинні вказати дійсну адресу електронної пошти\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"Ви повинні надати пароль PGP\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"Ви повинні надати дійсний закритий ключ PGP\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"Ви повинні вказати дійсне ім'я хоста або IP-адресу\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"Ви повинні вказати дійсний номер порту\",\n  \"components.Settings.Notifications.validationTypes\": \"Ви повинні вибрати хоча б один тип повідомлень\",\n  \"components.Settings.Notifications.validationUrl\": \"Ви повинні вказати дійсну URL-адресу\",\n  \"components.Settings.Notifications.webhookUrl\": \"URL веб-перехоплювача\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"Створіть <DiscordWebhookLink>інтеграцію веб-перехоплювача</DiscordWebhookLink> на своєму сервері\",\n  \"components.Settings.RadarrModal.add\": \"Додати сервер\",\n  \"components.Settings.RadarrModal.announced\": \"Анонсовано\",\n  \"components.Settings.RadarrModal.apiKey\": \"Ключ API\",\n  \"components.Settings.RadarrModal.baseUrl\": \"Базовий URL\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"Додати новий 4К сервер Radarr\",\n  \"components.Settings.RadarrModal.createradarr\": \"Додати новий сервер Radarr\",\n  \"components.Settings.RadarrModal.default4kserver\": \"4К сервер за промовчанням\",\n  \"components.Settings.RadarrModal.defaultserver\": \"Сервер за замовчуванням\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"Редагувати 4К сервер Radarr\",\n  \"components.Settings.RadarrModal.editradarr\": \"Редагувати сервер Radarr\",\n  \"components.Settings.RadarrModal.enableSearch\": \"Увімкнути автоматичний пошук\",\n  \"components.Settings.RadarrModal.externalUrl\": \"Зовнішня URL-адреса\",\n  \"components.Settings.RadarrModal.hostname\": \"Ім'я хоста або IP-адреса\",\n  \"components.Settings.RadarrModal.inCinemas\": \"У кіно\",\n  \"components.Settings.RadarrModal.loadingTags\": \"Завантаження тегів…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"Завантаження профілів якості…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"Завантаження кореневих каталогів…\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"Мінімальна доступність\",\n  \"components.Settings.RadarrModal.notagoptions\": \"Тегів немає.\",\n  \"components.Settings.RadarrModal.port\": \"Порт\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"Профіль якості\",\n  \"components.Settings.RadarrModal.released\": \"Випущено\",\n  \"components.Settings.RadarrModal.rootfolder\": \"Кореневий каталог\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"Виберіть мінімальну доступність\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"Виберіть профіль якості\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"Виберіть кореневий каталог\",\n  \"components.Settings.RadarrModal.selecttags\": \"Виберіть теги\",\n  \"components.Settings.RadarrModal.server4k\": \"4К сервер\",\n  \"components.Settings.RadarrModal.servername\": \"Назва сервера\",\n  \"components.Settings.RadarrModal.ssl\": \"Використовувати SSL\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"Увімкнути сканування\",\n  \"components.Settings.RadarrModal.tags\": \"Теги\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"Протестувати підключення для завантаження профілів якості\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"Протестувати підключення для завантаження кореневих каталогів\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"Протестувати підключення для завантаження тегів\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Не вдалося підключитися до Radarr.\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"З'єднання з Radarr встановлено успішно!\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"Ви повинні надати ключ API\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"Ви повинні вказати дійсну URL-адресу\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"URL-адреса не повинна закінчуватися косою рискою\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"Базова URL-адреса повинна мати косу риску на початку\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"Базова URL-адреса не повинна закінчуватися косою рискою\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"Ви повинні вказати дійсне ім'я хоста або IP-адресу\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"Ви повинні вибрати мінімальну доступність\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"Ви повинні вказати ім'я сервера\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"Ви повинні вказати дійсний номер порту\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"Ви повинні вибрати профіль якості\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"Ви повинні вибрати кореневий каталог\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"Поточна\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"Остання\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"Дані про реліз наразі недоступні.\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"Релізи\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"Зміни у версії {version}\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"Переглянути список змін\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"Подивитися на GitHub\",\n  \"components.Settings.SettingsAbout.about\": \"Про проект\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"Каталог даних\",\n  \"components.Settings.SettingsAbout.documentation\": \"Документація\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"Отримати підтримку\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"Обговорення на GitHub\",\n  \"components.Settings.SettingsAbout.outofdate\": \"Застаріла\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"Ви використовуєте гілку <code>develop</code> проєкту Seerr, яка рекомендується тільки для тих, хто робить внесок у розробку або допомагає в тестуванні.\",\n  \"components.Settings.SettingsAbout.timezone\": \"Часовий пояс\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"Усього мультимедіа\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"Усього запитів\",\n  \"components.Settings.SettingsAbout.uptodate\": \"Актуальна\",\n  \"components.Settings.SettingsAbout.version\": \"Версія\",\n  \"components.Settings.SettingsJobsCache.cache\": \"Кеш\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr кешує запити до зовнішніх кінцевих точок API, щоб оптимізувати продуктивність і уникнути непотрібних викликів API.\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} кеш скинутий.\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"Вдалих звернень\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"Усього ключів\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"Розмір ключів\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"Невдалих звернень\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"Назва кеша\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"Розмір значень\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"Скасувати завдання\",\n  \"components.Settings.SettingsJobsCache.command\": \"Команда\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"Синхронізувати завантаження\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"Скинути синхронізацію завантажень\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"Змінити завдання\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"Поточна частота\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"Частота\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"Кожен {jobScheduleHours, plural, one {година} other {{jobScheduleHours} години(ів)}}\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"Кожну {jobScheduleMinutes, plural, one {хвилину} other {{jobScheduleMinutes} хвилин(и)}}\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"Очистити кеш\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Нещодавно додане сканування Jellyfin\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Сканування повної бібліотеки Jellyfin\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"Очищення кешу зображень\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"Кеш зображень\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"Якщо в налаштуваннях увімкнено, Seerr буде проксі-сервером і кешувати зображення з попередньо налаштованих зовнішніх джерел. Кешовані зображення зберігаються у папці конфігурації. Ви можете знайти файли в <code>{appDataPath}/cache/images</code>.\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"Зображення кешовані\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"Загальний розмір кешу\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"Щось пішло не так при збереженні завдання.\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"Завдання успішно відредаговано!\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"Завдання \\\"{jobname}\\\" скасовано.\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"Назва завдання\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"Завдання\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr виконує певні завдання обслуговування як регулярно запланованих завдань, але вони також можуть бути запущені вручну нижче. Виконання завдання вручну не змінить його розклад.\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"Завдання та кеш\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"Завдання \\\"{jobname}\\\" запущено.\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"Тип\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"Наступне виконання\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Повне сканування бібліотек Plex\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Сканування нещодавно доданих медіафайлів у Plex\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Синхронізація списку перегляду Plex\",\n  \"components.Settings.SettingsJobsCache.process\": \"Процес\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Сканування Radarr\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"Виконати зараз\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Сканування Sonarr\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"Невідоме завдання\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"Повідомлення лога скопійовано в буфер обміну.\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"Скопіювати в буфер обміну\",\n  \"components.Settings.SettingsLogs.extraData\": \"Додаткова інформація\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"Налагоджувальні\",\n  \"components.Settings.SettingsLogs.filterError\": \"Помилки\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"Інформаційні\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"Попередження\",\n  \"components.Settings.SettingsLogs.label\": \"Мітка\",\n  \"components.Settings.SettingsLogs.level\": \"Важливість\",\n  \"components.Settings.SettingsLogs.logDetails\": \"Докладні відомості про лог\",\n  \"components.Settings.SettingsLogs.logs\": \"Логи\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"Ви також можете переглядати ці логи безпосередньо через <code>stdout</code> або в <code>{appDataPath}/logs/seerr.log</code>.\",\n  \"components.Settings.SettingsLogs.message\": \"Повідомлення\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"Зупинити\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"Відновити\",\n  \"components.Settings.SettingsLogs.showall\": \"Показати всі логі\",\n  \"components.Settings.SettingsLogs.time\": \"Час\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"Переглянути деталі\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"Дозволи за замовчуванням\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"Початкові дозволи, надані новим користувачам\",\n  \"components.Settings.SettingsUsers.localLogin\": \"Увімкнути локальний вхід\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"Дозволити користувачам входити в систему, використовуючи свою адресу електронної пошти та пароль замість Plex OAuth\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"Загальне обмеження кількості запитів фільмів\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"Увімкнути вхід через {mediaServerName} для нових користувачів\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"Дозволити користувачам {mediaServerName} входити до системи без попереднього імпорту\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"Щось пішло не так при збереженні налаштувань.\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"Налаштування користувачів успішно збережено!\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"Загальне обмеження кількості запитів серіалів\",\n  \"components.Settings.SettingsUsers.userSettings\": \"Налаштування користувачів\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"Налаштуйте глобальні параметри та параметри за промовчанням для користувачів.\",\n  \"components.Settings.SettingsUsers.users\": \"Користувачі\",\n  \"components.Settings.SonarrModal.add\": \"Додати сервер\",\n  \"components.Settings.SonarrModal.animeTags\": \"Теги для аніме\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"Мовний профіль для аніме\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"Профіль якості для аніме\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"Кореневий каталог для аніме\",\n  \"components.Settings.SonarrModal.apiKey\": \"Ключ API\",\n  \"components.Settings.SonarrModal.baseUrl\": \"Базовий URL\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"Додати новий 4К сервер Sonarr\",\n  \"components.Settings.SonarrModal.createsonarr\": \"Додати новий сервер Sonarr\",\n  \"components.Settings.SonarrModal.default4kserver\": \"4К сервер за промовчанням\",\n  \"components.Settings.SonarrModal.defaultserver\": \"Сервер за замовчуванням\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"Редагувати 4К сервер Sonarr\",\n  \"components.Settings.SonarrModal.editsonarr\": \"Редагувати сервер Sonarr\",\n  \"components.Settings.SonarrModal.enableSearch\": \"Увімкнути автоматичний пошук\",\n  \"components.Settings.SonarrModal.externalUrl\": \"Зовнішня URL-адреса\",\n  \"components.Settings.SonarrModal.hostname\": \"Ім'я хоста або IP-адреса\",\n  \"components.Settings.SonarrModal.languageprofile\": \"Мовний профіль\",\n  \"components.Settings.SonarrModal.loadingTags\": \"Завантаження тегів…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"Завантаження мовних профілів…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"Завантаження профілів якості…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"Завантаження кореневих каталогів…\",\n  \"components.Settings.SonarrModal.notagoptions\": \"Тегів немає.\",\n  \"components.Settings.SonarrModal.port\": \"Порт\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"Профіль якості\",\n  \"components.Settings.SonarrModal.rootfolder\": \"Кореневий каталог\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"Папки для сезонів\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"Виберіть мовний профіль\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"Виберіть профіль якості\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"Виберіть кореневий каталог\",\n  \"components.Settings.SonarrModal.selecttags\": \"Виберіть теги\",\n  \"components.Settings.SonarrModal.server4k\": \"4К сервер\",\n  \"components.Settings.SonarrModal.servername\": \"Назва сервера\",\n  \"components.Settings.SonarrModal.ssl\": \"Використовувати SSL\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"Увімкнути сканування\",\n  \"components.Settings.SonarrModal.tags\": \"Теги\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"Протестувати підключення для завантаження мовних профілів\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"Протестувати підключення для завантаження профілів якості\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"Протестувати з'єднання для завантаження кореневих каталогів\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"Протестувати підключення для завантаження тегів\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Не вдалося підключитися до Sonarr.\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"З'єднання з Sonarr встановлено успішно!\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"Ви повинні надати ключ API\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"Ви повинні вказати дійсну URL-адресу\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"URL-адреса не повинна закінчуватися косою рискою\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"Базова URL-адреса повинна мати косу риску на початку\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"Базова URL-адреса не повинна закінчуватися косою рискою\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"Ви повинні вказати дійсне ім'я хоста або IP-адресу\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"Ви повинні вибрати мовний профіль\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"Ви повинні вказати ім'я сервера\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"Ви повинні вказати дійсний номер порту\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"Ви повинні вибрати профіль якості\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"Ви повинні вибрати кореневий каталог\",\n  \"components.Settings.activeProfile\": \"Активний профіль\",\n  \"components.Settings.addradarr\": \"Додати сервер Radarr\",\n  \"components.Settings.address\": \"Адреса\",\n  \"components.Settings.addsonarr\": \"Додати сервер Sonarr\",\n  \"components.Settings.advancedTooltip\": \"Неправильне налаштування цього параметра може призвести до несправності функціональності\",\n  \"components.Settings.cancelscan\": \"Скасувати сканування\",\n  \"components.Settings.currentlibrary\": \"Поточна бібліотека: {name}\",\n  \"components.Settings.default\": \"За замовчуванням\",\n  \"components.Settings.default4k\": \"4К за замовчуванням\",\n  \"components.Settings.deleteServer\": \"Видалити сервер {serverType}\",\n  \"components.Settings.deleteserverconfirm\": \"Ви впевнені, що хочете видалити цей сервер?\",\n  \"components.Settings.email\": \"Електронна пошта\",\n  \"components.Settings.enablessl\": \"Використовувати SSL\",\n  \"components.Settings.experimentalTooltip\": \"Увімкнення цього параметра може призвести до неочікуваної поведінки програми\",\n  \"components.Settings.externalUrl\": \"Зовнішня URL-адреса\",\n  \"components.Settings.hostname\": \"Ім'я хоста або IP-адреса\",\n  \"components.Settings.is4k\": \"4К\",\n  \"components.Settings.librariesRemaining\": \"Залишилось бібліотек: {count}\",\n  \"components.Settings.manualscan\": \"Сканувати бібліотеки вручну\",\n  \"components.Settings.manualscanDescription\": \"Зазвичай виконується раз на 24 години. Seerr виконає більш агресивну перевірку вашого сервера Plex на предмет нещодавно доданих мультимедіа. Якщо ви вперше налаштовуєте Plex, рекомендується виконати одноразове повне сканування бібліотек вручну!\",\n  \"components.Settings.mediaTypeMovie\": \"фільм\",\n  \"components.Settings.mediaTypeSeries\": \"серіал\",\n  \"components.Settings.menuAbout\": \"Про проект\",\n  \"components.Settings.menuGeneralSettings\": \"Спільне\",\n  \"components.Settings.menuJobs\": \"Завдання та кеш\",\n  \"components.Settings.menuLogs\": \"Логи\",\n  \"components.Settings.menuNotifications\": \"Сповіщення\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuServices\": \"Служби\",\n  \"components.Settings.menuUsers\": \"Користувачі\",\n  \"components.Settings.noDefault4kServer\": \"4K сервер {serverType} повинен бути позначений як сервер за промовчанням, щоб користувачі могли надсилати запити на 4K {mediaType}и.\",\n  \"components.Settings.noDefaultNon4kServer\": \"Якщо ви використовуєте один сервер {serverType} для контенту, в тому числі і для 4К, або якщо ви завантажуєте лише контент 4K, ваш сервер {serverType} <strong>НЕ</strong> має бути позначений як 4К сервер.\",\n  \"components.Settings.noDefaultServer\": \"Принаймні один сервер {serverType} повинен бути позначений як сервер за промовчанням для обробки запитів на {mediaType}и.\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"Налаштуйте та активуйте служби сповіщень.\",\n  \"components.Settings.notifications\": \"Сповіщення\",\n  \"components.Settings.notificationsettings\": \"Налаштування повідомлень\",\n  \"components.Settings.notrunning\": \"Не працює\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.plexlibraries\": \"Бібліотеки Plex\",\n  \"components.Settings.plexlibrariesDescription\": \"Бібліотеки, які Seerr сканує на наявність мультимедіа. Налаштуйте та збережіть параметри підключення Plex, потім натисніть кнопку нижче, якщо список бібліотек порожній.\",\n  \"components.Settings.plexsettings\": \"Налаштування Plex\",\n  \"components.Settings.plexsettingsDescription\": \"Налаштуйте параметри вашого сервера Plex. Seerr сканує ваші бібліотеки Plex, щоб визначити доступність контенту.\",\n  \"components.Settings.port\": \"Порт\",\n  \"components.Settings.radarrsettings\": \"Налаштування Radarr\",\n  \"components.Settings.restartrequiredTooltip\": \"Seerr потрібно перезапустити, щоб зміни цього параметра набули чинності\",\n  \"components.Settings.scan\": \"Синхронізувати бібліотеки\",\n  \"components.Settings.scanning\": \"Синхронізація…\",\n  \"components.Settings.serverLocal\": \"локальний\",\n  \"components.Settings.serverRemote\": \"віддалений\",\n  \"components.Settings.serverSecure\": \"захищений\",\n  \"components.Settings.serverpreset\": \"Сервер\",\n  \"components.Settings.serverpresetLoad\": \"Натисніть кнопку, щоб завантажити список доступних серверів\",\n  \"components.Settings.serverpresetManualMessage\": \"Ручне налаштування\",\n  \"components.Settings.serverpresetRefreshing\": \"Отримання списку серверів…\",\n  \"components.Settings.serviceSettingsDescription\": \"Налаштуйте сервер(и) {serverType} нижче. Ви можете підключити кілька серверів {serverType}, але тільки два з них можуть бути позначені як сервери за промовчанням (один не 4К і один 4К). Адміністратори можуть перевизначити сервер для обробки нових запитів до їх схвалення.\",\n  \"components.Settings.services\": \"Служби\",\n  \"components.Settings.settingUpPlexDescription\": \"Щоб налаштувати Plex, ви можете або ввести дані вручну, або вибрати сервер, отриманий зі сторінки <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Натисніть кнопку праворуч від випадаючого списку, щоб отримати список доступних серверів .\",\n  \"components.Settings.sonarrsettings\": \"Налаштування Sonarr\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.startscan\": \"Почати сканування\",\n  \"components.Settings.tautulliApiKey\": \"Ключ API\",\n  \"components.Settings.tautulliSettings\": \"Tautulli Налаштування\",\n  \"components.Settings.tautulliSettingsDescription\": \"За бажанням налаштуйте параметри для вашого сервера Tautulli. Seerr отримує дані історії переглядів для медіафайлів Plex від Tautulli.\",\n  \"components.Settings.toastPlexConnecting\": \"Спроба підключення до Plex…\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Не вдалося підключитися до Plex.\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"З'єднання з Plex встановлено успішно!\",\n  \"components.Settings.toastPlexRefresh\": \"Отримання списку серверів Plex…\",\n  \"components.Settings.toastPlexRefreshFailure\": \"Не вдалося отримати список серверів Plex.\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"Список серверів Plex успішно отримано!\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"Під час збереження налаштувань Tautulli сталася помилка.\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Налаштування Tautulli успішно збережено!\",\n  \"components.Settings.urlBase\": \"URL Base\",\n  \"components.Settings.validationApiKey\": \"Ви повинні надати ключ API\",\n  \"components.Settings.validationHostnameRequired\": \"Ви повинні вказати дійсне ім'я хоста або IP-адресу\",\n  \"components.Settings.validationPortRequired\": \"Ви повинні вказати дійсний номер порту\",\n  \"components.Settings.validationUrl\": \"Ви повинні надати дійсну URL-адресу\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"Основа URL-адреси повинна мати косу риску на початку\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"База URL-адреси не має закінчуватися косою рискою\",\n  \"components.Settings.validationUrlTrailingSlash\": \"URL-адреса не має закінчуватися косою рискою\",\n  \"components.Settings.webAppUrl\": \"URL <WebAppLink>веб-програми</WebAppLink>\",\n  \"components.Settings.webAppUrlTip\": \"При необхідності надсилайте користувачів у веб-додаток на вашому сервері замість розміщеного на plex.tv\",\n  \"components.Settings.webhook\": \"Веб-перехоплювач\",\n  \"components.Settings.webpush\": \"Веб-push\",\n  \"components.Setup.configureservices\": \"Налаштуйте служби\",\n  \"components.Setup.continue\": \"Продовжити\",\n  \"components.Setup.finish\": \"Завершити налаштування\",\n  \"components.Setup.finishing\": \"Завершення…\",\n  \"components.Setup.setup\": \"Налаштування\",\n  \"components.Setup.signinMessage\": \"Почніть з входу в систему за допомогою облікового запису Plex\",\n  \"components.Setup.welcome\": \"Ласкаво просимо до Seerr\",\n  \"components.StatusBadge.managemedia\": \"Керувати {mediaType}\",\n  \"components.StatusBadge.openinarr\": \"Відкрити в{arr}\",\n  \"components.StatusBadge.playonplex\": \"Грати в {mediaServerName}\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.StatusBadge.status4k\": \"4K {status}\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} Оновлено\",\n  \"components.StatusChecker.appUpdatedDescription\": \"Натисніть кнопку нижче, щоб перезавантажити програму.\",\n  \"components.StatusChecker.reloadApp\": \"Перезавантажити {applicationTitle}\",\n  \"components.StatusChecker.restartRequired\": \"Потрібен перезапуск сервера\",\n  \"components.StatusChecker.restartRequiredDescription\": \"Перезапустіть сервер, щоб застосувати оновлені налаштування.\",\n  \"components.TitleCard.cleardata\": \"Очистити дані\",\n  \"components.TitleCard.mediaerror\": \"{mediaType} Не знайдено\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.TvDetails.Season.noepisodes\": \"Список епізодів недоступний.\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"Під час отримання даних про сезон сталася помилка.\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"Повний акторський склад серіалу\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"Повна знімальна група серіалу\",\n  \"components.TvDetails.anime\": \"Аніме\",\n  \"components.TvDetails.cast\": \"У ролях\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount, plural, one {# Епізод} other {# Епізоди}}\",\n  \"components.TvDetails.episodeRuntime\": \"Тривалість епізоду\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} хвилин\",\n  \"components.TvDetails.firstAirDate\": \"Дата першого ефіру\",\n  \"components.TvDetails.manageseries\": \"Керувати Серіалами\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Телеканал} other {Телеканали}}\",\n  \"components.TvDetails.nextAirDate\": \"Наступна дата виходу в ефір\",\n  \"components.TvDetails.originallanguage\": \"Мова оригіналу\",\n  \"components.TvDetails.originaltitle\": \"Назва оригіналу\",\n  \"components.TvDetails.overview\": \"Огляд\",\n  \"components.TvDetails.overviewunavailable\": \"Огляд недоступний.\",\n  \"components.TvDetails.productioncountries\": \"{countryCount, plural, one {Країна} other {Країни}} виробництва\",\n  \"components.TvDetails.recommendations\": \"Рекомендації\",\n  \"components.TvDetails.reportissue\": \"Повідомити про проблему\",\n  \"components.TvDetails.rtaudiencescore\": \"Оцінка аудиторії Rotten Tomatoes\",\n  \"components.TvDetails.rtcriticsscore\": \"Томатометр Rotten Tomatoes\",\n  \"components.TvDetails.seasonnumber\": \"Сезон {seasonNumber}\",\n  \"components.TvDetails.seasons\": \"{seasonCount, plural, one {# сезон} other {# сезонів}}\",\n  \"components.TvDetails.seasonstitle\": \"Сезони\",\n  \"components.TvDetails.showtype\": \"Тип серіалу\",\n  \"components.TvDetails.similar\": \"Схожі серіали\",\n  \"components.TvDetails.status4k\": \"4K {status}\",\n  \"components.TvDetails.streamingproviders\": \"Зараз транслюється\",\n  \"components.TvDetails.tmdbuserscore\": \"Оцінка користувача TMDB\",\n  \"components.TvDetails.viewfullcrew\": \"Подивитися повну знімальну групу\",\n  \"components.TvDetails.watchtrailer\": \"Дивитись трейлер\",\n  \"components.UserList.accounttype\": \"Тип\",\n  \"components.UserList.admin\": \"Адміністратор\",\n  \"components.UserList.autogeneratepassword\": \"Згенерувати пароль автоматично\",\n  \"components.UserList.autogeneratepasswordTip\": \"Надіслати користувачеві пароль, згенерований сервером, електронною поштою\",\n  \"components.UserList.bulkedit\": \"Масове редагування\",\n  \"components.UserList.create\": \"Створити\",\n  \"components.UserList.created\": \"Приєднався\",\n  \"components.UserList.createlocaluser\": \"Створити локального користувача\",\n  \"components.UserList.creating\": \"Створення…\",\n  \"components.UserList.deleteconfirm\": \"Ви впевнені, що хочете видалити цього користувача? Усі дані про його запити будуть видалені без можливості відновлення.\",\n  \"components.UserList.deleteuser\": \"Видалити користувача\",\n  \"components.UserList.edituser\": \"Змінити дозволи користувача\",\n  \"components.UserList.email\": \"Адреса електронної пошти\",\n  \"components.UserList.importedfromplex\": \"{userCount, plural, one {# новий користувач} other {# нових користувачів} успішно імпортовані з Plex!\",\n  \"components.UserList.importfrommediaserver\": \"Імпортувати користувачів з {mediaServerName}\",\n  \"components.UserList.importfromplex\": \"Імпортувати користувачів з Plex\",\n  \"components.UserList.importfromplexerror\": \"Щось пішло не так при імпорті користувачів з Plex.\",\n  \"components.UserList.localLoginDisabled\": \"Параметр <strong>Увімкнути локальний вхід</strong> в даний час вимкнено.\",\n  \"components.UserList.localuser\": \"Локальний користувач\",\n  \"components.UserList.newplexsigninenabled\": \"Параметр <strong>Увімкнути новий вхід Plex</strong> наразі ввімкнено. Користувачам Plex із доступом до бібліотеки не потрібно імпортувати, щоб увійти.\",\n  \"components.UserList.nouserstoimport\": \"Немає нових користувачів для імпорту з Plex.\",\n  \"components.UserList.owner\": \"Власник\",\n  \"components.UserList.password\": \"Пароль\",\n  \"components.UserList.passwordinfodescription\": \"Налаштуйте URL-адресу програми та увімкніть повідомлення електронною поштою, щоб забезпечити можливість автоматичної генерації пароля.\",\n  \"components.UserList.plexuser\": \"Користувач Plex\",\n  \"components.UserList.role\": \"Роль\",\n  \"components.UserList.sortCreated\": \"Дата приєднання\",\n  \"components.UserList.sortDisplayName\": \"Відображуване ім'я\",\n  \"components.UserList.sortRequests\": \"Кількість запитів\",\n  \"components.UserList.totalrequests\": \"Запитів\",\n  \"components.UserList.user\": \"Користувач\",\n  \"components.UserList.usercreatedfailed\": \"Щось пішло не так при створенні користувача.\",\n  \"components.UserList.usercreatedfailedexisting\": \"Вказана адреса електронної пошти вже використовується іншим користувачем.\",\n  \"components.UserList.usercreatedsuccess\": \"Користувача успішно створено!\",\n  \"components.UserList.userdeleted\": \"Користувача успішно видалено!\",\n  \"components.UserList.userdeleteerror\": \"Щось пішло не так при видаленні користувача.\",\n  \"components.UserList.userfail\": \"Щось пішло не так при збереженні дозволів користувача.\",\n  \"components.UserList.userlist\": \"Список користувачів\",\n  \"components.UserList.users\": \"Користувачі\",\n  \"components.UserList.userssaved\": \"Дозволи користувача успішно збережені!\",\n  \"components.UserList.validationEmail\": \"Потрібно вказати Email\",\n  \"components.UserList.validationpasswordminchars\": \"Пароль занадто короткий: він повинен містити не менше 8 символів\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"Приєднався {joindate}\",\n  \"components.UserProfile.ProfileHeader.profile\": \"Подивитися профіль\",\n  \"components.UserProfile.ProfileHeader.settings\": \"Редагувати налаштування\",\n  \"components.UserProfile.ProfileHeader.userid\": \"ID користувача: {userid}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"Тип облікового запису\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"Адміністратор\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"Мова інтерфейсу\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"ID користувача Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"<FindDiscordIdLink>багатозначний ідентифікаційний номер</FindDiscordIdLink>, пов’язаний із вашим обліковим записом користувача Discord\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"Відображуване ім'я\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"Перевизначити глобальні обмеження\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"Загальне\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"Загальні налаштування\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"За замовчуванням ({language})\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"Локальний користувач\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"Обмеження кількості запитів на фільми\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"Мови для пошуку фільмів та серіалів\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"Контент фільтрується за мовою оригіналу\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"Власник\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Користувач Plex\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"Автоматичний запит фільмів\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"Автоматично запитувати фільми з вашого <PlexWatchlistSupportLink>списку перегляду Plex</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"Автоматичний запит Серіалів\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"Автоматично запитувати серіали з вашого <PlexWatchlistSupportLink>списку перегляду Plex</PlexWatchlistSupportLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"Регіон для пошуку фільмів та серіалів\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"Контент фільтрується за доступністю у вибраному регіоні\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"Роль\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"Обмеження кількості запитів на серіали\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"Щось пішло не так при збереженні налаштувань.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"Налаштування успішно збережено!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"Користувач\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"Ви повинні надати дійсний ідентифікатор користувача Discord\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"ID користувача\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"<FindDiscordIdLink>ID</FindDiscordIdLink> вашого облікового запису\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Не вдалося зберегти налаштування повідомлень Discord.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Налаштування повідомлень Discord успішно збережено!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"Електронна пошта\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"Не вдалося зберегти налаштування повідомлень електронною поштою.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"Налаштування повідомлень електронною поштою успішно збережено!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"Сповіщення\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"Налаштування повідомлень\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"Відкритий ключ PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"Шифрувати повідомлення електронної пошти за допомогою <OpenPgpLink>OpenPGP</OpenPgpLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"Токен доступу\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"Створіть токен на сторінці <PushbulletSettingsLink>налаштувань вашого облікового запису</PushbulletSettingsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Не вдалося зберегти налаштування сповіщень Pushbullet.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Налаштування сповіщень Pushbullet успішно збережено!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"Токен API програми\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"<ApplicationRegistrationLink>Зареєструйте програму</ApplicationRegistrationLink> для використання з {applicationTitle}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"Ключ користувача або групи\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"Ваш 30-значний <UsersGroupsLink>ідентифікатор користувача або групи</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Не вдалося зберегти налаштування сповіщень Pushover.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Налаштування сповіщень Pushover успішно збережено!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"Надсилати без звуку\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"Надсилати повідомлення без звуку\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"ID чату\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"<TelegramBotLink>Почніть чат</TelegramBotLink>, додайте <GetIdBotLink>@get_id_bot</GetIdBotLink> і виконайте команду <code>/my_id</code>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Не вдалося зберегти налаштування сповіщень Telegram.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Налаштування сповіщень Telegram успішно збережено!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"Ви повинні надати дійсний ID користувача\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"Ви повинні надати дійсний відкритий ключ PGP\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"Ви повинні надати токен доступу\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"Ви повинні надати дійсний токен програми\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"Ви повинні надати дійсний ключ користувача або групи\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"Ви повинні надати дійсний ID чату\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"Веб-push\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"Підтвердіть пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"Поточний пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"Новий пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"В даний час для цього облікового запису не встановлено пароль. Встановіть пароль нижче, щоб з цим обліковим записом можна було увійти в систему як \\\"локальний користувач\\\".\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"В даний час для вашого облікового запису не встановлено пароль. Встановіть пароль нижче, щоб мати можливість увійти в систему як \\\"локальний користувач\\\", використовуючи свою адресу електронної пошти.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"У вас немає дозволу на зміну пароля цього користувача.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"Пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"Щось пішло не так при збереженні пароля.\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"Щось пішло не так при збереженні пароля. Чи правильно введено ваш поточний пароль?\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"Пароль успішно збережений!\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"Ви повинні підтвердити новий пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"Паролі повинні збігатися\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"Ви повинні вказати свій поточний пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"Ви повинні ввести новий пароль\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"Пароль занадто короткий: він повинен містити не менше 8 символів\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"Дозволи\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"Щось пішло не так при збереженні налаштувань.\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"Дозволи успішно збережені!\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"Ви не можете змінювати власні дозволи.\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"Пароль\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"Спільне\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"Сповіщення\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"Дозволи\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"У вас немає дозволу на зміну налаштувань цього користувача.\",\n  \"components.UserProfile.emptywatchlist\": \"Тут з’являться медіафайли, додані до вашого <PlexWatchlistSupportLink>списку перегляду Plex</PlexWatchlistSupportLink>.\",\n  \"components.UserProfile.limit\": \"{remaining} з {limit}\",\n  \"components.UserProfile.movierequests\": \"Запитів фільмів\",\n  \"components.UserProfile.pastdays\": \"{type} (на {days} дні(в)\",\n  \"components.UserProfile.plexwatchlist\": \"Список перегляду Plex\",\n  \"components.UserProfile.recentlywatched\": \"Нещодавно переглянуто\",\n  \"components.UserProfile.recentrequests\": \"Останні запити\",\n  \"components.UserProfile.requestsperdays\": \"залишилось {limit}\",\n  \"components.UserProfile.seriesrequest\": \"Запитів сезонів\",\n  \"components.UserProfile.totalrequests\": \"Усього запитів\",\n  \"components.UserProfile.unlimited\": \"Необмежено\",\n  \"i18n.advanced\": \"Для просунутих користувачів\",\n  \"i18n.all\": \"Всі\",\n  \"i18n.approve\": \"Схвалити\",\n  \"i18n.approved\": \"Схвалений\",\n  \"i18n.areyousure\": \"Ви впевнені?\",\n  \"i18n.available\": \"Доступний\",\n  \"i18n.back\": \"Назад\",\n  \"i18n.cancel\": \"Скасувати\",\n  \"i18n.canceling\": \"Скасувати…\",\n  \"i18n.close\": \"Закрити\",\n  \"i18n.decline\": \"Відхилити\",\n  \"i18n.declined\": \"Відхилений\",\n  \"i18n.delete\": \"Видалити\",\n  \"i18n.deleting\": \"Видалення…\",\n  \"i18n.delimitedlist\": \"{a}, {b}\",\n  \"i18n.edit\": \"Редагувати\",\n  \"i18n.experimental\": \"Експериментальний параметр\",\n  \"i18n.failed\": \"Помилка\",\n  \"i18n.import\": \"Імпорт\",\n  \"i18n.importing\": \"Імпортування...\",\n  \"i18n.loading\": \"Завантаження…\",\n  \"i18n.movie\": \"Фільм\",\n  \"i18n.movies\": \"Фільми\",\n  \"i18n.next\": \"Наступна\",\n  \"i18n.noresults\": \"Результатів немає.\",\n  \"i18n.notrequested\": \"Не запрошений\",\n  \"i18n.open\": \"Відкрити\",\n  \"i18n.partiallyavailable\": \"Доступний частково\",\n  \"i18n.pending\": \"Чекаючи\",\n  \"i18n.previous\": \"Попередня\",\n  \"i18n.processing\": \"В обробці\",\n  \"i18n.request\": \"Запит\",\n  \"i18n.request4k\": \"Запит у 4K\",\n  \"i18n.requested\": \"Запрошений\",\n  \"i18n.requesting\": \"Запит…\",\n  \"i18n.resolved\": \"Вирішені\",\n  \"i18n.restartRequired\": \"Потрібне перезавантаження\",\n  \"i18n.resultsperpage\": \"Відобразити {pageSize} результатів на сторінці\",\n  \"i18n.retry\": \"Повторити\",\n  \"i18n.retrying\": \"Повтор…\",\n  \"i18n.save\": \"Зберегти зміни\",\n  \"i18n.saving\": \"Збереження…\",\n  \"i18n.settings\": \"Налаштування\",\n  \"i18n.showingresults\": \"Показуються результати з <strong>{from}</strong> по <strong>{to}</strong> з <strong>{total}</strong>\",\n  \"i18n.status\": \"Статус\",\n  \"i18n.test\": \"Протестувати\",\n  \"i18n.testing\": \"Тестування…\",\n  \"i18n.tvshow\": \"Серіал\",\n  \"i18n.tvshows\": \"Серіали\",\n  \"i18n.unavailable\": \"Недоступний\",\n  \"i18n.usersettings\": \"Налаштування користувача\",\n  \"i18n.view\": \"Подивитися\",\n  \"pages.errormessagewithcode\": \"{statusCode} - {error}\",\n  \"pages.internalservererror\": \"Внутрішня помилка сервера\",\n  \"pages.oops\": \"Упс\",\n  \"pages.pagenotfound\": \"Сторінку не знайдено\",\n  \"pages.returnHome\": \"Повернутись додому\",\n  \"pages.serviceunavailable\": \"Сервіс недоступний\",\n  \"pages.somethingwentwrong\": \"Щось пішло не так\",\n  \"components.Discover.CreateSlider.nooptions\": \"Немає результатів.\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Ключові слова пошуку…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Пошук студій…\",\n  \"components.Discover.CreateSlider.starttyping\": \"Починайте писати для пошуку.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Ви повинні вказати назву.\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# Активний фільтр} other {# Активні фільтри}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Фільми\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"Змінити видимість\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"Видалити\",\n  \"components.Discover.DiscoverTv.discovertv\": \"Серіали\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# Активний фільтр} other {# Активні фільтри}}\",\n  \"components.Discover.FilterSlideover.filters\": \"Фільтри\",\n  \"components.Discover.FilterSlideover.from\": \"Від\",\n  \"components.Discover.FilterSlideover.genres\": \"Жанри\",\n  \"components.Discover.FilterSlideover.keywords\": \"Ключові слова\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"Оригінальна мова\",\n  \"components.Discover.FilterSlideover.ratingText\": \"Оцінки від {minValue} до {maxValue}\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"Дата релізу\",\n  \"components.Discover.FilterSlideover.runtime\": \"Тривалість\",\n  \"components.Discover.FilterSlideover.studio\": \"Студія\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"Оцінка користувачів TMDB\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"Кількість голосів від користувачів TMDB\",\n  \"components.Discover.FilterSlideover.to\": \"До\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"Медіа додано до вашого <PlexWatchlistSupportLink>списку перегляду Plex</PlexWatchlistSupportLink>.\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"Ваш список перегляду Plex\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"Нещодавно додані\",\n  \"components.Discover.studios\": \"Студії\",\n  \"components.Discover.tmdbmoviegenre\": \"Жанр фільму TMDB\",\n  \"components.Discover.tmdbmoviekeyword\": \"Ключове слово фільму TMDB\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"Сервіси потокової передачі фільмів TMDB\",\n  \"components.Discover.tmdbnetwork\": \"Телеканал TMDB\",\n  \"components.Discover.tmdbstudio\": \"Студія TMDB\",\n  \"components.Discover.tmdbtvgenre\": \"Жанр серіалу TMDB\",\n  \"components.Discover.tmdbtvkeyword\": \"Ключове слово серіалу TMDB\",\n  \"components.Discover.tvgenres\": \"Жанри серіалів\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"Потрібно вказати пароль.\",\n  \"components.Login.initialsignin\": \"Підключитися\",\n  \"components.Login.initialsigningin\": \"Підключення…\",\n  \"components.Login.save\": \"Додати\",\n  \"components.Login.signinwithjellyfin\": \"Використовуйте свій {mediaServerName} обліковий запис\",\n  \"components.Login.title\": \"Додати email\",\n  \"components.Login.username\": \"Ім'я користувача\",\n  \"components.ManageSlideOver.removearr4k\": \"Видалити з 4K {arr}\",\n  \"components.MovieDetails.downloadstatus\": \"Статус завантаження\",\n  \"components.MovieDetails.imdbuserscore\": \"Оцінка користувачів IMDB\",\n  \"components.MovieDetails.openradarr4k\": \"Відкрити фільм у 4К Radarr\",\n  \"components.Selector.searchKeywords\": \"Ключові слова пошуку…\",\n  \"components.Selector.searchStudios\": \"Пошук студій…\",\n  \"components.Selector.starttyping\": \"Початок введення для пошуку.\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"Звук сповіщення\",\n  \"components.Settings.SettingsMain.general\": \"Загальні\",\n  \"components.Settings.SettingsMain.generalsettings\": \"Загальні налаштування\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"Назва програми\",\n  \"components.Settings.SettingsMain.applicationurl\": \"URL програми\",\n  \"components.Settings.SettingsMain.cacheImages\": \"Увімкнути кешування зображень\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"Приховати доступні медіа\",\n  \"components.Settings.SettingsMain.locale\": \"Мова програми\",\n  \"components.Settings.SettingsMain.originallanguage\": \"Мови для пошуку фільмів та серіалів\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"Дозволити запитувати серіали частково\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"Новий ключ API успішно згенеровано!\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"Під час збереження налаштувань сталася помилка.\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"Налаштування успішно збережено!\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"Ви повинні надати дійсну URL-адресу\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"URL-адреса не має закінчуватися косою рискою\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"Тип аніме\",\n  \"components.Settings.jellyfinSettings\": \"Налаштування {mediaServerName}\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"Налаштування {mediaServerName} успішно збережено!\",\n  \"components.Settings.jellyfinlibraries\": \"Бібліотеки {mediaServerName}\",\n  \"components.Settings.jellyfinsettings\": \"Налаштування {mediaServerName}\",\n  \"components.Setup.signinWithPlex\": \"Використовуйте свій обліковий запис Plex\",\n  \"components.TvDetails.play\": \"Відтворити в {mediaServerName}\",\n  \"components.UserList.mediaServerUser\": \"Користувач {mediaServerName}\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"Електронна пошта\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"Збереження…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"Звук сповіщення\",\n  \"i18n.collection\": \"Колекція\",\n  \"components.Discover.CreateSlider.needresults\": \"Ви повинні мати принаймні 1 результат.\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Пошук жанрів…\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"Фільми {keywordTitle}\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# Активний фільтр} other {# Активні фільтри}}\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} Серіали\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"Очистити всі активні фільтри\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"тривалість {minValue}-{maxValue} хвилин\",\n  \"components.Discover.FilterSlideover.voteCount\": \"Кількість голосів від {minValue} до {maxValue}\",\n  \"components.Discover.networks\": \"Телеканали\",\n  \"components.Discover.resettodefault\": \"Скинути за замовчуванням\",\n  \"components.Discover.tmdbsearch\": \"Пошук TMDB\",\n  \"components.Discover.tmdbtvstreamingservices\": \"Сервіси потокового передавання серіалів TMDB\",\n  \"components.Layout.Sidebar.browsemovies\": \"Фільми\",\n  \"components.Layout.Sidebar.browsetv\": \"Серіали\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Адреса електронної пошти недійсна.\",\n  \"components.Login.saving\": \"Додавання…\",\n  \"components.Login.validationhostformat\": \"Потрібна дійсна URL-адреса\",\n  \"components.Login.validationusernamerequired\": \"Потрібно ім'я користувача\",\n  \"components.ManageSlideOver.removearr\": \"Видалити з {arr}\",\n  \"components.MovieDetails.openradarr\": \"Відкрити фільм у Radarr\",\n  \"components.Selector.nooptions\": \"Немає результатів.\",\n  \"components.Selector.searchGenres\": \"Виберіть жанри…\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"Пристрій за замовчуванням\",\n  \"components.Settings.Notifications.userEmailRequired\": \"Потрібен email користувача\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"Автоматично додавати додатковий тег з ID та іменем користувача, який запитує\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"Синхронізація доступності медіа\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"Кожну {jobScheduleSeconds, plural, one {секунду} other {{jobScheduleSeconds} секунд}}\",\n  \"components.Settings.SettingsMain.apikey\": \"Ключ API\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"Під час створення нового ключа API сталася помилка.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"Пристрій за замовчуванням\",\n  \"components.UserList.noJellyfinuserstoimport\": \"Немає користувачів {mediaServerName} для імпорту.\",\n  \"components.UserList.importfromJellyfinerror\": \"Під час імпорту користувачів з {mediaServerName} сталася помилка.\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"Кешувати зображення із зовнішніх джерел (потрібний значний об'єм дискового простору)\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"Ви повинні вказати назву програми\",\n  \"components.Settings.SonarrModal.seriesType\": \"Тип серіалу\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"Користувач {mediaServerName}\",\n  \"components.TitleCard.watchlistError\": \"Щось пішло не так, повторіть спробу.\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Налаштуйте глобальні параметри та параметри за замовчуванням для Seerr.\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"Фільтрувати вміст за мовою оригіналу\",\n  \"components.Settings.jellyfinSettingsFailure\": \"Під час збереження налаштувань {mediaServerName} сталася помилка.\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"Зберегти зміни\",\n  \"components.TvDetails.play4k\": \"Відтворити 4K в {mediaServerName}\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Введіть пошуковий запит\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"Сервіси потокового передавання\",\n  \"components.Discover.moviegenres\": \"Жанри фільмів\",\n  \"components.MovieDetails.play\": \"Відтворити в {mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"Відтворити в {mediaServerName} у 4К\",\n  \"components.Selector.showless\": \"Згорнути\",\n  \"components.Discover.CreateSlider.addSlider\": \"Додати повзунок\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Створити власний повзунок\",\n  \"components.Discover.CreateSlider.addfail\": \"Не вдалося створити новий повзунок.\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"Не вдалося видалити повзунок.\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"Повзунок успішно видалено.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Створено новий повзунок і збережено параметри налаштування Discover.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Редагувати повзунок\",\n  \"components.Discover.CreateSlider.editfail\": \"Не вдалося відредагувати повзунок.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Відредаговано повзунок і збережено параметри налаштування Discover.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Введіть TMDB ID жанру\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Введіть TMDB ID ключового слова\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Введіть TMDB ID мережі\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Введіть TMDB ID студії\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Назва повзунка\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Ви повинні надати доступний для пошуку вміст.\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Популярність за зростанням\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Популярність за спаданням\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"Дата випуску за зростанням\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"Дата випуску за спаданням\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"Назва (А-Я) за зростанням\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"Назва (Я-А) за спаданням\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"Рейтинг TMDB за зростанням\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"Рейтинг TMDB за спаданням\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"Дата виходу в ефір за зростанням\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"Дата виходу в ефір за спаданням\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"Популярність за зростанням\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"Популярність за спаданням\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"Назва (А-Я) за зростанням\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"Назва (Я-А) за спаданням\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"Рейтинг TMDB за зростанням\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"Рейтинг TMDB за спаданням\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"Дата виходу в ефір\",\n  \"components.Discover.createnewslider\": \"Створити новий повзунок\",\n  \"components.Discover.customizediscover\": \"Налаштувати Discover\",\n  \"components.Discover.resetfailed\": \"Щось пішло не так під час скидання налаштувань Discover.\",\n  \"components.Discover.resetsuccess\": \"Успішно скинуто параметри налаштування.\",\n  \"components.Discover.resetwarning\": \"Скинути всі повзунки до стандартних. Це також видалить будь-які спеціальні повзунки!\",\n  \"components.Discover.stopediting\": \"Зупинити редагування\",\n  \"components.Discover.updatefailed\": \"Під час оновлення налаштувань Discover сталася помилка.\",\n  \"components.Discover.updatesuccess\": \"Оновлено параметри налаштування Discover.\",\n  \"components.Login.credentialerror\": \"Ім'я користувача або пароль неправильні.\",\n  \"components.Login.description\": \"Оскільки ви вперше входите в {applicationName}, вам потрібно додати дійсну адресу електронної пошти.\",\n  \"components.Login.validationEmailFormat\": \"Невірний email\",\n  \"components.Login.validationEmailRequired\": \"Ви повинні вказати адресу електронної пошти\",\n  \"components.Login.validationemailformat\": \"Потрібен дійсний email\",\n  \"components.Layout.UserWarnings.emailRequired\": \"Потрібно вказати адресу електронної пошти.\",\n  \"components.Login.emailtooltip\": \"Адресу не потрібно пов’язувати з вашим {mediaServerName} сервером.\",\n  \"components.Login.validationhostrequired\": \"Необхідна URL-адреса {mediaServerName}\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* Це безповоротно видалить цей {mediaType} з {arr}, включаючи всі файли.\",\n  \"components.Selector.showmore\": \"Показати більше\",\n  \"components.Settings.RadarrModal.tagRequests\": \"Теги запитів\",\n  \"components.Settings.SonarrModal.tagRequests\": \"Теги запитів\",\n  \"components.Setup.configuremediaserver\": \"Налаштуйте медіасервер\",\n  \"components.Settings.jellyfinsettingsDescription\": \"Налаштуйте свій {mediaServerName} сервер. {mediaServerName} відсканує бібліотеки, щоб побачити, які бібліотеки доступні.\",\n  \"components.Settings.manualscanJellyfin\": \"Сканувати бібліотеки вручну\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"Бібліотеки {mediaServerName} перевіряються на наявність заголовків. Натисніть нижче, якщо в списку не вистачає бібліотек.\",\n  \"components.Settings.saving\": \"Збереження…\",\n  \"components.Settings.syncJellyfin\": \"Синхронізувати бібліотеки\",\n  \"components.Settings.syncing\": \"Синхронізація\",\n  \"components.Setup.signin\": \"Увійти\",\n  \"components.Setup.signinWithJellyfin\": \"Введіть дані Jellyfin\",\n  \"components.TitleCard.addToWatchList\": \"Додати в список перегляду\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong> успішно додано до списку перегляду!\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} успішно імпортовано!\",\n  \"components.UserList.importfromJellyfin\": \"Додати користувачів з {mediaServerName}\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"Зазвичай це запускається лише раз на 24 години. Seerr перевірятиме нещодавно доданий сервер {mediaServerName} більш агресивно. Якщо ви вперше налаштовуєте Seerr, рекомендується одноразове повне сканування бібліотеки вручну!\",\n  \"components.Settings.save\": \"Зберегти зміни\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong> Успішно видалено зі списку перегляду!\",\n  \"components.UserList.newJellyfinsigninenabled\": \"Параметр <strong>Увімкнути новий вхід на {mediaServerName}</strong> наразі ввімкнено. Користувачам {mediaServerName} із доступом до бібліотеки не потрібно імпортувати, щоб увійти.\",\n  \"components.UserProfile.localWatchlist\": \"Список перегляду {username}\",\n  \"components.Settings.jellyfinSettingsDescription\": \"Додатково налаштуйте внутрішні та зовнішні кінцеві точки для вашого сервера {mediaServerName}. У більшості випадків зовнішня URL-адреса відрізняється від внутрішньої URL-адреси. Для входу в систему {mediaServerName} також можна встановити спеціальну URL-адресу скидання пароля, якщо ви хочете переспрямувати на іншу сторінку скидання пароля. Ви також можете змінити ключ Jellyfin API, який був автоматично згенерований раніше.\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"Автоматично додавати додатковий тег з ID та іменем користувача, який запитує\",\n  \"components.Login.servertype\": \"Тип сервера\",\n  \"components.Login.validationPortRequired\": \"Ви повинні вказати дійсний номер порту\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL-адреса не має закінчуватися косою рискою\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong> додано до списку перегляду!\",\n  \"components.MovieDetails.addtowatchlist\": \"Додати до списку перегляду\",\n  \"components.Selector.pilot\": \"Пілот\",\n  \"components.RequestList.RequestItem.profileName\": \"Профіль\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"Спеціальна автентифікація з автоматичним групуванням бібліотек не підтримується\",\n  \"components.Settings.timeout\": \"Час очікування\",\n  \"components.Selector.canceled\": \"Скасовано\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"Забули пароль URL\",\n  \"components.TitleCard.watchlistCancel\": \"список перегляду для <strong>{title}</strong> скасовано.\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong> Видалено зі списку перегляду успішно!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"Потрібен дійсний email\",\n  \"components.Login.adminerror\": \"Для входу необхідно використовувати обліковий запис адміністратора.\",\n  \"components.Login.enablessl\": \"Використовувати SSL\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.invalidurlerror\": \"Неможливо підключитися до {mediaServerName} сервера.\",\n  \"components.Login.port\": \"Порт\",\n  \"components.Login.back\": \"Назад\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"Базова URL-адреса повинна мати косу риску на початку\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"Базова URL-адреса не має закінчуватися косою рискою\",\n  \"components.Login.validationservertyperequired\": \"Виберіть тип сервера\",\n  \"components.Login.urlBase\": \"Базова URL-адреса\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong> Видалено зі списку перегляду успішно!\",\n  \"components.MovieDetails.watchlistError\": \"Щось пішло не так, повторіть спробу.\",\n  \"components.Selector.ended\": \"Завершено\",\n  \"components.Selector.inProduction\": \"У виробництві\",\n  \"components.Selector.planned\": \"Планується\",\n  \"components.Selector.returningSeries\": \"Повернення серіалу\",\n  \"components.Selector.searchStatus\": \"Виберіть статус...\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"Під час синхронізації бібліотек сталася помилка\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"Бібліотеки не знайдено\",\n  \"components.Setup.configemby\": \"Налаштувати Emby\",\n  \"components.Setup.configjellyfin\": \"Налаштувати Jellyfin\",\n  \"components.Setup.configplex\": \"Налаштувати Plex\",\n  \"components.Setup.servertype\": \"Виберіть тип сервера\",\n  \"components.Setup.signinWithEmby\": \"Введіть свої дані Emby\",\n  \"components.Setup.subtitle\": \"Почніть із вибору медіа-сервера\",\n  \"components.StatusBadge.seasonnumber\": \"С{seasonNumber}\",\n  \"components.Setup.back\": \"Назад\",\n  \"components.TvDetails.addtowatchlist\": \"Додати до списку перегляду\",\n  \"components.TvDetails.removefromwatchlist\": \"Видалити зі списку перегляду\",\n  \"components.TvDetails.watchlistError\": \"Щось пішло не так, повторіть спробу.\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong> додано до списку перегляду!\",\n  \"components.UserList.username\": \"Ім'я користувача\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"Потрібно вказати Email\",\n  \"components.Settings.invalidurlerror\": \"Неможливо підключитися до {mediaServerName} сервера.\",\n  \"components.UserList.validationUsername\": \"Ви повинні вказати ім'я користувача\",\n  \"components.Discover.FilterSlideover.status\": \"Статус\",\n  \"components.MovieDetails.removefromwatchlist\": \"Видалити зі списку перегляду\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"Регіон для пошуку фільмів та серіалів\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"Вміст фільтрується за доступністю у вибраному регіоні\",\n  \"components.Settings.apiKey\": \"Ключ API\",\n  \"components.RequestList.RequestItem.removearr\": \"Видалити з {arr}\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"Регіон для пошуку фільмів та серіалів\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"Фільтрувати вміст за регіональною доступністю\",\n  \"components.Settings.scanbackground\": \"Сканування працюватиме у фоновому режимі. Тим часом ви можете продовжити процес налаштування.\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"Аватар користувача\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"Ви повинні надати дійсний ідентифікатор ролі Discord\",\n  \"components.Settings.OverrideRuleModal.service\": \"Сервіс\",\n  \"components.Settings.SettingsNetwork.docs\": \"документація\",\n  \"components.Settings.SettingsNetwork.network\": \"Мережа\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"Налаштування мережі\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"Під час збереження налаштувань сталася помилка.\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"Налаштування успішно збережено!\",\n  \"components.Settings.general\": \"Загальне\",\n  \"components.MetadataSelector.tmdbLabel\": \"The Movie Database (TMDB)\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"Ім'я користувача\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"Умови\",\n  \"components.Settings.OverrideRuleTile.settings\": \"Налаштування\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"Активна адреса\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"Кеш DNS\",\n  \"components.Settings.connectionTestFailed\": \"Тест з'єднання не пройдено\",\n  \"components.Settings.failed\": \"Не працює\",\n  \"components.Settings.menuNetwork\": \"Мережа\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"Створено\",\n  \"i18n.completed\": \"Завершено\",\n  \"i18n.deleted\": \"Видалено\",\n  \"i18n.specials\": \"Спецвипуски\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"Профіль якості\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"Кореневий каталог\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"Встановити зовнішній доступ API тільки для читання (потрібен HTTPS)\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) проксі\",\n  \"components.Discover.FilterSlideover.certification\": \"Вікове обмеження\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"Виключити ключові слова\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"Майбутні серіали\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"Опис проблеми\",\n  \"components.Login.loginwithapp\": \"Увійти через {appName}\",\n  \"components.Login.noadminerror\": \"Адміністратор на сервері не знайдений.\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"Виберіть провайдера метаданих\",\n  \"components.MetadataSelector.tvdbLabel\": \"TheTVDB\",\n  \"components.RequestList.sortDirection\": \"Змінити напрямок сортування\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"Не вдалося завантажити вікові обмеження\",\n  \"components.Selector.CertificationSelector.maxRating\": \"Максимальний рейтинг\",\n  \"components.Selector.CertificationSelector.minRating\": \"Мінімальний рейтинг\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"Ви повинні вказати номер пріоритету\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"Увімкнути агента\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"Вбудувати постер\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"Не вдалося зберегти налаштування сповіщень Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"Налаштування сповіщень Ntfy успішно збережено!\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"Пароль\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"Не вдалося надіслати тестове сповіщення Ntfy.\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"Надсилання тестового сповіщення Ntfy…\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"Тестове сповіщення Ntfy надіслано!\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"Автентифікація за ім'ям та паролем\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"Ви повинні вказати тему\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"Ви повинні вказати дійсну URL-адресу\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"Ви повинні вибрати хоча б один тип сповіщення\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"Вбудувати постер\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"Вбудувати постер\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"Вбудувати постер\",\n  \"components.Settings.Notifications.embedPoster\": \"Вбудувати постер\",\n  \"components.Settings.Notifications.messageThreadId\": \"ID теми/гілки\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"Якщо у вашому груповому чаті ввімкнено теми, ви можете вказати ID теми/гілки тут\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"ID теми/гілки повинен бути цілим додатним числом\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"Вказує умови перед застосуванням змін параметрів. Кожне поле повинно бути перевірено для застосування правил (операція AND). Поле вважається перевіреним, якщо будь-яка з його властивостей відповідає (операція OR).\",\n  \"components.Settings.OverrideRuleModal.create\": \"Створити правило\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"Нове правило перевизначення\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"Редагувати правило перевизначення\",\n  \"components.Settings.OverrideRuleModal.genres\": \"Жанри\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"Ключові слова\",\n  \"components.Settings.OverrideRuleModal.languages\": \"Мови\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"Виберіть профіль якості\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"Виберіть кореневий каталог\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"Виберіть сервіс\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"Виберіть теги\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"Застосувати це правило до вибраного сервісу.\",\n  \"components.Settings.OverrideRuleModal.settings\": \"Налаштування\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"Вказує, які налаштування будуть змінені при виконанні вищезазначених умов.\",\n  \"components.Settings.OverrideRuleModal.tags\": \"Теги\",\n  \"components.Settings.OverrideRuleModal.users\": \"Користувачі\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"Умови\",\n  \"components.Settings.OverrideRuleTile.tags\": \"Теги\",\n  \"components.Settings.OverrideRuleTile.users\": \"Користувачі\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"Jellyseerr кешує DNS-запити для оптимізації продуктивності та уникнення непотрібних API-викликів.\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"Глобальна статистика кешу DNS\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"Ця статистика агрегована по всіх записах кешу DNS.\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"Вік\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"Кеш DNS {hostname} очищено.\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"Вдалих звернень\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"Невдалих звернень\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"Ім'я хоста\",\n  \"components.Settings.SettingsJobsCache.failures\": \"Помилки\",\n  \"components.Settings.SettingsJobsCache.hits\": \"Вдалих\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"Запасні IPv4\",\n  \"components.Settings.SettingsJobsCache.misses\": \"Невдалих\",\n  \"components.Settings.SettingsJobsCache.size\": \"Розмір\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"Ключ API скопійовано в буфер обміну.\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"Приховати доступні медіа зі сторінок \\\"Discover\\\", але не з результатів пошуку\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"Регіон для стримінгу\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"Показувати стримінгові сайти за регіональною доступністю\",\n  \"components.Settings.SettingsMain.validationUrl\": \"Ви повинні вказати дійсну URL-адресу\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"URL-адреса не має закінчуватися косою рискою\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"Максимальний TTL кешу DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"Мінімальний TTL кешу DNS\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"НЕ вмикайте це, якщо у вас виникають проблеми з DNS-пошуком\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"Увімкнути кешування DNS-запитів для оптимізації продуктивності та уникнення непотрібних API-викликів\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"Примусово спершу резолвити IPv4\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"Використовуйте ',' як роздільник та '*.' як шаблон для піддоменів\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"Обхід проксі для локальних адрес\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"Ім'я користувача проксі\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"Увімкнути підтримку проксі\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"Дозволити Jellyseerr правильно реєструвати IP-адреси клієнтів за проксі\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"Ви повинні вказати дійсний порт\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"Потрібно вибрати принаймні один метод автентифікації.\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"Методи входу\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"Налаштуйте методи входу для користувачів.\",\n  \"components.Settings.addrule\": \"Нове правило перевизначення\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"Всі вибрані провайдери метаданих працюють\",\n  \"components.Settings.animeMetadataProvider\": \"Провайдер метаданих аніме\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"Не вдалося зберегти налаштування провайдера метаданих\",\n  \"components.Settings.invalidKeyword\": \"{keywordId} не є ключовим словом TMDB.\",\n  \"components.Settings.menuMetadataProviders\": \"Провайдери метаданих\",\n  \"components.Settings.metadataProviderSelection\": \"Вибір провайдера метаданих\",\n  \"components.Settings.metadataProviderSettings\": \"Провайдери метаданих\",\n  \"components.Settings.metadataSettings\": \"Налаштування провайдера метаданих\",\n  \"components.Settings.metadataSettingsSaved\": \"Налаштування провайдера метаданих збережено\",\n  \"components.Settings.no\": \"Ні\",\n  \"components.Settings.noSpecialCharacters\": \"Конфігурація повинна бути списком ID ключових слів TMDB, розділених комами, і не повинна починатися або закінчуватися комою.\",\n  \"components.Settings.nooptions\": \"Немає результатів.\",\n  \"components.Settings.notTested\": \"Не тестовано\",\n  \"components.Settings.providerStatus\": \"Статус провайдера метаданих\",\n  \"components.Settings.searchKeywords\": \"Шукати ключові слова…\",\n  \"components.Settings.seriesMetadataProvider\": \"Провайдер метаданих серіалів\",\n  \"components.Settings.settings\": \"Налаштування\",\n  \"components.Settings.starttyping\": \"Почніть вводити для пошуку.\",\n  \"components.Settings.tip\": \"Порада\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"Провайдер TMDB не працює, виберіть інший провайдер метаданих\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"Провайдер TVDB не працює, виберіть інший провайдер метаданих\",\n  \"components.Settings.valueRequired\": \"Ви повинні вказати значення.\",\n  \"components.Settings.yes\": \"Так\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"Цей обліковий запис вже пов'язаний з користувачем {applicationName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"Не вдалося підключитися до {mediaServerName} за допомогою ваших облікових даних\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"Сталася невідома помилка\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"Пароль\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"Ви повинні вказати пароль\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"Пов'язати\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"Додавання…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"Пов'язати обліковий запис {mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"Ім'я користувача\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"Регіон для стримінгу\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"Цей email вже використовується!\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"Інший користувач вже має таке ім'я користувача. Ви повинні вказати email\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"Не вдалося видалити пов'язаний обліковий запис.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"Сталася невідома помилка\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"Пов'язані облікові записи\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"Ці зовнішні облікові записи пов'язані з вашим обліковим записом {applicationName}.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"У вас немає зовнішніх облікових записів, пов'язаних з вашим обліковим записом.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"Видалити підписку\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"Пристрій\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"Вимкнути веб-push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"Щось пішло не так при вимкненні веб-push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"Увімкнути веб-push\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"Щось пішло не так при вмиканні веб-push.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"Рушій\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"Керувати пристроями\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"Щось пішло не так при видаленні підписки користувача.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"тип\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"Невідомо\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"Веб-push вимкнено.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"Веб-push увімкнено.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"Не вдалося зберегти налаштування веб-push сповіщень.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"Налаштування веб-push сповіщень успішно збережено!\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"ID теми/гілки\",\n  \"components.Login.orsigninwith\": \"Або увійти за допомогою\",\n  \"components.Selector.CertificationSelector.noOptions\": \"Немає доступних параметрів\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"Виберіть вікове обмеження\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"Виберіть країну\",\n  \"components.Selector.CertificationSelector.starttyping\": \"Почніть вводити для пошуку.\",\n  \"components.Selector.searchUsers\": \"Виберіть користувачів…\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"Пріоритет\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"Токен\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"Автентифікація за токеном\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"Тема\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"Кореневий URL сервера\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"Змінні URL підтримки\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"Доступні змінні описані в розділі змінних шаблону веб-перехоплювача\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"Тестовий URL для сповіщень встановлено на {testUrl} замість фактичного URL веб-перехоплювача.\",\n  \"components.Settings.Notifications.webhookRoleId\": \"ID ролі для сповіщень\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"ID ролі для згадування у повідомленні веб-перехоплювача. Залиште порожнім для вимкнення згадувань\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"Тегів немає.\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"Правило перевизначення успішно створено!\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"Правило перевизначення успішно оновлено!\",\n  \"components.Settings.OverrideRuleTile.genre\": \"Жанр\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"Ключові слова\",\n  \"components.Settings.OverrideRuleTile.language\": \"Мова\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"Профіль якості\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"Кореневий каталог\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"Кеш DNS\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"Кожен {jobScheduleDays, plural, one {день} other {{jobScheduleDays} днів}}\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"Очистити кеш DNS\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"Частка вдалих\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"Дозволити запити на спеціальні епізоди\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"YouTube URL\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"Базова URL-адреса для відео YouTube, якщо використовується власний екземпляр YouTube.\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"Увімкнути захист CSRF\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"НЕ вмикайте цей параметр, якщо ви не розумієте, що робите!\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"Ім'я хоста проксі\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"Пароль проксі\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"Порт проксі\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"Використовувати SSL для проксі\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"Увімкнути вхід через {mediaServerName}\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"Дозволити користувачам входити за допомогою облікового запису {mediaServerName}\",\n  \"components.Settings.chooseProvider\": \"Виберіть провайдерів метаданих для різних типів контенту\",\n  \"components.Settings.clickTest\": \"Натисніть кнопку \\\"Тест\\\" для перевірки з'єднання з провайдерами метаданих\",\n  \"components.Settings.operational\": \"Працює\",\n  \"components.Settings.overrideRules\": \"Правила перевизначення\",\n  \"components.Settings.overrideRulesDescription\": \"Правила перевизначення дозволяють вказати властивості, які будуть замінені, якщо запит відповідає правилу.\",\n  \"components.Setup.librarieserror\": \"Перевірка не пройдена. Будь ласка, знову перемкніть бібліотеки, щоб продовжити.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"Введіть облікові дані {mediaServerName}, щоб пов'язати ваш обліковий запис з {applicationName}.\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"Ви повинні вказати ім'я користувача\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"Показувати стримінгові сайти за регіональною доступністю\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"У вас немає дозволу на зміну пов'язаних облікових записів цього користувача.\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"Цей обліковий запис вже пов'язаний з користувачем Plex\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"Не вдалося підключитися до Plex за допомогою ваших облікових даних\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"Браузер\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"У вас немає підписок на веб-push для відображення.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"Операційна система\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"Підписку видалено.\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"Якщо у вашому груповому чаті ввімкнено теми, ви можете вказати ID теми/гілки тут\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"ID теми/гілки повинен бути цілим додатним числом\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"Пов'язані облікові записи\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Оновлення токена Plex\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"Змусити Jellyseerr спершу резолвити адреси IPv4 замість IPv6\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"Параметри мережі з вашого контейнера/системи слід використовувати замість цих налаштувань. Дивіться {docs} для отримання додаткової інформації.\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"Налаштуйте параметри мережі для вашого екземпляра Jellyseerr.\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"Ігноровані адреси проксі\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\"\n}\n"
  },
  {
    "path": "src/i18n/locale/vi.json",
    "content": "{\n  \"components.AirDateBadge.airedrelative\": \"Đã phát sóng {relativeTime}\",\n  \"components.AirDateBadge.airsrelative\": \"Phát sóng {relativeTime}\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"Cấu hình gắn kết ổ đĩa ở <code>{appDataPath}</code> không chính xác. Mọi dữ liệu sẽ bị mất khi dừng hoặc khởi động lại container.\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} Phim\",\n  \"components.CollectionDetails.overview\": \"Tổng quát\",\n  \"components.CollectionDetails.requestcollection\": \"Yêu cầu bộ siêu tập\",\n  \"components.CollectionDetails.requestcollection4k\": \"Yêu cầu bộ siêu tập 4K\",\n  \"components.Discover.CreateSlider.addSlider\": \"Thêm thanh trượt\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"Tạo thanh trượt tùy chỉnh\",\n  \"components.Discover.CreateSlider.addfail\": \"Tạo thanh trượt thất bại.\",\n  \"components.Discover.CreateSlider.addsuccess\": \"Tạo thanh trượt mới và lưu cài đặt tùy chỉnh khám phá thành công.\",\n  \"components.Discover.CreateSlider.editSlider\": \"Thay đổi thanh trượt\",\n  \"components.Discover.CreateSlider.editfail\": \"Thay đổi thanh trượt thất bại.\",\n  \"components.Discover.CreateSlider.editsuccess\": \"Thay đổi thanh trượt và lưu cài đặt tùy chỉnh khám phá thành công.\",\n  \"components.Discover.CreateSlider.needresults\": \"Cần ít nhất 1 kết quả.\",\n  \"components.Discover.CreateSlider.nooptions\": \"Không có kết quả.\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"Nhập TMDB Genre ID\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"Nhập TMDB Keyword ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"Nhập TMDB Network ID\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"Nhập từ khóa tìm kiếm\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"Nhập TMDB Studio ID\",\n  \"components.Discover.CreateSlider.searchGenres\": \"Tìm kiếm thể loại…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"Tìm kiếm từ khóa…\",\n  \"components.Discover.CreateSlider.searchStudios\": \"Tìm kiếm hãng phim…\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"Tên thanh trượt\",\n  \"components.Discover.CreateSlider.starttyping\": \"Gõ để tìm kiếm.\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"Phải nhập có giá trị.\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"Phải nhập tựa đề.\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"Phim {genre}\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"Phim {keywordTitle}\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"Phim {language}\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {Dùng # bộ lọc} other {Dùng # bộ lọc}}\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"Phim\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"Phổ biến sắp xếp tăng dần\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"Phổ biến sắp xếp giảm dần\"\n}\n"
  },
  {
    "path": "src/i18n/locale/zh_Hans.json",
    "content": "{\n  \"components.UserList.validationpasswordminchars\": \"密码必须至少包含八个字符\",\n  \"components.UserList.validationEmail\": \"需要提供电子邮件\",\n  \"components.UserList.userssaved\": \"用户权限保存成功！\",\n  \"components.UserList.users\": \"用户\",\n  \"components.UserList.userlist\": \"用户清单\",\n  \"components.UserList.userfail\": \"用户权限保存中出了点问题。\",\n  \"components.UserList.userdeleteerror\": \"刪除用户中出了点问题。\",\n  \"components.UserList.userdeleted\": \"用户刪除成功！\",\n  \"components.UserList.usercreatedsuccess\": \"建立新用户成功！\",\n  \"components.UserList.usercreatedfailedexisting\": \"你提供的电子邮件地址已由其他用户使用。\",\n  \"components.UserList.usercreatedfailed\": \"建立新用户中出了点问题。\",\n  \"components.UserList.user\": \"用户\",\n  \"components.UserList.totalrequests\": \"请求数\",\n  \"components.UserList.sortRequests\": \"请求数\",\n  \"components.UserList.sortDisplayName\": \"显示名称\",\n  \"components.UserList.sortCreated\": \"加入日期\",\n  \"components.UserList.role\": \"角色\",\n  \"components.UserList.plexuser\": \"Plex 用户\",\n  \"components.UserList.passwordinfodescription\": \"设置应用程序网址以及启用电子邮件通知，才能自动生成密码。\",\n  \"components.UserList.password\": \"密码\",\n  \"components.UserList.owner\": \"所有者\",\n  \"components.UserList.nouserstoimport\": \"没有要导入的 Plex 用户。\",\n  \"components.UserList.localuser\": \"本地用户\",\n  \"components.UserList.localLoginDisabled\": \"<strong>允许本地登录</strong>的设置目前被禁用。\",\n  \"components.UserList.importfromplexerror\": \"导入 Plex 用户时出错。\",\n  \"components.UserList.importfromplex\": \"导入 Plex 用户\",\n  \"components.UserList.importedfromplex\": \"<strong>{userCount}</strong> Plex {userCount, plural, one {user} other {users}} 成功导入！\",\n  \"components.UserList.email\": \"电子邮件地址\",\n  \"components.UserList.edituser\": \"编辑用户权限\",\n  \"components.UserList.deleteuser\": \"刪除用户\",\n  \"components.UserList.deleteconfirm\": \"确定要刪除这个用户吗？此用户的所有储存资料将被清除。\",\n  \"components.UserList.creating\": \"创建中…\",\n  \"components.UserList.createlocaluser\": \"建立本地用户\",\n  \"components.UserList.created\": \"加入\",\n  \"components.UserList.create\": \"建立\",\n  \"components.UserList.bulkedit\": \"批量编辑\",\n  \"components.UserList.autogeneratepasswordTip\": \"通過电子邮件发送服务器生成的密码给用户\",\n  \"components.UserList.autogeneratepassword\": \"自动生成密码\",\n  \"components.UserList.admin\": \"管理员\",\n  \"components.UserList.accounttype\": \"类型\",\n  \"components.TvDetails.watchtrailer\": \"观看预告片\",\n  \"components.TvDetails.viewfullcrew\": \"查看完整制作群\",\n  \"components.TvDetails.similar\": \"类似\",\n  \"components.TvDetails.showtype\": \"节目类型\",\n  \"components.TvDetails.seasons\": \"{seasonCount} 季\",\n  \"components.TvDetails.recommendations\": \"推荐\",\n  \"components.TvDetails.overviewunavailable\": \"没有简介。\",\n  \"components.TvDetails.overview\": \"简介\",\n  \"components.TvDetails.originaltitle\": \"原始標題\",\n  \"components.TvDetails.originallanguage\": \"原始语言\",\n  \"components.TvDetails.nextAirDate\": \"下一次播出日期\",\n  \"components.TvDetails.network\": \"{networkCount, plural, one {Network} other {Networks}}\",\n  \"components.TvDetails.firstAirDate\": \"原始播出日期\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} 分钟\",\n  \"components.TvDetails.episodeRuntime\": \"劇集片長\",\n  \"components.TvDetails.cast\": \"演员阵容\",\n  \"components.TvDetails.anime\": \"动漫\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"制作群\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"演员阵容\",\n  \"components.StatusBadge.status4k\": \"4K 版{status}\",\n  \"components.Setup.welcome\": \"欢迎來到 Seerr\",\n  \"components.Setup.signinMessage\": \"首先，请使用你的 Plex 账户登入\",\n  \"components.Setup.setup\": \"配置\",\n  \"components.Setup.finishing\": \"完成配置中…\",\n  \"components.Setup.finish\": \"完成配置\",\n  \"components.Setup.continue\": \"继续\",\n  \"components.Setup.configureservices\": \"配置服务器\",\n  \"components.Settings.webpush\": \"网络推送\",\n  \"components.Settings.webhook\": \"网络钩子\",\n  \"components.Settings.webAppUrlTip\": \"使用服务器的网络应用代替“托管”的网络应用\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>网络应用</WebAppLink>网址（URL）\",\n  \"components.Settings.validationPortRequired\": \"请输入有效的端口\",\n  \"components.Settings.validationHostnameRequired\": \"请输入有效的主机名称或 IP 地址\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"获取 Plex 服务器列表成功！\",\n  \"components.Settings.toastPlexRefreshFailure\": \"获取 Plex 服务器列表失败。\",\n  \"components.Settings.toastPlexRefresh\": \"载入中…\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex 服务器连线成功！\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Plex 服务器连线失败。\",\n  \"components.Settings.toastPlexConnecting\": \"连线中…\",\n  \"components.Settings.startscan\": \"执行扫描\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.sonarrsettings\": \"Sonarr 设置\",\n  \"components.Settings.settingUpPlexDescription\": \"你可以手动输入你的 Plex 服务器资料，或从 <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink> 返回的设置做选择以及自动配置。请点下拉式选单右边的按钮获取服务器列表。\",\n  \"components.Settings.services\": \"服务器\",\n  \"components.Settings.serviceSettingsDescription\": \"关于 {serverType} 服务器的设置。{serverType} 服务器数没有最大值限制，但你只能指定兩个服务器为默认（一个非 4K、一个 4K）。\",\n  \"components.Settings.serverpresetRefreshing\": \"载入中…\",\n  \"components.Settings.serverpresetManualMessage\": \"手动设定\",\n  \"components.Settings.serverpresetLoad\": \"请点右边的按钮\",\n  \"components.Settings.serverpreset\": \"服务器\",\n  \"components.Settings.serverSecure\": \"SSL\",\n  \"components.Settings.serverRemote\": \"遠端\",\n  \"components.Settings.serverLocal\": \"本地\",\n  \"components.Settings.scanning\": \"同步中…\",\n  \"components.Settings.scan\": \"媒体库同步\",\n  \"components.Settings.radarrsettings\": \"Radarr 设置\",\n  \"components.Settings.port\": \"端口\",\n  \"components.Settings.plexsettingsDescription\": \"配置您的 Plex 服务器设置。Seerr 将通过扫描 Plex 媒体库来确定内容可用性。\",\n  \"components.Settings.plexsettings\": \"Plex 设置\",\n  \"components.Settings.plexlibrariesDescription\": \"Seerr 扫描影片的媒体库。如果未列出任何媒体库，请先设置并保存您的 Plex 连接配置，然后点击下方按钮。\",\n  \"components.Settings.plexlibraries\": \"Plex 媒体库\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notrunning\": \"未运行\",\n  \"components.Settings.notificationsettings\": \"通知设置\",\n  \"components.Settings.notifications\": \"通知\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"设置通知类型和代理服务。\",\n  \"components.Settings.noDefaultServer\": \"你必须至少指定一个 {serverType} 服务器为默认，才能处理{mediaType}请求。\",\n  \"components.Settings.noDefaultNon4kServer\": \"如果你只有一台 {serverType} 服务器用于非 4K 和 4K 内容（或者如果你只下载 4k 内容），你的 {serverType} 服务器 <strong>不应该</strong>被指定为 4K 服务器。\",\n  \"components.Settings.noDefault4kServer\": \"你必须指定一个 4K {serverType} 服务器为默认，才能处理 4K 的{mediaType}请求。\",\n  \"components.Settings.menuUsers\": \"用户\",\n  \"components.Settings.menuServices\": \"服务器\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.Settings.menuNotifications\": \"通知\",\n  \"components.Settings.menuLogs\": \"日志\",\n  \"components.Settings.menuJobs\": \"作业和缓存\",\n  \"components.Settings.menuGeneralSettings\": \"常规\",\n  \"components.Settings.menuAbout\": \"关于 Seerr\",\n  \"components.Settings.mediaTypeSeries\": \"电视节目\",\n  \"components.Settings.mediaTypeMovie\": \"电影\",\n  \"components.Settings.manualscanDescription\": \"在正常情況下，Seerr 会每24小时扫描一次你的 Plex 媒体库。Seerr会更积极地检查你的Plex服务器最近添加的内容。如果这是你第一次配置Plex，我们建议你执行一次手动扫描！\",\n  \"components.Settings.manualscan\": \"媒体库手动扫描\",\n  \"components.Settings.librariesRemaining\": \"媒体库剩余数： {count}\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.hostname\": \"主机名称或 IP 地址\",\n  \"components.Settings.enablessl\": \"使用安全通訊协议（SSL）\",\n  \"components.Settings.email\": \"电子邮件\",\n  \"components.Settings.deleteserverconfirm\": \"确定要刪除这个服务器吗？\",\n  \"components.Settings.default4k\": \"设置 4K 为默认分辨率\",\n  \"components.Settings.default\": \"默认\",\n  \"components.Settings.currentlibrary\": \"当前媒体库： {name}\",\n  \"components.Settings.cancelscan\": \"取消扫描\",\n  \"components.Settings.addsonarr\": \"添加 Sonarr 服务器\",\n  \"components.Settings.address\": \"网址\",\n  \"components.Settings.addradarr\": \"添加 Radarr 服务器\",\n  \"components.Settings.activeProfile\": \"现行质量设置\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"必须设置根目录\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"必须设置质量\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"请输入有效的端口\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"请输入服务器名称\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"必须设置语言\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"你必须提供有效的主机名或 IP 地址\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"必须刪除結尾斜線\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"必须添加前置斜線\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"必须刪除結尾斜線\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"请输入有效的网址\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"请输入应用程序密钥\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr 服务器连线成功！\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Sonarr 服务器连线失败。\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"请先测试连线\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"请先测试连线\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"请先测试连线\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"请先测试连线\",\n  \"components.Settings.SonarrModal.tags\": \"标签\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"启用扫描\",\n  \"components.Settings.SonarrModal.ssl\": \"使用安全通訊协议（SSL）\",\n  \"components.Settings.SonarrModal.servername\": \"服务器名称\",\n  \"components.Settings.SonarrModal.server4k\": \"4K 服务器\",\n  \"components.Settings.SonarrModal.selecttags\": \"设定标签\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"设定根目录\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"设定质量\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"设定语言\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"季数档案夹\",\n  \"components.Settings.SonarrModal.rootfolder\": \"根目录\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"质量设置\",\n  \"components.Settings.SonarrModal.port\": \"端口\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"自动批准非 4K 电视节目请求。\",\n  \"components.PermissionEdit.autoapproveSeries\": \"电视节目自动批准\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"自动批准非 4K 电影请求。\",\n  \"components.PermissionEdit.autoapproveMovies\": \"电影自动批准\",\n  \"components.PermissionEdit.autoapproveDescription\": \"自动批准所有非 4K 媒体请求。\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"自动批准 4K 电视节目请求。\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"4K 电视节目自动批准\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"自动批准 4K 电影请求。\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"4K 电影自动批准\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"自动批准所有 4K 媒体请求。\",\n  \"components.PermissionEdit.autoapprove4k\": \"自动批准 4K\",\n  \"components.PermissionEdit.autoapprove\": \"自动批准\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"授予修改高级媒体请求选项的权限。\",\n  \"components.PermissionEdit.advancedrequest\": \"进阶请求\",\n  \"components.PermissionEdit.adminDescription\": \"授予最高权限；旁路所有权限检查。\",\n  \"components.PermissionEdit.admin\": \"管理员\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"当其他用户提交需要管理员批准的请求时得到通知。\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"当 Radarr 或 Sonarr 处理请求失败时得到通知。\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"当你的请求被拒绝时得到通知。\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"当你请求的媒体可观看时得到通知。\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"当你的请求被手动批准时得到通知。\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"当其他用户提交自动批准的请求时得到通知。\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"通知类型\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"当用户提交需要管理员批准的请求时发送通知。\",\n  \"components.NotificationTypeSelector.mediarequested\": \"请求待批准\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"当 Radarr 或 Sonarr 处理请求失败时发送通知。\",\n  \"components.NotificationTypeSelector.mediafailed\": \"请求处理失败\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"当请求拒被絕时发送通知。\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"请求被拒\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"当请求的媒体可观看时发送通知。\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"请求可用\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"当请求被手动批准时发送通知。\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"请求已获批准\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"当用户提交自动批准的请求时发送通知。\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"请求自动批准\",\n  \"components.MovieDetails.watchtrailer\": \"观看预告片\",\n  \"components.MovieDetails.viewfullcrew\": \"查看完整制作群\",\n  \"components.MovieDetails.studio\": \"制作公司\",\n  \"components.MovieDetails.similar\": \"类似\",\n  \"components.MovieDetails.showmore\": \"显示更多\",\n  \"components.MovieDetails.showless\": \"显示更少\",\n  \"components.MovieDetails.runtime\": \"{minutes} 分钟\",\n  \"components.MovieDetails.revenue\": \"收入\",\n  \"components.MovieDetails.releasedate\": \"上映日期\",\n  \"components.MovieDetails.recommendations\": \"推荐\",\n  \"components.MovieDetails.overviewunavailable\": \"没有简介。\",\n  \"components.MovieDetails.overview\": \"简介\",\n  \"components.MovieDetails.originaltitle\": \"原始標題\",\n  \"components.MovieDetails.originallanguage\": \"原始语言\",\n  \"components.MovieDetails.markavailable\": \"標记为可观看\",\n  \"components.MovieDetails.mark4kavailable\": \"標记 4K 版为可观看\",\n  \"components.MovieDetails.cast\": \"演员阵容\",\n  \"components.MovieDetails.budget\": \"电影成本\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"制作群\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"演员阵容\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"更多\",\n  \"components.Login.validationpasswordrequired\": \"请输入你的密码\",\n  \"components.Login.validationemailrequired\": \"请输入有效的电子邮件地址\",\n  \"components.Login.signinwithplex\": \"使用你的 Plex 账户\",\n  \"components.Login.signinwithoverseerr\": \"使用你的 {applicationTitle} 账户\",\n  \"components.Login.signinheader\": \"请先登入\",\n  \"components.Login.signingin\": \"登入中…\",\n  \"components.Login.signin\": \"登入\",\n  \"components.Login.password\": \"密码\",\n  \"components.Login.loginerror\": \"登入中出了点问题。\",\n  \"components.Login.forgotpassword\": \"忘记密码？\",\n  \"components.Login.email\": \"电子邮件地址\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr 稳定版\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr 开发版\",\n  \"components.Layout.VersionStatus.outofdate\": \"過时\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"落后 {commitsBehind} 次提交\",\n  \"components.Layout.UserDropdown.signout\": \"登出\",\n  \"components.Layout.UserDropdown.settings\": \"用户设定\",\n  \"components.Layout.UserDropdown.myprofile\": \"个人档案\",\n  \"components.Layout.Sidebar.browsemovies\": \"电影\",\n  \"components.Layout.Sidebar.browsetv\": \"电视节目\",\n  \"components.Layout.Sidebar.users\": \"用户\",\n  \"components.Layout.Sidebar.settings\": \"设定\",\n  \"components.Layout.Sidebar.requests\": \"请求\",\n  \"components.Layout.Sidebar.dashboard\": \"探索\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"搜索电影、电视节目\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"显示语言\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"所有语言\",\n  \"components.LanguageSelector.languageServerDefault\": \"默认设置（{language}）\",\n  \"components.DownloadBlock.estimatedtime\": \"预计：{time}\",\n  \"components.Discover.upcomingtv\": \"即将上映的电视节目\",\n  \"components.Discover.upcomingmovies\": \"即将上映的电影\",\n  \"components.Discover.upcoming\": \"即将上映的电影\",\n  \"components.Discover.trending\": \"趋势\",\n  \"components.Discover.recentrequests\": \"最新请求\",\n  \"components.Discover.recentlyAdded\": \"最新添加\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"最新添加\",\n  \"components.Discover.populartv\": \"热门电视节目\",\n  \"components.Discover.popularmovies\": \"热门电影\",\n  \"components.Discover.discover\": \"探索\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"电视节目类型\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"电视节目类型\",\n  \"components.Discover.StudioSlider.studios\": \"制作公司\",\n  \"components.Discover.NetworkSlider.networks\": \"流媒体平台\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"电影类型\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"电影类型\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language}电视节目\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre}电视节目\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} 电影\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} 电视节目\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language}电影\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre}电影\",\n  \"components.CollectionDetails.requestcollection4k\": \"提交 4K 系列请求\",\n  \"components.CollectionDetails.requestcollection\": \"提交系列请求\",\n  \"components.CollectionDetails.overview\": \"简介\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} 部电影\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code> 卷挂载配置不正确。容器停止或重启时，所有数据将被清除。\",\n  \"components.PersonDetails.ascharacter\": \"饰演 {character}\",\n  \"pages.somethingwentwrong\": \"出了点问题\",\n  \"pages.serviceunavailable\": \"服务器无法使用\",\n  \"pages.returnHome\": \"返回首页\",\n  \"pages.pagenotfound\": \"页面不存在\",\n  \"pages.oops\": \"哎呀\",\n  \"pages.internalservererror\": \"內部服务器错误\",\n  \"pages.errormessagewithcode\": \"{statusCode}－{error}\",\n  \"i18n.view\": \"查看\",\n  \"i18n.usersettings\": \"用户设定\",\n  \"i18n.unavailable\": \"不可观看\",\n  \"i18n.tvshows\": \"电视节目\",\n  \"i18n.tvshow\": \"电视节目\",\n  \"i18n.testing\": \"测试中…\",\n  \"i18n.test\": \"测试\",\n  \"i18n.status\": \"状态\",\n  \"i18n.showingresults\": \"<strong>{from}</strong>－<strong>{to}</strong> 列（共 <strong>{total}</strong> 列）\",\n  \"i18n.settings\": \"设定\",\n  \"i18n.saving\": \"保存中…\",\n  \"i18n.save\": \"保存\",\n  \"i18n.retrying\": \"重试中…\",\n  \"i18n.retry\": \"重试\",\n  \"i18n.resultsperpage\": \"每页显示 {pageSize} 列\",\n  \"i18n.requesting\": \"提交请求中…\",\n  \"i18n.requested\": \"已经有请求\",\n  \"i18n.request4k\": \"提交 4K 请求\",\n  \"i18n.request\": \"提交请求\",\n  \"i18n.processing\": \"处理中\",\n  \"i18n.previous\": \"上一页\",\n  \"i18n.pending\": \"待处理\",\n  \"i18n.partiallyavailable\": \"部分可观看\",\n  \"i18n.notrequested\": \"没有请求\",\n  \"i18n.noresults\": \"没有結果。\",\n  \"i18n.next\": \"下一页\",\n  \"i18n.movies\": \"电影\",\n  \"i18n.movie\": \"电影\",\n  \"i18n.loading\": \"载入中…\",\n  \"i18n.failed\": \"失败\",\n  \"i18n.experimental\": \"实验性\",\n  \"i18n.edit\": \"编辑\",\n  \"i18n.delimitedlist\": \"{a}、{b}\",\n  \"i18n.deleting\": \"刪除中…\",\n  \"i18n.delete\": \"刪除\",\n  \"i18n.declined\": \"已拒绝\",\n  \"i18n.decline\": \"拒绝\",\n  \"i18n.close\": \"关闭\",\n  \"i18n.canceling\": \"取消中…\",\n  \"i18n.cancel\": \"取消\",\n  \"i18n.back\": \"返回\",\n  \"i18n.available\": \"可观看\",\n  \"i18n.areyousure\": \"确定吗？\",\n  \"i18n.approved\": \"已批准\",\n  \"i18n.approve\": \"批准\",\n  \"i18n.all\": \"所有\",\n  \"i18n.advanced\": \"进阶\",\n  \"components.UserProfile.unlimited\": \"无限\",\n  \"components.UserProfile.totalrequests\": \"请求总数\",\n  \"components.UserProfile.seriesrequest\": \"电视节目请求\",\n  \"components.UserProfile.requestsperdays\": \"剩余 {limit}\",\n  \"components.UserProfile.recentrequests\": \"最新请求\",\n  \"components.UserProfile.pastdays\": \"{type}（前 {days} 天）\",\n  \"components.UserProfile.movierequests\": \"电影请求\",\n  \"components.UserProfile.limit\": \"{limit} 之 {remaining}\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"你无权编辑此用户的设置。\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"权限\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"通知\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"常规\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"密码\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"你不能编辑自己的权限。\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"权限设置保存成功！\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"保存设置中出了点问题。\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"权限设置\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"密码必须至少包含八个字符\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"请输入新密码\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"请输入当前的密码\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"密码必须匹配\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"密码必须匹配\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"密码设置成功！\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"重设密码中出了点问题。你确定输入的当前密码是正确的吗？\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"重设密码中出了点问题。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"密码设置\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"你无权设置此用户的密码。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"你的帐户目前没有设置密码。在下方配置密码，使你能够作为“本地用户”登录。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"该用户账户当前未设置密码。请在下方配置密码，以启用“本地用户”登录功能。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"新密码\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"当前的密码\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"确认密码\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"网络推送\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"请输入聊天室 ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"请输入有效的 PGP 公钥\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"请输入有效的用户 ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram 通知设置保存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Telegram 通知设置保存失败。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"先<TelegramBotLink>建立一个聊天室</TelegramBotLink>以及把 <GetIdBotLink>@get_id_bot</GetIdBotLink> 加到聊天室，然后在聊天室里发出 <code>/my_id</code> 命令\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"聊天室 ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"发送没有声音警报的通知\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"无声通知\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"使用 <OpenPgpLink>OpenPGP</OpenPgpLink> 电子邮件加密\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"PGP 公钥\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"通知设置\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"通知\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"电子邮件通知设置保存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"电子邮件通知设置保存失败。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"电子邮件\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord 通知设置保存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Discord 通知设置保存失败。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"和用户账号关联的<FindDiscordIdLink>多位数 ID 号码</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"用户 ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"用户\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"设置保存成功！\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"保存设置中出了点问题。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"电视节目请求限制\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"角色\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"以地区可用性筛选結果\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"探索地区\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex 用户\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"所有者\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"以原始语言筛选結果\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"探索语言\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"电影请求限制\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"本地用户\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"默认设置（{language}）\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"常规设置\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"常规\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"覆盖全局限制\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"显示名称\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"显示语言\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"管理员\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"用户类型\",\n  \"components.UserProfile.ProfileHeader.userid\": \"用户 ID：{userid}\",\n  \"components.UserProfile.ProfileHeader.settings\": \"用户设定\",\n  \"components.UserProfile.ProfileHeader.profile\": \"个人档案\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"建立日期：{joindate}\",\n  \"components.Settings.SonarrModal.notagoptions\": \"没有标签。\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"载入中…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"载入中…\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"载入中…\",\n  \"components.Settings.SonarrModal.loadingTags\": \"载入中…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"语言设置\",\n  \"components.Settings.SonarrModal.hostname\": \"主机名称或 IP 地址\",\n  \"components.Settings.SonarrModal.externalUrl\": \"外部网址\",\n  \"components.Settings.SonarrModal.enableSearch\": \"启用自动搜索\",\n  \"components.Settings.SonarrModal.editsonarr\": \"编辑 Sonarr 服务器\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"编辑 4K Sonarr 服务器\",\n  \"components.Settings.SonarrModal.defaultserver\": \"默认服务器\",\n  \"components.Settings.SonarrModal.default4kserver\": \"默认 4K 服务器\",\n  \"components.Settings.SonarrModal.createsonarr\": \"添加 Sonarr 服务器\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"添加 4K Sonarr 服务器\",\n  \"components.Settings.SonarrModal.baseUrl\": \"网站根目录\",\n  \"components.Settings.SonarrModal.apiKey\": \"应用程序密钥\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"动漫根目录\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"动漫质量设置\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"动漫语言设置\",\n  \"components.Settings.SonarrModal.animeTags\": \"动漫标签\",\n  \"components.Settings.SonarrModal.add\": \"添加服务器\",\n  \"components.Settings.SettingsUsers.users\": \"用户\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"关于用户的全局和默认设置。\",\n  \"components.Settings.SettingsUsers.userSettings\": \"用户设置\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"电视节目请求全局限制\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"用户设置保存成功！\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"保存设置中出了点问题。\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"让还没导入的 Plex 用户登录\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"允许新的 Plex 登录\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"电影请求全局限制\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"允许用户使用电子邮件地址和密码登录\",\n  \"components.Settings.SettingsUsers.localLogin\": \"允许本地登录\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"授予给新用户的权限\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"默认权限\",\n  \"components.Settings.SettingsLogs.time\": \"时间戳\",\n  \"components.Settings.SettingsLogs.showall\": \"查看所有日志\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"恢复\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"暫停\",\n  \"components.Settings.SettingsLogs.message\": \"消息\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"您也可以通过<code>stdout</code>或<code>{appDataPath}/logs/seerr.log</code>直接查看这些日志。\",\n  \"components.Settings.SettingsLogs.logs\": \"日志\",\n  \"components.Settings.SettingsLogs.logDetails\": \"日志详細信息\",\n  \"components.Settings.SettingsLogs.level\": \"等級\",\n  \"components.Settings.SettingsLogs.label\": \"标签\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"警告\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"消息\",\n  \"components.Settings.SettingsLogs.filterError\": \"错误\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"除错\",\n  \"components.Settings.SettingsLogs.extraData\": \"附加数据\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"复制到剪贴板\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"日志消息已复制到剪贴板。\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"未知作业\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr 扫描\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"执行\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr 扫描\",\n  \"components.Settings.SettingsJobsCache.process\": \"程序\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plex 最新添加扫描\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plex 媒体库扫描\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"下一次执行时间\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"作业类型\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} 已开始运行。\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"作业和缓存\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Seerr将某些维护任务作为定期计划的任务执行，但它们也可以在下面手动触发。手动运行任务不会改变它的时间表。\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"作业\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"作业名\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname}已被取消。\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"清除缓存\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"下载状态同步复位\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"下载状态同步\",\n  \"components.Settings.SettingsJobsCache.command\": \"命令\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"取消作业\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"值储存大小\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"缓存名\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"失误数\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"键储存大小\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"键数\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"击中数\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} 缓存已清除。\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"Seerr将请求缓存到外部API端点，以优化性能，避免进行不必要的API调用。\",\n  \"components.Settings.SettingsJobsCache.cache\": \"缓存\",\n  \"components.Settings.SettingsAbout.version\": \"软件版本\",\n  \"components.Settings.SettingsAbout.uptodate\": \"最新\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"请求数\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"媒体数\",\n  \"components.Settings.SettingsAbout.timezone\": \"时区\",\n  \"components.Settings.SettingsAbout.outofdate\": \"過时\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub 讨论区\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"支援\",\n  \"components.Settings.SettingsAbout.documentation\": \"文档\",\n  \"components.Settings.SettingsAbout.about\": \"关于 Seerr\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"在 GitHub 上查看\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"查看变更日志\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} 更新日志\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"软件版本\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"软件发行数据当前不可用。\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"最新软件版本\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"当前版本\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"必须设置根目录\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"必须设置质量\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"请输入有效的端口\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"请输入服务器名称\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"必须设置最低状态\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"你必须提供有效的主机名或 IP 地址\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"URL base 不能以尾部斜杠结束\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"URL base 必须有前置斜杠\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"必须刪除結尾斜線\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"请输入有效的网址\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"请输入应用程序密钥\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr 服务器连线成功！\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Radarr 服务器连线失败。\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"请先测试连线\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"请先测试连线\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"请先测试连线\",\n  \"components.Settings.RadarrModal.tags\": \"标签\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"启用扫描\",\n  \"components.Settings.RadarrModal.ssl\": \"使用安全通訊协议（SSL）\",\n  \"components.Settings.RadarrModal.servername\": \"服务器名称\",\n  \"components.Settings.RadarrModal.server4k\": \"4K 服务器\",\n  \"components.Settings.RadarrModal.selecttags\": \"设定标签\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"设定根目录\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"设定质量\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"设定最低状态\",\n  \"components.Settings.RadarrModal.rootfolder\": \"根目录\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"质量设置\",\n  \"components.Settings.RadarrModal.port\": \"端口\",\n  \"components.Settings.RadarrModal.notagoptions\": \"没有标签。\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"最低状态\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"载入中…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"载入中…\",\n  \"components.Settings.RadarrModal.loadingTags\": \"载入中…\",\n  \"components.Settings.RadarrModal.hostname\": \"主机名称或 IP 地址\",\n  \"components.Settings.RadarrModal.externalUrl\": \"外部网址（URL）\",\n  \"components.Settings.RadarrModal.enableSearch\": \"启用自动搜索\",\n  \"components.Settings.RadarrModal.editradarr\": \"编辑 Radarr 服务器\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"编辑 4K Radarr 服务器\",\n  \"components.Settings.RadarrModal.defaultserver\": \"默认服务器\",\n  \"components.Settings.RadarrModal.default4kserver\": \"默认 4K 服务器\",\n  \"components.Settings.RadarrModal.createradarr\": \"添加 Radarr 服务器\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"添加 4K Radarr 服务器\",\n  \"components.Settings.RadarrModal.baseUrl\": \"网站根目录\",\n  \"components.Settings.RadarrModal.apiKey\": \"应用程序密钥\",\n  \"components.Settings.RadarrModal.add\": \"添加服务器\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"在你的服务器里创建一个<DiscordWebhookLink>网络钩子</DiscordWebhookLink>\",\n  \"components.Settings.Notifications.webhookUrl\": \"网络钩子网址（URL）\",\n  \"components.Settings.Notifications.validationUrl\": \"请输入有效的网址\",\n  \"components.Settings.Notifications.validationTypes\": \"请选择通知类型\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"请输入有效的端口\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"请输入有效的主机名称或 IP 地址\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"请输入有效的 PGP 私钥\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"请输入 PGP 解密密码\",\n  \"components.Settings.Notifications.validationEmail\": \"请输入有效的电子邮件地址\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"请输入有效的聊天室 ID\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"请输入机器人授权令牌\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram 测试通知已发送！\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"发送 Telegram 测试通知中…\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram 测试通知发送失败。\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"电子邮件测试通知已发送！\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"发送电子邮件测试通知中…\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"电子邮件测试通知发送失败。\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord 测试通知已发送！\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"发送 Discord 测试通知中…\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord 测试通知发送失败。\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram 通知设置保存成功！\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegram 通知设置保存失败。\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP 端口\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP 主机\",\n  \"components.Settings.Notifications.senderName\": \"发件人姓名\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"发送没有声音警报的通知\",\n  \"components.Settings.Notifications.sendSilently\": \"无声通知\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"使用 <OpenPgpLink>OpenPGP</OpenPgpLink> 电子邮件加密与签章\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP 私钥\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"使用 <OpenPgpLink>OpenPGP</OpenPgpLink> 电子邮件加密与签章\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP 解密密码\",\n  \"components.Settings.Notifications.encryptionTip\": \"TLS 通常会使用端口 465，而 STARTTLS 通常会使用端口 587\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Authorization 頭欄位\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"启用通知\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"网络推送通知设置保存成功！\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"网络推送通知设置保存失败。\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"网络推送测试通知已发送！\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"发送网络推送测试通知中…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"网络推送测试通知发送失败。\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"为了接收web推送通知，Seerr必须通过HTTPS提供服务。\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"启用通知\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"创建一个 <WebhookLink>incoming webhook</WebhookLink> 集成\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"网络钩子网址（URL）\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"请输入有效的网址\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"请选择通知类型\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack 测试通知已发送！\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"发送 Slack 测试通知中…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack 测试通知发送失败。\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack 通知设置保存成功！\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Slack 通知设置保存失败。\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"启用通知\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"请输入有效的用户或群组令牌\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"请选择通知类型\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"请输入应用程序 API 令牌\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"你的 30 个字符的<UsersGroupsLink>用户或群组標識符</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"用户或群组令牌\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover 测试通知已发送！\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"发送 Pushover 测试通知中…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover 测试通知发送失败。\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover 通知设置保存成功！\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushover 通知设置保存失败。\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"启用通知\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"<ApplicationRegistrationLink>创建应用</ApplicationRegistrationLink> 并关联 Seerr\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"应用程序 API 令牌\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"请选择通知类型\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"请输入 API 令牌\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet 测试通知已发送！\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"发送 Pushbullet 测试通知中…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet 测试通知发送失败。\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet 通知设置保存成功！\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbullet 通知设置保存失败。\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"启用通知\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"从你的<PushbulletSettingsLink>账户设定</PushbulletSettingsLink>取得 API 令牌\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"API 令牌\",\n  \"components.Search.searchresults\": \"搜索結果\",\n  \"components.Search.search\": \"搜索\",\n  \"components.ResetPassword.validationpasswordrequired\": \"请输入密码\",\n  \"components.ResetPassword.validationpasswordminchars\": \"密码必须至少包含八个字符\",\n  \"components.ResetPassword.validationpasswordmatch\": \"密码必须匹配\",\n  \"components.ResetPassword.validationemailrequired\": \"请输入有效的电子邮件地址\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"密码重设成功！\",\n  \"components.ResetPassword.resetpassword\": \"重设密码\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"通過电子邮件发送了密码重设鏈接。\",\n  \"components.ResetPassword.passwordreset\": \"密码重设\",\n  \"components.ResetPassword.password\": \"密码\",\n  \"components.ResetPassword.gobacklogin\": \"返回\",\n  \"components.ResetPassword.emailresetlink\": \"发送密码重设电子邮件\",\n  \"components.ResetPassword.email\": \"电子邮件地址\",\n  \"components.ResetPassword.confirmpassword\": \"确认密码\",\n  \"components.RequestModal.selectseason\": \"季数选择\",\n  \"components.RequestModal.seasonnumber\": \"第 {number} 季\",\n  \"components.RequestModal.season\": \"季数\",\n  \"components.RequestModal.requestseasons\": \"提交请求\",\n  \"components.RequestModal.requestfrom\": \"{username} 的请求待处理。\",\n  \"components.RequestModal.requesterror\": \"提交请求中出了点问题。\",\n  \"components.RequestModal.requestedited\": \"<strong>{title}</strong> 的请求编辑成功！\",\n  \"components.RequestModal.requestcancelled\": \"<strong>{title}</strong> 的请求已被取消。\",\n  \"components.RequestModal.requestadmin\": \"此请求将自动被批准。\",\n  \"components.RequestModal.requestSuccess\": \"为 <strong>{title}</strong> 提交请求成功！\",\n  \"components.RequestModal.requestCancel\": \"<strong>{title}</strong> 的请求已被取消。\",\n  \"components.RequestModal.pendingrequest\": \"待处理请求\",\n  \"components.RequestModal.pendingapproval\": \"你的请求正在等待管理员批准。\",\n  \"components.RequestModal.pending4krequest\": \"待处理的 4K 请求\",\n  \"components.RequestModal.numberofepisodes\": \"集数\",\n  \"components.RequestModal.errorediting\": \"编辑请求中出了点问题。\",\n  \"components.RequestModal.edit\": \"编辑请求\",\n  \"components.RequestModal.cancel\": \"取消请求\",\n  \"components.RequestModal.autoapproval\": \"自动批准\",\n  \"components.RequestModal.alreadyrequested\": \"已经有请求\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"我们无法自动匹配这个连续剧。请选择下方正确的匹配。\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"个季数\",\n  \"components.RequestModal.QuotaDisplay.season\": \"电视节目季数\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"此用户的电视节目请求数量必须至少剩余 <strong>{seasons}</strong> 个季数才能为此节目提交请求。\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"你的电视节目请求数量必须至少剩余 <strong>{seasons}</strong> 个季数才能为此节目提交请求。\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {电影请求剩余数不足} other {剩余 <strong>#</strong> 个{type}请求}}\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"访问此用户的<ProfileLink>个人资料页面</ProfileLink>以查看用户的请求限制 。\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"访问你的<ProfileLink>个人资料页面</ProfileLink>以查看你的请求限制 。\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"请求剩余数不足\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"部电影\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"电影\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"此用户每 <strong>{days}</strong> 天能为 <strong>{limit}</strong> {type}提交请求。\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"你每 <strong>{days}</strong> 天能为 <strong>{limit}</strong> {type}提交请求。\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"标签\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"设定标签\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"根目录\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"请求者\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"质量设置\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"没有标签。\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"语言设置\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path}（{space}）\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"目標服务器\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name}（默认）\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"＊这是个动漫节目。\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"进阶选项\",\n  \"components.RequestList.sortModified\": \"最后修改时间\",\n  \"components.RequestList.sortAdded\": \"最新\",\n  \"components.RequestList.showallrequests\": \"查看所有请求\",\n  \"components.RequestList.requests\": \"请求\",\n  \"components.RequestList.RequestItem.seasons\": \"季数\",\n  \"components.RequestList.RequestItem.requesteddate\": \"请求日期\",\n  \"components.RequestList.RequestItem.requested\": \"请求者\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{user}（{date}）\",\n  \"components.RequestList.RequestItem.modified\": \"最后修改者\",\n  \"components.RequestList.RequestItem.mediaerror\": \"未找到{mediaType}\",\n  \"components.RequestList.RequestItem.failedretry\": \"重试提交请求中出了点问题。\",\n  \"components.RequestList.RequestItem.editrequest\": \"编辑请求\",\n  \"components.RequestList.RequestItem.deleterequest\": \"刪除请求\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"取消请求\",\n  \"components.RequestCard.seasons\": \"季数\",\n  \"components.RequestCard.mediaerror\": \"未找到{mediaType}\",\n  \"components.RequestCard.failedretry\": \"重试提交请求中出了点问题。\",\n  \"components.RequestCard.deleterequest\": \"刪除请求\",\n  \"components.RequestButton.viewrequest4k\": \"查看 4K 请求\",\n  \"components.RequestButton.viewrequest\": \"查看请求\",\n  \"components.RequestButton.requestmore4k\": \"再提交 4K 请求\",\n  \"components.RequestButton.requestmore\": \"提交更多季数的请求\",\n  \"components.RequestButton.declinerequests\": \"拒绝{requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.declinerequest4k\": \"拒绝 4K 请求\",\n  \"components.RequestButton.declinerequest\": \"拒绝请求\",\n  \"components.RequestButton.decline4krequests\": \"拒绝 {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestButton.approverequests\": \"批准 {requestCount, plural, one {Request} other {{requestCount} Requests}}\",\n  \"components.RequestButton.approverequest4k\": \"批准 4K 请求\",\n  \"components.RequestButton.approverequest\": \"批准请求\",\n  \"components.RequestButton.approve4krequests\": \"批准 {requestCount, plural, one {4K Request} other {{requestCount} 4K Requests}}\",\n  \"components.RequestBlock.server\": \"目標服务器\",\n  \"components.RequestBlock.seasons\": \"季数\",\n  \"components.RequestBlock.rootfolder\": \"根目录\",\n  \"components.RequestBlock.requestoverrides\": \"覆盖请求\",\n  \"components.RequestBlock.profilechanged\": \"质量设置\",\n  \"components.RegionSelector.regionServerDefault\": \"默认设置（{region}）\",\n  \"components.RegionSelector.regionDefault\": \"所有地区\",\n  \"components.QuotaSelector.unlimited\": \"无限\",\n  \"components.QuotaSelector.tvRequests\": \"{quotaLimit} <quotaUnits>{seasons} 每 {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.seasons\": \"季\",\n  \"components.QuotaSelector.movies\": \"部电影\",\n  \"components.QuotaSelector.movieRequests\": \"{quotaLimit} <quotaUnits>{movies} 每 {quotaDays} {days}</quotaUnits>\",\n  \"components.QuotaSelector.days\": \"天\",\n  \"components.PersonDetails.lifespan\": \"{birthdate}－{deathdate}\",\n  \"components.PersonDetails.crewmember\": \"制作群成员\",\n  \"components.PersonDetails.birthdate\": \"{birthdate}－\",\n  \"components.PersonDetails.appearsin\": \"演出\",\n  \"components.PersonDetails.alsoknownas\": \"別名：{names}\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"授予查看其他用户提交的媒体请求的权限。\",\n  \"components.PermissionEdit.viewrequests\": \"查看请求\",\n  \"components.PermissionEdit.usersDescription\": \"授予管理用户的权限。 拥有此权限的用户无法修改具有管理员权限的用户或授予管理员权限。\",\n  \"components.PermissionEdit.users\": \"用户管理\",\n  \"components.PermissionEdit.requestTvDescription\": \"授予提交非 4K 电视剧请求的权限。\",\n  \"components.PermissionEdit.requestTv\": \"提交电视节目请求\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"授予提交非 4K 电影请求的权限。\",\n  \"components.PermissionEdit.requestMovies\": \"提交电影请求\",\n  \"components.PermissionEdit.requestDescription\": \"授予提交非 4K 媒体请求的权限。\",\n  \"components.PermissionEdit.request4kTvDescription\": \"授予提交 4K 电视剧请求的权限。\",\n  \"components.PermissionEdit.request4kTv\": \"提交 4K 电视节目请求\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"授予提交 4K 影片请求的权限。\",\n  \"components.PermissionEdit.request4kMovies\": \"提交 4K 电影请求\",\n  \"components.PermissionEdit.request4kDescription\": \"授予提交 4K 媒体请求的权限。\",\n  \"components.PermissionEdit.request4k\": \"提交 4K 请求\",\n  \"components.PermissionEdit.request\": \"提交请求\",\n  \"components.PermissionEdit.managerequestsDescription\": \"授予管理媒体请求的权限。 拥有此权限的用户提出的所有请求都将被自动批准。\",\n  \"components.PermissionEdit.managerequests\": \"请求管理\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"电子邮件通知设置保存成功！\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"电子邮件通知设置保存失败。\",\n  \"components.Settings.Notifications.emailsender\": \"发件人电子邮件地址\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord 通知设置保存成功！\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discord 通知设置保存失败。\",\n  \"components.Settings.Notifications.chatIdTip\": \"先与你的机器人建立一个聊天室以及把 <GetIdBotLink>@get_id_bot</GetIdBotLink> 也加到聊天室，然后在聊天室里发出 <code>/my_id</code> 命令\",\n  \"components.Settings.Notifications.chatId\": \"聊天室 ID\",\n  \"components.Settings.Notifications.botUsernameTip\": \"允许用户也把机器人加到自己的聊天室以及设定自己的通知\",\n  \"components.Settings.Notifications.botUsername\": \"Bot 机器人名\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Bot 机器人頭像网址（URL）\",\n  \"components.Settings.Notifications.botApiTip\": \"建立一个 Seerr 专用的<CreateBotLink>机器人</CreateBotLink>\",\n  \"components.Settings.Notifications.botAPI\": \"Bot 机器人授权令牌\",\n  \"components.Settings.Notifications.authUser\": \"SMTP 用户\",\n  \"components.Settings.Notifications.authPass\": \"SMTP 密码\",\n  \"components.Settings.Notifications.allowselfsigned\": \"允许自签名证书\",\n  \"components.Settings.Notifications.agentenabled\": \"启用通知\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"网络钩子通知设置保存成功！\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"网络钩子通知设置保存失败。\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"网络钩子网址（URL）\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"请输入有效的网址\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"请选择通知类型\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"请输入有效的 JSON 有效负载\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"网络钩子测试通知已发送！\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"发送网络钩子测试通知中…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"网络钩子测试通知发送失败。\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"幫助\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON 有效负载重设为默认负载成功！\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"重置为默认\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON 有效负载\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"始終使用 STARTTLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"不使用加密\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"使用传输层安全标准（TLS）\",\n  \"components.Settings.Notifications.encryptionDefault\": \"盡可能使用 STARTTLS\",\n  \"components.Settings.Notifications.encryption\": \"加密方式\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"你确定删除此条评论吗？\",\n  \"components.IssueDetails.IssueComment.delete\": \"删除评论\",\n  \"components.IssueDetails.IssueComment.edit\": \"编辑评论\",\n  \"components.IssueDetails.IssueComment.postedby\": \"由 {username} 发布于 {relativeTime}\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"由 {username} 发布于 {relativeTime}（已编辑）\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"你必须输入一条消息\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"删除 Issue\",\n  \"components.IssueDetails.allseasons\": \"所有季数\",\n  \"components.IssueDetails.nocomments\": \"没有评论。\",\n  \"components.IssueDetails.openedby\": \"#{issueId} 由 {username} 报告于 {relativeTime}\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"更新问题状态时出了点问题。\",\n  \"components.IssueDetails.unknownissuetype\": \"未知\",\n  \"components.IssueDetails.IssueDescription.description\": \"描述\",\n  \"components.IssueDetails.IssueDescription.edit\": \"编辑描述\",\n  \"components.IssueDetails.closeissue\": \"关闭 Issue\",\n  \"components.IssueDetails.closeissueandcomment\": \"评论后关闭\",\n  \"components.IssueDetails.comments\": \"评论\",\n  \"components.IssueDetails.deleteissueconfirm\": \"你是否确实要删除此 issue？\",\n  \"components.IssueDetails.episode\": \"第 {episodeNumber} 集\",\n  \"components.IssueDetails.issuepagetitle\": \"问题\",\n  \"components.IssueDetails.lastupdated\": \"最后更新时间\",\n  \"components.IssueDetails.leavecomment\": \"评论\",\n  \"components.IssueDetails.openinarr\": \"在 {arr} 中打开\",\n  \"components.IssueDetails.problemseason\": \"有问题的季数\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"编辑问题描述时出了点问题。\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"删除问题时出了点问题。\",\n  \"components.IssueDetails.play4konplex\": \"在 {mediaServerName} 上播放 4K 版\",\n  \"components.IssueDetails.openin4karr\": \"在 4K {arr} 中打开\",\n  \"components.IssueDetails.playonplex\": \"在 {mediaServerName} 上播放\",\n  \"components.IssueDetails.problemepisode\": \"有问题的集数\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"Issue 描述编辑成功！\",\n  \"components.IssueDetails.toaststatusupdated\": \"Issue 状态更新成功！\",\n  \"components.IssueDetails.reopenissue\": \"重新打开 Issue\",\n  \"components.IssueDetails.allepisodes\": \"所有剧集\",\n  \"components.IssueDetails.issuetype\": \"类型\",\n  \"components.IssueDetails.deleteissue\": \"删除 Issue\",\n  \"components.IssueDetails.reopenissueandcomment\": \"评论后重新打开\",\n  \"components.IssueDetails.season\": \"第 {seasonNumber} 季\",\n  \"components.IssueDetails.toastissuedeleted\": \"Issue 删除成功！\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"第 {episodeNumber} 集\",\n  \"components.IssueDetails.commentplaceholder\": \"添加评论…\",\n  \"components.IssueList.IssueItem.issuestatus\": \"状态\",\n  \"components.IssueList.IssueItem.issuetype\": \"类型\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{date} by {user}\",\n  \"components.IssueList.IssueItem.problemepisode\": \"受影响的剧集\",\n  \"components.IssueList.IssueItem.episodes\": \"集数\",\n  \"components.IssueList.IssueItem.opened\": \"打开\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"开启通知\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify通知设置保存失败。\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify通知设置保存成功！\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify 测试通知发送失败。\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"Gotify测试通知发送中…\",\n  \"components.Settings.Notifications.enableMentions\": \"允许提及\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"每 {jobScheduleMinutes, plural, one {minute} other {{jobScheduleMinutes} minutes}}\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"应用 API 令牌\",\n  \"components.UserList.newplexsigninenabled\": \"<strong>允许新的 Plex 用户登录</strong> 设置目前已启用。还没有导入的Plex用户也能登录。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Pushover 通知设置保存失败。\",\n  \"components.NotificationTypeSelector.issuecomment\": \"问题评论\",\n  \"components.MovieDetails.streamingproviders\": \"当前可播放\",\n  \"components.Settings.RadarrModal.inCinemas\": \"已上映\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"从您的<PushbulletSettingsLink>账号设置</PushbulletSettingsLink>获取API令牌\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"数据目录\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"每 {jobScheduleHours, plural, one {hour} other {{jobScheduleHours} hours}}\",\n  \"components.Settings.tautulliSettings\": \"Tautulli 设置\",\n  \"components.Settings.tautulliSettingsDescription\": \"可选配置您的 Tautulli 服务器设置。Seerr 会从 Tautulli 获取您的 Plex 媒体观看历史数据。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord 用户ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Pushbullet 通知设置保存失败。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"您的<FindDiscordIdLink>Discord 用户 ID </FindDiscordIdLink>\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"未知\",\n  \"components.IssueList.IssueItem.viewissue\": \"查看问题\",\n  \"components.IssueList.issues\": \"问题\",\n  \"components.IssueList.showallissues\": \"查看所有问题\",\n  \"components.IssueList.sortAdded\": \"最新\",\n  \"components.IssueList.IssueItem.seasons\": \"季\",\n  \"components.IssueList.sortModified\": \"最后修改\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"所有集数\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"所有季数\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"提交问题\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"提交问题报告时出了点问题。\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"成功为 <strong>{title}</strong> 报告问题！\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"查看问题\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"请输入问题说明\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"请描述您遇到的问题？\",\n  \"components.IssueModal.issueAudio\": \"音频\",\n  \"components.IssueModal.issueOther\": \"其他\",\n  \"components.Layout.Sidebar.issues\": \"问题\",\n  \"components.ManageSlideOver.downloadstatus\": \"下载状态\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"清除数据\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"当用户报告问题时发送通知。\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"当问题重新开启时发送通知。\",\n  \"components.PermissionEdit.createissuesDescription\": \"授予报告媒体问题的权限。\",\n  \"components.PermissionEdit.manageissuesDescription\": \"授予管理媒体问题的权限。\",\n  \"components.RequestModal.requestmovies\": \"提出请求\",\n  \"components.RequestModal.requestseasons4k\": \"提出4K请求\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"作业编辑成功！\",\n  \"i18n.resolved\": \"已解决\",\n  \"components.NotificationTypeSelector.issuereopened\": \"问题重新开启\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"当您报告的问题解决时获取通知。\",\n  \"components.ManageSlideOver.alltime\": \"历史\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"高级\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"* 这将会删除所有和{mediaType}相关的数据和所有请求。如果{mediaType}在您的{mediaServerName}服务器存在，数据将会在媒体库扫描时重新建立。\",\n  \"components.ManageSlideOver.manageModalIssues\": \"未解决问题\",\n  \"components.ManageSlideOver.manageModalMedia\": \"媒体\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K 媒体\",\n  \"components.ManageSlideOver.manageModalRequests\": \"请求\",\n  \"components.ManageSlideOver.manageModalTitle\": \"管理{mediaType}\",\n  \"components.ManageSlideOver.markavailable\": \"标记为可观看\",\n  \"components.ManageSlideOver.mark4kavailable\": \"标记4K版本可观看\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"标记所有季的4K版本可观看\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"标记所有季可观看\",\n  \"components.ManageSlideOver.opentautulli\": \"在 Tautulli 中查看\",\n  \"components.ManageSlideOver.pastdays\": \"过去 {days, number} 天\",\n  \"components.ManageSlideOver.playedby\": \"观看者\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> 次\",\n  \"components.MovieDetails.productioncountries\": \"出品国家\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"当其他用户评论时可以获取通知。\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"当其他用户重新开启问题时获取通知。\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"当其他用户解决问题时获取通知。\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"当问题有新评论时发送通知。\",\n  \"components.NotificationTypeSelector.issuecreated\": \"问题报告\",\n  \"components.NotificationTypeSelector.issueresolved\": \"问题解决\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"当问题解决时发送通知。\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"当您报告的问题有新评论时获取通知。\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"当其他用户报告问题时获取通知。\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"当您报告的问题重新开启时获取通知。\",\n  \"components.PermissionEdit.createissues\": \"报告问题\",\n  \"components.PermissionEdit.viewissues\": \"查看问题\",\n  \"components.PermissionEdit.viewissuesDescription\": \"授予查看其他用户报告的媒体问题的权限。\",\n  \"components.RequestModal.selectmovies\": \"请选择电影\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify 测试通知已发送！\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"应用令牌\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"服务器地址\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"请输入应用令牌\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"请选择通知类型\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"请输入有效的网址\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"请删除网址结尾斜杠\",\n  \"components.Settings.urlBase\": \"网站根路径\",\n  \"components.Settings.validationApiKey\": \"请输入API key\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"您 30 个字符的<UsersGroupsLink>用户或群组ID</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"频道标签\",\n  \"components.Settings.RadarrModal.announced\": \"已公布\",\n  \"components.Settings.RadarrModal.released\": \"已发布\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"新频率\",\n  \"components.Settings.externalUrl\": \"外部网址\",\n  \"components.Settings.tautulliApiKey\": \"应用程序密钥\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"保存 Tautulli 设置时出了点问题。\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli 设置保存成功！\",\n  \"components.Settings.validationUrlTrailingSlash\": \"请删除结尾斜杠\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"请添加前置斜杠\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"请删除结尾斜杠\",\n  \"components.TvDetails.productioncountries\": \"出品国家\",\n  \"components.TvDetails.streamingproviders\": \"当前可播放\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"API 令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet 通知设置保存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"建立一个 {applicationTitle} 专用的 <ApplicationRegistrationLink>应用</ApplicationRegistrationLink>\",\n  \"components.UserProfile.recentlywatched\": \"最近观看\",\n  \"components.IssueModal.issueSubtitles\": \"字幕\",\n  \"components.IssueModal.issueVideo\": \"视频\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"没有请求。\",\n  \"i18n.open\": \"未解决\",\n  \"components.PermissionEdit.manageissues\": \"管理问题\",\n  \"components.RequestModal.approve\": \"批准请求\",\n  \"components.RequestModal.requestApproved\": \"<strong>{title}</strong> 的请求已被批准！\",\n  \"components.RequestModal.requestmovies4k\": \"提出4K请求\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"特辑\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"有问题的集数\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"有问题的季数\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"请详细描述您遇到的问题。\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"报告问题\",\n  \"components.IssueModal.CreateIssueModal.season\": \"第 {seasonNumber} 季\",\n  \"components.ManageSlideOver.openarr\": \"打开{arr}服务器\",\n  \"components.ManageSlideOver.openarr4k\": \"打开4K {arr} 服务器\",\n  \"components.ManageSlideOver.tvshow\": \"个剧集\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"请输入有效的 API 令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"请输入 API 令牌\",\n  \"components.ManageSlideOver.movie\": \"部电影\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"您正在使用 Seerr 的 <code>develop</code> 开发板。我们只建议开发者和协助测试的人员使用。\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"编辑作业\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"保存作业设置时出了点问题。\",\n  \"components.Settings.validationUrl\": \"请输入有效的网址\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"请输入有效的 Discord 用户 ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"用户或群组令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover 通知设置保存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"请输入有效的用户或群组令牌\",\n  \"i18n.import\": \"导入\",\n  \"i18n.importing\": \"导入中…\",\n  \"components.RequestBlock.languageprofile\": \"语言配置文件\",\n  \"components.TitleCard.mediaerror\": \"未找到{mediaType}\",\n  \"components.MovieDetails.digitalrelease\": \"数字发行\",\n  \"components.MovieDetails.physicalrelease\": \"物理释放\",\n  \"components.MovieDetails.theatricalrelease\": \"剧场版\",\n  \"components.PermissionEdit.viewrecent\": \"查看最近添加的内容\",\n  \"components.PermissionEdit.viewrecentDescription\": \"授予查看最近添加的媒体列表的权限。\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} 已更新\",\n  \"components.StatusChecker.restartRequired\": \"需要重启服务器\",\n  \"components.StatusChecker.appUpdatedDescription\": \"请点击下面的按钮，重新加载应用程序。\",\n  \"components.StatusChecker.reloadApp\": \"重新加载 {applicationTitle}\",\n  \"i18n.restartRequired\": \"需要重新启动\",\n  \"components.Settings.deleteServer\": \"删除 {serverType} 服务器\",\n  \"components.StatusChecker.restartRequiredDescription\": \"请重新启动服务器以应用更新的设置。\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex 关注列表\",\n  \"components.MovieDetails.managemovie\": \"管理电影\",\n  \"components.MovieDetails.reportissue\": \"报告问题\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"自动提交的请求\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"授权查看其他用户的Plex关注列表。\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.Settings.advancedTooltip\": \"错误配置此设置可能会导致功能不可用\",\n  \"components.Settings.experimentalTooltip\": \"启用此设置可能会导致意外的应用程序行为\",\n  \"components.TvDetails.reportissue\": \"报告问题\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"查看详情\",\n  \"components.Layout.UserDropdown.requests\": \"请求\",\n  \"components.Settings.restartrequiredTooltip\": \"需重启 Seerr 服务才能使此设置生效\",\n  \"components.TvDetails.manageseries\": \"管理电视节目\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"自动请求您的 <PlexWatchlistSupportLink>Plex 关注列表</PlexWatchlistSupportLink>的媒体\",\n  \"components.AirDateBadge.airedrelative\": \"{relativeTime}播出\",\n  \"components.AirDateBadge.airsrelative\": \"{relativeTime}播出\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"电影请求\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"电视节目请求\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"当 Plex 关注列表中的项目自动提交新媒体请求时，会收到通知。\",\n  \"components.PermissionEdit.viewwatchlists\": \"查看 Plex 关注列表\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"在检索季元数据时出了问题。\",\n  \"components.UserProfile.plexwatchlist\": \"Plex 关注列表\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"当前频率\",\n  \"components.StatusBadge.playonplex\": \"在 Plex 上观看\",\n  \"components.TitleCard.cleardata\": \"清除数据\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"您的 Plex 关注列表\",\n  \"components.Discover.plexwatchlist\": \"您的 Plex 关注列表\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"授予自动请求 Plex 关注列表中的非 4K 电视节目的权限。\",\n  \"components.PermissionEdit.autorequest\": \"自动请求\",\n  \"components.PermissionEdit.autorequestDescription\": \"授予自动请求 Plex 关注列表中的非 4K 媒体的权限。\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount} 集\",\n  \"components.MovieDetails.rtcriticsscore\": \"烂番茄专业评分\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB 用户评分\",\n  \"components.RequestBlock.approve\": \"批准请求\",\n  \"components.RequestBlock.lastmodifiedby\": \"最后修改者\",\n  \"components.MovieDetails.rtaudiencescore\": \"烂番茄观众评分\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"电视节目自动请求\",\n  \"components.TvDetails.rtaudiencescore\": \"烂番茄观众评分\",\n  \"components.TvDetails.rtcriticsscore\": \"烂番茄专业评分\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB 用户评分\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"同步 Plex 关注列表\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"自动请求您的 <PlexWatchlistSupportLink>Plex 关注列表</PlexWatchlistSupportLink> 中的电影\",\n  \"components.PermissionEdit.autorequestSeries\": \"电视节目自动请求\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"授予自动请求 Plex 关注列表中的非 4K 电影的权限。\",\n  \"components.PermissionEdit.autorequestMovies\": \"电影自动请求\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"电影自动请求\",\n  \"components.RequestBlock.decline\": \"拒绝请求\",\n  \"components.RequestModal.requestcollection4ktitle\": \"提交 4K 系列请求\",\n  \"components.RequestModal.requestmovie4ktitle\": \"提交 4K 电影请求\",\n  \"components.RequestModal.requestmovietitle\": \"提交电影请求\",\n  \"components.RequestModal.requestseriestitle\": \"提交电视节目请求\",\n  \"components.RequestBlock.edit\": \"编辑请求\",\n  \"components.RequestModal.requestseries4ktitle\": \"提交 4K 电视节目请求\",\n  \"components.RequestBlock.delete\": \"删除请求\",\n  \"components.RequestBlock.requestdate\": \"请求日期\",\n  \"components.RequestBlock.requestedby\": \"请求者\",\n  \"components.RequestCard.approverequest\": \"批准请求\",\n  \"components.RequestModal.requestcollectiontitle\": \"提交系列请求\",\n  \"components.TvDetails.Season.noepisodes\": \"剧集列表不可用。\",\n  \"components.StatusBadge.managemedia\": \"管理{mediaType}\",\n  \"components.StatusBadge.openinarr\": \"在 {arr} 中打开\",\n  \"components.TvDetails.status4k\": \"4K 版{status}\",\n  \"components.UserProfile.emptywatchlist\": \"您的 <PlexWatchlistSupportLink>Plex 关注列表</PlexWatchlistSupportLink>中的媒体会显示在这里。\",\n  \"components.TvDetails.seasonnumber\": \"第 {seasonNumber} 季\",\n  \"components.TvDetails.seasonstitle\": \"季数\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"找不到此电视节目的数据。\",\n  \"components.Discover.emptywatchlist\": \"您的 <PlexWatchlistSupportLink>Plex 关注列表</PlexWatchlistSupportLink>中的媒体会显示在这里。\",\n  \"components.RequestCard.cancelrequest\": \"取消请求\",\n  \"components.RequestCard.declinerequest\": \"拒绝请求\",\n  \"components.RequestCard.editrequest\": \"编辑请求\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"已缓存图片\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"清理图片缓存\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"当此功能在设置中启用时，Seerr 将代理并缓存预配置的外部来源中的图像。缓存的图片保存于你的配置文件夹中，你可以在 <code>{appDataPath}/cache/images</code> 目录下找到这些文件。\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"图片缓存\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"缓存总大小\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"您的 Plex 关注列表\",\n  \"components.Discover.moviegenres\": \"电影类型\",\n  \"components.Discover.networks\": \"流媒体平台\",\n  \"components.Discover.studios\": \"制作公司\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} 电影\",\n  \"components.Settings.SettingsMain.apikey\": \"应用程序密钥\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"应用程序标题\",\n  \"components.Settings.SettingsMain.applicationurl\": \"应用程序网址\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"缓存外部来源中的图像，这将需要大量的磁盘空间\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"为 Seerr 配置全局和默认设置。\",\n  \"components.Settings.SettingsMain.generalsettings\": \"常规设置\",\n  \"components.Settings.SettingsMain.general\": \"常规\",\n  \"components.Settings.SettingsMain.locale\": \"显示语言\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"隐藏可观看的电影和电视节目\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"生成新的用户程序密钥中出了点问题。\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"保存设置中出了点问题。\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"已成功生成新的应用程序密钥！\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"成功保存设置！\",\n  \"components.Discover.CreateSlider.nooptions\": \"没有结果。\",\n  \"components.Discover.DiscoverTv.discovertv\": \"电视节目\",\n  \"components.Settings.SettingsMain.cacheImages\": \"启用图片缓存\",\n  \"components.Discover.FilterSlideover.keywords\": \"关键词\",\n  \"components.Discover.FilterSlideover.from\": \"从\",\n  \"components.Discover.FilterSlideover.to\": \"到\",\n  \"components.Selector.searchKeywords\": \"搜索关键词…\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"上映日期\",\n  \"components.Selector.showmore\": \"显示更多\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} 分钟时长\",\n  \"components.Discover.CreateSlider.searchStudios\": \"搜索制作公司…\",\n  \"components.Selector.searchStudios\": \"搜索制作公司…\",\n  \"components.Discover.FilterSlideover.studio\": \"制作公司\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"原始语言\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"流媒体平台\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB 用户评分\",\n  \"components.Discover.FilterSlideover.runtime\": \"时长\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"清除使用中的筛选项\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"电影\",\n  \"components.Discover.FilterSlideover.ratingText\": \"评分从 {minValue} 到 {maxValue}\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"搜索关键词…\",\n  \"components.Selector.nooptions\": \"没有结果。\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"人气递增\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB 评分递增\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB 评分递减\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"人气递增\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB 评分递增\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"标题 (A-Z) 递增\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"人气递减\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"上映日期递增\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"上映日期递减\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"人气递减\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"标题 (Z-A) 递减\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"允许部分剧集请求\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"标题 (Z-A) 递减\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB 评分递减\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"标题 (A-Z) 递增\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"必须删除结尾斜线\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"请输入有效的网址\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"首次播出日期\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"首次播出日期递增\",\n  \"components.Discover.tvgenres\": \"电视节目类型\",\n  \"components.Selector.searchGenres\": \"选择类型…\",\n  \"components.Discover.FilterSlideover.filters\": \"筛选项\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"首次播出日期递减\",\n  \"components.Discover.FilterSlideover.genres\": \"类型\",\n  \"components.Discover.CreateSlider.searchGenres\": \"搜索类型…\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"您的 <PlexWatchlistSupportLink>Plex 关注列表</PlexWatchlistSupportLink>中的媒体会显示在这里。\",\n  \"components.Selector.starttyping\": \"开始打字以进行搜索。\",\n  \"components.Discover.CreateSlider.starttyping\": \"开始打字以进行搜索。\",\n  \"components.Discover.CreateSlider.needresults\": \"你需要至少有 1 个结果。\",\n  \"components.Selector.showless\": \"显示更少\",\n  \"components.Discover.resetfailed\": \"重置探索媒体设置时出了点问题。\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"你必须提供一个应用程序标题\",\n  \"components.Discover.updatefailed\": \"更新探索媒体设置时出了点问题。\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"以原始语言筛选结果\",\n  \"components.Settings.SettingsMain.originallanguage\": \"探索语言\",\n  \"components.Discover.tmdbnetwork\": \"TMDB 平台\",\n  \"components.Discover.tmdbsearch\": \"TMDB 搜索\",\n  \"components.Discover.tmdbstudio\": \"TMDB 制作公司\",\n  \"components.Discover.CreateSlider.editfail\": \"编辑滑块失败。\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"你必须提供滑动框的名称。\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"成功删除滑动框。\",\n  \"components.Discover.resettodefault\": \"重置为默认\",\n  \"components.Discover.stopediting\": \"退出编辑\",\n  \"components.Discover.resetwarning\": \"将所有滑动框重置为默认。这也将删除所有自定义滑动框！\",\n  \"components.Discover.CreateSlider.editSlider\": \"编辑滑块\",\n  \"components.Discover.CreateSlider.addSlider\": \"添加滑动框\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"创建自定义滑块\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"删除滑动框失败。\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"移除\",\n  \"components.Discover.CreateSlider.addfail\": \"创建新滑块失败。\",\n  \"components.Discover.CreateSlider.addsuccess\": \"已创建新滑块并保存探索页面的自定义设置。\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB 电影类型\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB 电视节目类型\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB 电视节目关键词\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"提供一个 TMDB 类型 ID\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"提供一个TMDB 关键词 ID\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# 个使用中的筛选项} other {# 个使用中的筛选项}}\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"切换可见性\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# 个使用中的筛选项} other {# 个使用中的筛选项}}\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle}电视节目\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# 个使用中的筛选项} other {# 个使用中的筛选项}}\",\n  \"components.Discover.updatesuccess\": \"已更新探索自定义设置。\",\n  \"components.RequestCard.unknowntitle\": \"未知标题\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"未知标题\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: 第 {seasonNumber} 季 第 {episodeNumber} 集\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"提供一个搜索内容\",\n  \"components.Discover.customizediscover\": \"自定义探索\",\n  \"components.Discover.createnewslider\": \"创建新的滑动框\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB 电影关键词\",\n  \"components.Discover.CreateSlider.editsuccess\": \"已编辑滑块并保存探索页面的自定义设置。\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"你必须提供一个供搜索的内容。\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"提供 TMDB 制作公司 ID\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"请提供 TMDB 网络 ID\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"滑动框名称\",\n  \"components.Discover.resetsuccess\": \"成功重置探索自定义设置。\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"同步媒体可用性\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB 电影流媒体服务\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB 电视流媒体服务\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"每 {jobScheduleSeconds, plural, one {second} other {{jobScheduleSeconds} seconds}}\",\n  \"components.Discover.FilterSlideover.voteCount\": \"在 {minValue} 和 {maxValue} 之间的评分数\",\n  \"components.Settings.RadarrModal.tagRequests\": \"标签请求\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"自动添加带有请求者的用户 ID 和显示名称的附加标签\",\n  \"components.Settings.SonarrModal.tagRequests\": \"标记请求\",\n  \"i18n.collection\": \"合集\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB 用户评分数\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"自动添加带有请求者的用户 ID 和显示名称的附加标签\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"需要输入密码。\",\n  \"components.Login.emailtooltip\": \"地址不需要与{mediaServerName}实例相关联。\",\n  \"components.Login.initialsignin\": \"连接\",\n  \"components.Login.initialsigningin\": \"连接中……\",\n  \"components.Login.save\": \"添加\",\n  \"components.Login.saving\": \"添加中……\",\n  \"components.Login.signinwithjellyfin\": \"使用您的{mediaServerName}帐户\",\n  \"components.Login.title\": \"添加邮件\",\n  \"components.Login.username\": \"用户名\",\n  \"components.Login.validationEmailFormat\": \"无效的邮件地址\",\n  \"components.Login.validationEmailRequired\": \"你必须提供一个电子邮件\",\n  \"components.Login.validationemailformat\": \"需要有效的电子邮件\",\n  \"components.Login.validationhostformat\": \"需要有效的URL\",\n  \"components.Login.validationusernamerequired\": \"需要用户名\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"* 这将不可逆地从{arr}中删除{mediaType}，包括所有文件。\",\n  \"components.ManageSlideOver.removearr4k\": \"移除4K {arr}\",\n  \"components.MovieDetails.downloadstatus\": \"下载状态\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB用户评分\",\n  \"components.MovieDetails.openradarr\": \"在Radarr中打开电影\",\n  \"components.MovieDetails.play\": \"播放{mediaServerName}\",\n  \"components.MovieDetails.play4k\": \"播放 4K {mediaServerName}\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"通知声音\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"Jellyfin全库扫描\",\n  \"components.Settings.SonarrModal.seriesType\": \"系列类型\",\n  \"components.Settings.jellyfinSettingsFailure\": \"保存{mediaServerName}设置时出错。\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"{mediaServerName}设置保存成功!\",\n  \"components.Settings.jellyfinlibraries\": \"{mediaServerName}库\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"库{mediaServerName}用于扫描标题。如果没有列出库，请单击下面的按钮。\",\n  \"components.Settings.jellyfinsettings\": \"{mediaServerName}设置\",\n  \"components.Settings.manualscanJellyfin\": \"手动扫描库\",\n  \"components.Settings.menuJellyfinSettings\": \"{mediaServerName}\",\n  \"components.Settings.saving\": \"保存中……\",\n  \"components.Settings.syncJellyfin\": \"同步库\",\n  \"components.Settings.syncing\": \"同步中\",\n  \"components.Settings.timeout\": \"超时\",\n  \"components.Setup.signin\": \"登录\",\n  \"components.Setup.signinWithJellyfin\": \"输入您的 Jellyfin 详细信息\",\n  \"components.TitleCard.addToWatchList\": \"添加到监视列表\",\n  \"components.TitleCard.watchlistDeleted\": \"<strong>{title}</strong>从监视列表中删除成功!\",\n  \"components.TitleCard.watchlistError\": \"出现错误，请重试。\",\n  \"components.TvDetails.play\": \"在 {mediaServerName} 播放\",\n  \"components.TvDetails.play4k\": \"mediaServerName} 播放 4K\",\n  \"components.UserList.importfrommediaserver\": \"导入{mediaServerName}用户\",\n  \"components.UserList.mediaServerUser\": \"{mediaServerName} 用户\",\n  \"components.UserList.noJellyfinuserstoimport\": \"在{mediaServerName}中没有用户要导入。\",\n  \"components.UserList.newJellyfinsigninenabled\": \"<strong>启用 {mediaServerName} 登录</strong> 设置当前已启用. {mediaServerName} 具有库访问权限的用户不需要导入即可登录。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"{mediaServerName} 用户\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"设备默认\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"邮件地址无效。\",\n  \"components.Layout.UserWarnings.emailRequired\": \"需要填写电子邮件地址。\",\n  \"components.Login.credentialerror\": \"用户名或密码错误。\",\n  \"components.Login.description\": \"由于这是您第一次登录{applicationName}，您需要添加一个有效的电子邮件地址。\",\n  \"components.Login.validationhostrequired\": \"{mediaServerName} URL是必需的\",\n  \"components.ManageSlideOver.removearr\": \"从{arr}中删除\",\n  \"components.MovieDetails.openradarr4k\": \"在 4K Radarr 中打开电影\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"设备默认\",\n  \"components.Settings.Notifications.userEmailRequired\": \"获取用户邮箱\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"Jellyfin最近新增扫描\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"动漫系列\",\n  \"components.Settings.jellyfinSettings\": \"{mediaServerName}设置\",\n  \"components.Settings.jellyfinSettingsDescription\": \"可以为您的{mediaServerName}服务器配置内部和外部端点。在大多数情况下，外部URL与内部URL是不同的。如果你想重定向到不同的密码重置页面，也可以为{mediaServerName}登录设置自定义密码重置URL。你也可以修改之前自动生成的Jellyfin API密钥。\",\n  \"components.Settings.jellyfinsettingsDescription\": \"配置{mediaServerName}服务器的设置。{mediaServerName}扫描{mediaServerName}库以查看可用的内容。\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"正常情况下，每24小时只会运行一次。Seerr将更积极地检查您的{mediaServerName}服务器最近添加的内容。如果这是您第一次配置Seerr，建议您手动进行一次完整的库扫描!\",\n  \"components.Settings.save\": \"保存更改\",\n  \"components.Setup.configuremediaserver\": \"配置媒体服务器\",\n  \"components.Setup.signinWithPlex\": \"输入您的 Plex 详细信息\",\n  \"components.TitleCard.watchlistCancel\": \"<strong>{title}</strong>的监视列表已取消。\",\n  \"components.TitleCard.watchlistSuccess\": \"<strong>{title}</strong>添加到监视列表成功!\",\n  \"components.UserList.importfromJellyfin\": \"导入{mediaServerName}用户\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"电子邮件\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"保存更改\",\n  \"components.UserList.importfromJellyfinerror\": \"导入{mediaServerName}用户时出错。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"通知声音\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"保存中……\",\n  \"components.UserProfile.localWatchlist\": \"{username}的监视列表\",\n  \"components.UserList.importedfromJellyfin\": \"<strong>{userCount}</strong> {mediaServerName} {userCount, plural, one {user} other {users}} 导入成功!\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"代理绕过本地地址\",\n  \"components.MovieDetails.addtowatchlist\": \"加入监视列表\",\n  \"components.MovieDetails.watchlistError\": \"出了点问题，请重试。\",\n  \"components.Login.invalidurlerror\": \"无法连接到 {mediaServerName} 服务器。\",\n  \"components.Login.enablessl\": \"使用 SSL\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"基础 URL 末尾不得包含斜杠\",\n  \"components.Login.noadminerror\": \"没有在服务器上找到管理员账户。\",\n  \"components.Login.port\": \"端口\",\n  \"components.Login.validationPortRequired\": \"您必须提供一个有效的端口号\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"基础 URL 开头必须包含斜杠\",\n  \"components.Login.validationUrlTrailingSlash\": \"URL不能以斜杠结尾\",\n  \"components.MovieDetails.removefromwatchlist\": \"从监视列表中移除\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"启用 CSRF 保护\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"探索地区\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"允许特别剧集请求\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"HTTP(S) 代理\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"代理主机名\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"代理密码\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"代理端口\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"使用 SSL 进行代理\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"代理用户名\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"启用代理支持\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"您必须提供有效端口\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"登录方式\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"允许 {mediaServerName} 登录\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"网络设置\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"线程/话题ID必须为正的整数\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"指定应用参数更改前的条件。每个字段必须经过验证才能应用（和操作）规则。如果字段的任何属性（或操作）匹配，则认为该字段已验证。\",\n  \"components.Settings.OverrideRuleModal.genres\": \"类型\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"覆盖规则创建成功！\",\n  \"components.TvDetails.watchlistDeleted\": \"<strong>{title}</strong>从监视列表中删除成功！\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"输入您的{mediaServerName}凭据以将您的帐户与{applicationName}链接。\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"关联账户\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"即将播出的电视剧\",\n  \"components.Login.adminerror\": \"您必须使用管理员帐户登录。\",\n  \"components.Selector.canceled\": \"已取消\",\n  \"components.Settings.addrule\": \"新的覆盖规则\",\n  \"components.Setup.signinWithEmby\": \"输入您的Emby详细信息\",\n  \"components.TvDetails.addtowatchlist\": \"添加到监控列表\",\n  \"components.UserList.validationUsername\": \"你必须提供一个用户名\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"流媒体区域\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"如果您的群聊启用了主题，您可以在这里指定线程/主题的ID\",\n  \"components.Discover.FilterSlideover.status\": \"状态\",\n  \"components.Login.back\": \"返回\",\n  \"components.RequestList.RequestItem.removearr\": \"从{arr}中删除\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"指定当满足上述条件时将更改哪些设置。\",\n  \"components.RequestList.sortDirection\": \"切换排序方向\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"要在webhook消息中提及的角色ID。留空以禁用提及\",\n  \"components.UserList.username\": \"用户名\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"这个邮箱已经被使用了！\",\n  \"components.Settings.invalidurlerror\": \"无法连接到{mediaServerName}服务器。\",\n  \"components.Settings.scanbackground\": \"扫描将在后台运行。在此期间，您可以继续安装过程。\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"这个帐户已经链接到一个{applicationName}用户\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"这些外部帐户与您的{applicationName}帐户相关联。\",\n  \"components.Selector.returningSeries\": \"回归剧集\",\n  \"components.Login.hostname\": \"{mediaServerName} URL\",\n  \"components.Login.loginwithapp\": \"使用{appName}登录\",\n  \"components.Login.orsigninwith\": \"或者登录\",\n  \"components.Login.servertype\": \"服务器类型\",\n  \"components.Login.validationservertyperequired\": \"请选择服务器类型\",\n  \"components.Login.urlBase\": \"基础 URL\",\n  \"components.MovieDetails.watchlistDeleted\": \"<strong>{title}</strong>从监视列表中删除成功！\",\n  \"components.MovieDetails.watchlistSuccess\": \"<strong>{title}</strong>添加到监视列表成功！\",\n  \"components.RequestList.RequestItem.profileName\": \"配置方案\",\n  \"components.Selector.ended\": \"已结束\",\n  \"components.Selector.inProduction\": \"在生产中\",\n  \"components.Selector.pilot\": \"试播节目\",\n  \"components.Selector.planned\": \"计划中\",\n  \"components.Selector.searchStatus\": \"选择状态…\",\n  \"components.Selector.searchUsers\": \"选择用户…\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"如果您的群聊启用了主题，您可以在这里指定线程/主题的ID\",\n  \"components.Settings.Notifications.messageThreadId\": \"主题/帖子 ID\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"您必须提供一个有效的Discord角色ID\",\n  \"components.Settings.Notifications.webhookRoleId\": \"通知角色ID\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"条件\",\n  \"components.Settings.OverrideRuleModal.create\": \"创建规则\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"新覆盖规则\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"编辑覆盖规则\",\n  \"components.Settings.OverrideRuleTile.tags\": \"标签\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"关键字\",\n  \"components.Settings.OverrideRuleModal.languages\": \"语言\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"没有标签。\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"质量概况\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"根目录\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"覆盖规则更新成功！\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"选择根目录\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"选择标签\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"将此规则应用于所选服务。\",\n  \"components.Settings.OverrideRuleModal.settings\": \"设置\",\n  \"components.Settings.OverrideRuleModal.tags\": \"标签\",\n  \"components.Settings.OverrideRuleModal.users\": \"用户\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"条件\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"关键字\",\n  \"components.Settings.OverrideRuleTile.language\": \"语言\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"质量档案\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"根目录\",\n  \"components.Settings.OverrideRuleTile.settings\": \"设置\",\n  \"components.Settings.OverrideRuleTile.users\": \"用户\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"选择服务\",\n  \"components.Settings.OverrideRuleModal.service\": \"服务\",\n  \"components.Settings.OverrideRuleTile.genre\": \"类型\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"选择画质配置\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"用户头像\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"Plex 刷新令牌\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"根据区域可用性过滤内容\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"按地区可用性显示流媒体网站\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"不要启用这个设置，除非你明白你在做什么！\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"流媒体区域\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"将外部API访问设置为只读（需要HTTPS）\",\n  \"components.Settings.SettingsNetwork.docs\": \"文档\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"强制IPv4优先解析\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"强制Jellyseerr首先解析IPv4地址，而不是IPv6地址\",\n  \"components.Settings.SettingsNetwork.network\": \"网络\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"应该使用来自容器/系统的网络参数，而不是这些设置。有关更多信息，请参阅{docs}。\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"为您的Jellyseerr实例配置网络设置。\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"忽略的代理地址\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"使用“,”和“*”作为分隔符。“*”作为子域的通配符\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"在保存设置时出错了。\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"设置保存成功！\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"允许Jellyseerr在代理后正确地注册客户端IP地址\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"必须选择至少一种身份验证方法。\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"配置用户登录方式。\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"允许用户使用他们的{mediaServerName}帐户登录\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"忘记密码URL\",\n  \"components.Settings.apiKey\": \"API 密钥\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"同步库时出错了\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"没有找到库\",\n  \"components.Settings.menuNetwork\": \"网络\",\n  \"components.Settings.overrideRules\": \"覆盖规则\",\n  \"components.Settings.overrideRulesDescription\": \"覆盖规则允许您指定在请求与规则匹配时将被替换的属性。\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"不支持同时使用自定义认证和自动媒体库分组功能\",\n  \"components.Settings.tip\": \"提示\",\n  \"components.Setup.configemby\": \"配置Emby\",\n  \"components.Setup.configjellyfin\": \"配置Jellyfin\",\n  \"components.Setup.configplex\": \"配置Plex\",\n  \"components.Setup.librarieserror\": \"验证失败。请再次切换库以继续。\",\n  \"components.Setup.servertype\": \"选择服务器类型\",\n  \"components.Setup.subtitle\": \"首先选择您的媒体服务器\",\n  \"components.Setup.back\": \"返回\",\n  \"components.StatusBadge.seasonnumber\": \"第 {seasonNumber} 季\",\n  \"components.TvDetails.removefromwatchlist\": \"从监视列表中删除\",\n  \"components.TvDetails.watchlistError\": \"发生了一些错误。请再试一次。\",\n  \"components.TvDetails.watchlistSuccess\": \"<strong>{title}</strong>添加到监视列表成功！\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"无法使用您的凭据连接到{mediaServerName}\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"发生未知错误\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"密码\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"你必须提供一个密码\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"链接\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"添加中…\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"链接{mediaServerName}帐户\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"用户名\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"你必须提供一个用户名\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"发现区域\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"根据区域可用性筛选内容\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"按地区可用性显示流媒体网站\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"该用户名已被其他用户使用，你必须设置一个邮箱\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"需要有效的邮箱\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"需要邮箱\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"发生未知错误\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"关联账户\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"您的账号没有绑定任何外部账号。\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"您没有权限修改此用户的关联帐户。\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"无法删除关联帐户。\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"此帐户已关联到一个Plex用户\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"无法使用您的凭证连接Plex\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"线程/主题 ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"线程/主题ID必须是正的整数\",\n  \"i18n.specials\": \"特别篇\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"排除关键词\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"问题描述\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"选择元数据提供商\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"证书加载失败\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"选择国家/地区\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"\",\n  \"i18n.completed\": \"\",\n  \"i18n.deleted\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\",\n  \"component.BlocklistBlock.blocklistdate\": \"封锁日期\",\n  \"component.BlocklistBlock.blocklistedby\": \"封锁者\",\n  \"component.BlocklistModal.blocklisting\": \"封锁清單\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> 不在封锁清單\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"管理已封锁媒体\",\n  \"components.Blocklist.blocklistdate\": \"日期\",\n  \"components.Blocklist.blocklistedby\": \"{date} 由 {user} 封锁\",\n  \"components.Blocklist.blocklistsettings\": \"封锁清单设置\",\n  \"components.Blocklist.filterManual\": \"手动\",\n  \"components.Blocklist.mediaType\": \"类型\",\n  \"components.Blocklist.showAllBlocklisted\": \"显示所有被屏蔽的媒体\",\n  \"components.Discover.RecentRequestsSlider.unableToConnect\": \"无法连接到 {services}，部分信息可能不可用。\",\n  \"components.Layout.Sidebar.blocklist\": \"黑名单\",\n  \"components.PermissionEdit.manageblocklist\": \"管理黑名单\",\n  \"components.PermissionEdit.manageblocklistDescription\": \"授予管理被屏蔽媒体的权限。\",\n  \"components.PermissionEdit.viewblocklistedItems\": \"查看被屏蔽的媒体。\",\n  \"components.PermissionEdit.viewblocklistedItemsDescription\": \"授予查看被屏蔽的媒体的权限。\",\n  \"components.RequestList.unableToConnect\": \"无法连接到 {services}，部分信息可能不可用。\",\n  \"components.Blocklist.filterBlocklistedTags\": \"被屏蔽的标签\",\n  \"i18n.removefromBlocklist\": \"从黑名单中移除\",\n  \"components.Settings.Notifications.NotificationsWebhook.customHeadersTip\": \"添加自定义 HTTP 标头以包含在 webhook 请求中\"\n}\n"
  },
  {
    "path": "src/i18n/locale/zh_Hant.json",
    "content": "{\n  \"components.Settings.Notifications.webhookUrl\": \"Webhook 網址\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrl\": \"Webhook 網址\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrl\": \"Webhook 網址\",\n  \"components.Settings.SonarrModal.apiKey\": \"應用程式密鑰\",\n  \"components.Settings.RadarrModal.apiKey\": \"應用程式密鑰\",\n  \"components.Settings.Notifications.senderName\": \"發件人名稱\",\n  \"components.Settings.Notifications.emailsender\": \"發件人電子郵件地址\",\n  \"components.Settings.Notifications.authUser\": \"SMTP 使用者\",\n  \"components.Settings.Notifications.authPass\": \"SMTP 密碼\",\n  \"components.Settings.Notifications.NotificationsWebhook.agentenabled\": \"啟用通知\",\n  \"components.Settings.Notifications.agentenabled\": \"啟用通知\",\n  \"components.Settings.Notifications.NotificationsSlack.agentenabled\": \"啟用通知\",\n  \"components.Settings.Notifications.NotificationsPushover.agentenabled\": \"啟用通知\",\n  \"components.Settings.Notifications.validationSmtpPortRequired\": \"請輸入有效的通訊埠\",\n  \"components.Settings.Notifications.validationSmtpHostRequired\": \"請輸入有效的主機名稱或 IP 位址\",\n  \"components.Settings.Notifications.smtpPort\": \"SMTP 通訊埠\",\n  \"components.Settings.Notifications.smtpHost\": \"SMTP 主機\",\n  \"i18n.partiallyavailable\": \"部分可觀看\",\n  \"i18n.unavailable\": \"不可觀看\",\n  \"components.StatusBadge.status4k\": \"4K 版{status}\",\n  \"components.Setup.welcome\": \"歡迎來到 Jellyseerr\",\n  \"components.TvDetails.TvCast.fullseriescast\": \"演員陣容\",\n  \"components.TvDetails.TvCrew.fullseriescrew\": \"製作群\",\n  \"components.TvDetails.originallanguage\": \"原始語言\",\n  \"components.TvDetails.network\": \"影視平台\",\n  \"components.TvDetails.recommendations\": \"推薦\",\n  \"i18n.pending\": \"待處理\",\n  \"i18n.failed\": \"失敗\",\n  \"i18n.close\": \"關閉\",\n  \"i18n.cancel\": \"取消\",\n  \"i18n.request\": \"提出請求\",\n  \"i18n.requested\": \"已經有請求\",\n  \"i18n.retry\": \"重試\",\n  \"pages.returnHome\": \"返回首頁\",\n  \"components.TvDetails.viewfullcrew\": \"檢視完整製作群\",\n  \"components.TvDetails.overview\": \"概要\",\n  \"components.Settings.SettingsAbout.Releases.viewongithub\": \"在 GitHub 上查看\",\n  \"components.Settings.SettingsAbout.Releases.viewchangelog\": \"查看變更日誌\",\n  \"components.UserList.validationpasswordminchars\": \"密碼必須至少包含八個字符\",\n  \"components.UserList.userlist\": \"使用者清單\",\n  \"components.Setup.finish\": \"完成設定\",\n  \"components.Setup.continue\": \"繼續\",\n  \"components.Setup.configureservices\": \"設定伺服器\",\n  \"components.Settings.sonarrsettings\": \"Sonarr 設定\",\n  \"components.Settings.radarrsettings\": \"Radarr 設定\",\n  \"components.Settings.menuPlexSettings\": \"Plex\",\n  \"components.UserList.importfromplexerror\": \"匯入 Plex 使用者時出了點問題。\",\n  \"components.UserList.importfromplex\": \"匯入 Plex 使用者\",\n  \"components.UserList.importedfromplex\": \"匯入 <strong>{userCount}</strong> 個 Plex 使用者成功！\",\n  \"components.UserList.localuser\": \"本地使用者\",\n  \"components.UserList.creating\": \"創建中…\",\n  \"components.UserList.createlocaluser\": \"建立本地使用者\",\n  \"components.UserList.autogeneratepassword\": \"自動生成密碼\",\n  \"i18n.tvshows\": \"影集\",\n  \"pages.oops\": \"哎呀\",\n  \"components.TvDetails.firstAirDate\": \"原始播出日期\",\n  \"i18n.delete\": \"刪除\",\n  \"i18n.declined\": \"已拒絕\",\n  \"i18n.decline\": \"拒絕\",\n  \"components.MovieDetails.cast\": \"演員陣容\",\n  \"components.TvDetails.cast\": \"演員陣容\",\n  \"i18n.available\": \"可觀看\",\n  \"i18n.approved\": \"獲批准\",\n  \"i18n.approve\": \"批准\",\n  \"components.TvDetails.anime\": \"動漫\",\n  \"i18n.processing\": \"處理中\",\n  \"i18n.deleting\": \"刪除中…\",\n  \"components.Setup.finishing\": \"完成設定中…\",\n  \"components.Settings.SonarrModal.loadingrootfolders\": \"載入中…\",\n  \"components.Settings.SonarrModal.loadingprofiles\": \"載入中…\",\n  \"components.Settings.RadarrModal.loadingrootfolders\": \"載入中…\",\n  \"components.Settings.RadarrModal.loadingprofiles\": \"載入中…\",\n  \"components.Search.searchresults\": \"搜尋結果\",\n  \"components.RequestModal.seasonnumber\": \"第 {number} 季\",\n  \"components.RequestModal.season\": \"季數\",\n  \"components.RequestModal.numberofepisodes\": \"集數\",\n  \"components.RequestModal.cancel\": \"取消請求\",\n  \"components.RequestList.sortModified\": \"最後修改\",\n  \"components.RequestList.sortAdded\": \"最新\",\n  \"components.RequestList.showallrequests\": \"查看所有請求\",\n  \"components.RequestList.requests\": \"請求\",\n  \"components.RequestList.RequestItem.seasons\": \"季數\",\n  \"components.RequestList.RequestItem.failedretry\": \"重試提出請求時出了點問題。\",\n  \"components.RequestCard.seasons\": \"季數\",\n  \"components.RequestButton.viewrequest4k\": \"查看 4K 請求\",\n  \"components.RequestButton.viewrequest\": \"查看請求\",\n  \"components.RequestButton.requestmore4k\": \"再提出 4K 請求\",\n  \"components.RequestButton.requestmore\": \"提出更多季數的請求\",\n  \"components.RequestButton.declinerequests\": \"拒絕{requestCount, plural, one {請求} other {{requestCount} 個請求}}\",\n  \"components.RequestButton.declinerequest4k\": \"拒絕 4K 請求\",\n  \"components.RequestButton.declinerequest\": \"拒絕請求\",\n  \"components.RequestButton.decline4krequests\": \"拒絕 {requestCount, plural, one {4K 請求} other {{requestCount} 個 4K 請求}}\",\n  \"components.RequestButton.approverequests\": \"批准{requestCount, plural, one {請求} other { {requestCount} 個請求}}\",\n  \"components.RequestButton.approverequest4k\": \"批准 4K 請求\",\n  \"components.RequestButton.approverequest\": \"批准請求\",\n  \"components.RequestButton.approve4krequests\": \"批准{requestCount, plural, one { 4K 請求} other { {requestCount} 個 4K 請求}}\",\n  \"components.RequestBlock.seasons\": \"季數\",\n  \"components.PersonDetails.crewmember\": \"製作群成員\",\n  \"components.NotificationTypeSelector.mediarequested\": \"請求待批准\",\n  \"components.NotificationTypeSelector.mediafailed\": \"請求處理失敗\",\n  \"components.NotificationTypeSelector.mediaapproved\": \"請求獲批准\",\n  \"components.NotificationTypeSelector.mediaavailableDescription\": \"當請求的媒體可觀看時發送通知。\",\n  \"components.NotificationTypeSelector.mediaapprovedDescription\": \"當請求獲手動批准時發送通知。\",\n  \"components.NotificationTypeSelector.mediaavailable\": \"請求可觀看\",\n  \"components.MovieDetails.watchtrailer\": \"觀看預告片\",\n  \"components.MovieDetails.viewfullcrew\": \"檢視完整製作群\",\n  \"components.MovieDetails.studio\": \"製作公司\",\n  \"components.MovieDetails.similar\": \"類似\",\n  \"components.MovieDetails.runtime\": \"{minutes} 分鐘\",\n  \"components.MovieDetails.revenue\": \"收入\",\n  \"components.MovieDetails.releasedate\": \"上映日期\",\n  \"components.MovieDetails.recommendations\": \"推薦\",\n  \"components.Layout.Sidebar.dashboard\": \"探索\",\n  \"components.MovieDetails.overview\": \"概要\",\n  \"components.MovieDetails.originallanguage\": \"原始語言\",\n  \"components.MovieDetails.budget\": \"電影成本\",\n  \"components.MovieDetails.MovieCrew.fullcrew\": \"製作群\",\n  \"components.MovieDetails.MovieCast.fullcast\": \"演員陣容\",\n  \"components.Login.validationpasswordrequired\": \"請輸入您的密碼\",\n  \"components.Login.validationemailrequired\": \"請輸入有效的電子郵件地址\",\n  \"components.Login.signinwithoverseerr\": \"使用您的 {applicationTitle} 帳戶\",\n  \"components.Login.password\": \"密碼\",\n  \"components.Login.loginerror\": \"登入時出了點問題。\",\n  \"components.Login.email\": \"電子郵件地址\",\n  \"components.Layout.UserDropdown.signout\": \"登出\",\n  \"components.Layout.Sidebar.users\": \"使用者\",\n  \"components.Layout.Sidebar.settings\": \"設定\",\n  \"components.Layout.Sidebar.requests\": \"請求\",\n  \"components.Layout.SearchInput.searchPlaceholder\": \"搜尋電影、影集、人物…\",\n  \"components.Discover.upcomingmovies\": \"即將上映的電影\",\n  \"components.Discover.upcoming\": \"即將上映的電影\",\n  \"components.Discover.trending\": \"熱門趨勢\",\n  \"components.Discover.recentlyAdded\": \"最近新增\",\n  \"components.Discover.recentrequests\": \"最新請求\",\n  \"components.Discover.populartv\": \"熱門影集\",\n  \"components.Discover.popularmovies\": \"熱門電影\",\n  \"components.CollectionDetails.requestcollection\": \"提出電影系列請求\",\n  \"components.CollectionDetails.overview\": \"概要\",\n  \"components.UserList.userdeleteerror\": \"刪除使用者時出了點問題。\",\n  \"components.UserList.userdeleted\": \"使用者刪除成功！\",\n  \"components.UserList.usercreatedsuccess\": \"建立新使用者成功！\",\n  \"components.UserList.usercreatedfailed\": \"建立新使用者時出了點問題。\",\n  \"components.UserList.user\": \"使用者\",\n  \"components.UserList.totalrequests\": \"請求數\",\n  \"components.UserList.plexuser\": \"Plex 使用者\",\n  \"components.UserList.email\": \"電子郵件地址\",\n  \"components.UserList.deleteuser\": \"刪除使用者\",\n  \"components.UserList.role\": \"角色\",\n  \"components.UserList.password\": \"密碼\",\n  \"i18n.movies\": \"電影\",\n  \"components.Setup.signinMessage\": \"首先，請使用您的 Plex 帳戶登入\",\n  \"components.CollectionDetails.numberofmovies\": \"{count} 部電影\",\n  \"components.UserList.admin\": \"管理員\",\n  \"components.Settings.SonarrModal.baseUrl\": \"網站根目錄\",\n  \"components.Settings.RadarrModal.baseUrl\": \"網站根目錄\",\n  \"components.Settings.notrunning\": \"未運行\",\n  \"components.Settings.activeProfile\": \"目前的品質設定\",\n  \"components.Settings.notificationsettings\": \"通知設定\",\n  \"components.Settings.default4k\": \"設定 4K 為預設分辨率\",\n  \"components.Settings.currentlibrary\": \"當前媒體庫： {name}\",\n  \"components.Settings.SonarrModal.seasonfolders\": \"季數檔案夾\",\n  \"components.Settings.SettingsAbout.gettingsupport\": \"支援\",\n  \"components.Settings.manualscan\": \"媒體庫手動掃描\",\n  \"components.Settings.plexlibraries\": \"Plex 媒體庫\",\n  \"components.Settings.menuGeneralSettings\": \"一般\",\n  \"components.Settings.SettingsAbout.totalrequests\": \"請求數\",\n  \"components.Settings.SettingsAbout.totalmedia\": \"媒體數\",\n  \"components.Settings.SettingsAbout.githubdiscussions\": \"GitHub 討論區\",\n  \"components.Settings.startscan\": \"執行掃描\",\n  \"components.Settings.cancelscan\": \"取消掃描\",\n  \"components.Settings.RadarrModal.toastRadarrTestSuccess\": \"Radarr 伺服器連線成功！\",\n  \"components.Settings.SonarrModal.testFirstRootFolders\": \"請先測試連線\",\n  \"components.Settings.SonarrModal.testFirstQualityProfiles\": \"請先測試連線\",\n  \"components.Settings.RadarrModal.testFirstRootFolders\": \"請先測試連線\",\n  \"components.Settings.RadarrModal.testFirstQualityProfiles\": \"請先測試連線\",\n  \"components.Settings.SonarrModal.defaultserver\": \"預設伺服器\",\n  \"components.Settings.deleteserverconfirm\": \"確定要刪除這個伺服器嗎？\",\n  \"components.Settings.addradarr\": \"新增 Radarr 伺服器\",\n  \"components.Settings.addsonarr\": \"新增 Sonarr 伺服器\",\n  \"components.Settings.SonarrModal.server4k\": \"4K 伺服器\",\n  \"components.Settings.SonarrModal.validationProfileRequired\": \"請設定品質\",\n  \"components.Settings.RadarrModal.validationProfileRequired\": \"請設定品質\",\n  \"components.Settings.SonarrModal.selectQualityProfile\": \"設定品質\",\n  \"components.Settings.RadarrModal.selectQualityProfile\": \"設定品質\",\n  \"components.Settings.RadarrModal.validationMinimumAvailabilityRequired\": \"請設定最低狀態\",\n  \"components.Settings.RadarrModal.selectMinimumAvailability\": \"設定最低狀態\",\n  \"components.Settings.SonarrModal.validationRootFolderRequired\": \"請設定根目錄\",\n  \"components.Settings.SonarrModal.selectRootFolder\": \"設定根目錄\",\n  \"components.Settings.RadarrModal.selectRootFolder\": \"設定根目錄\",\n  \"components.Settings.RadarrModal.validationRootFolderRequired\": \"請設定根目錄\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingssaved\": \"Slack 通知設定儲存成功！\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingssaved\": \"Webhook 通知設定儲存成功！\",\n  \"components.Settings.Notifications.discordsettingssaved\": \"Discord 通知設定儲存成功！\",\n  \"components.Settings.Notifications.emailsettingssaved\": \"電子郵件通知設定儲存成功！\",\n  \"components.Settings.Notifications.chatId\": \"聊天室 ID\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed\": \"Pushover 通知設定儲存失敗。\",\n  \"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed\": \"Slack 通知設定儲存失敗。\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed\": \"Webhook 通知設定儲存失敗。\",\n  \"components.Settings.Notifications.discordsettingsfailed\": \"Discord 通知設定儲存失敗。\",\n  \"components.Settings.Notifications.emailsettingsfailed\": \"電子郵件通知設定儲存失敗。\",\n  \"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp\": \"幫助\",\n  \"components.Settings.SonarrModal.animerootfolder\": \"動漫根目錄\",\n  \"components.Settings.SonarrModal.rootfolder\": \"根目錄\",\n  \"components.Settings.RadarrModal.rootfolder\": \"根目錄\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayload\": \"重設為預設\",\n  \"components.Settings.Notifications.NotificationsWebhook.customJson\": \"JSON 有效負載\",\n  \"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess\": \"JSON 有效負載重設為預設負載成功！\",\n  \"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired\": \"請輸入有效的使用者或群組令牌\",\n  \"components.Settings.menuJobs\": \"作業和快取\",\n  \"components.UserList.deleteconfirm\": \"確定要刪除這個使用者嗎？此使用者的所有儲存資料將被清除。\",\n  \"components.Settings.SettingsAbout.Releases.releasedataMissing\": \"無法獲取軟體版本資料。\",\n  \"components.UserList.passwordinfodescription\": \"設定應用程式網址以及啟用電子郵件通知，才能自動生成密碼。\",\n  \"components.Settings.Notifications.validationBotAPIRequired\": \"請輸入機器人授權令牌\",\n  \"components.Settings.Notifications.botAPI\": \"Bot 機器人授權令牌\",\n  \"components.Settings.menuServices\": \"伺服器\",\n  \"components.Settings.address\": \"網址\",\n  \"components.Settings.ssl\": \"SSL\",\n  \"components.Settings.SonarrModal.ssl\": \"使用安全通訊協定（SSL）\",\n  \"components.Settings.RadarrModal.ssl\": \"使用安全通訊協定（SSL）\",\n  \"components.Settings.port\": \"通訊埠\",\n  \"components.Settings.SonarrModal.port\": \"通訊埠\",\n  \"components.Settings.RadarrModal.port\": \"通訊埠\",\n  \"components.Settings.Notifications.NotificationsPushover.userToken\": \"使用者或群組令牌\",\n  \"components.Settings.Notifications.NotificationsPushover.accessToken\": \"應用程式 API 令牌\",\n  \"components.Settings.menuNotifications\": \"通知\",\n  \"components.Settings.menuLogs\": \"日誌\",\n  \"components.Settings.menuAbout\": \"關於 Jellyseerr\",\n  \"components.Settings.default\": \"預設\",\n  \"components.Settings.SettingsAbout.version\": \"軟體版本\",\n  \"components.Settings.SettingsAbout.Releases.latestversion\": \"最新版本\",\n  \"components.Settings.SettingsAbout.Releases.currentversion\": \"目前的版本\",\n  \"components.Settings.SettingsAbout.timezone\": \"時區\",\n  \"components.Settings.SettingsAbout.documentation\": \"使用說明\",\n  \"components.RequestModal.pending4krequest\": \"待處理的 4K 請求\",\n  \"components.RequestModal.pendingrequest\": \"待處理的請求\",\n  \"components.Settings.SettingsAbout.Releases.versionChangelog\": \"{version} 變更日誌\",\n  \"components.Settings.SettingsAbout.Releases.releases\": \"軟體版本\",\n  \"components.Settings.plexsettings\": \"Plex 設定\",\n  \"components.RequestModal.selectseason\": \"請選擇季數\",\n  \"components.RequestModal.requestseasons\": \"提出請求\",\n  \"components.RequestModal.requestadmin\": \"此請求將自動獲批准。\",\n  \"components.RequestModal.requestSuccess\": \"為 <strong>{title}</strong> 提出請求成功！\",\n  \"components.RequestModal.requestCancel\": \"<strong>{title}</strong> 的請求已被取消。\",\n  \"components.PersonDetails.appearsin\": \"演出\",\n  \"components.PersonDetails.ascharacter\": \"飾演 {character}\",\n  \"components.TvDetails.overviewunavailable\": \"沒有概要。\",\n  \"components.MovieDetails.overviewunavailable\": \"沒有概要。\",\n  \"components.TvDetails.watchtrailer\": \"觀看預告片\",\n  \"components.TvDetails.showtype\": \"影集類型\",\n  \"components.TvDetails.similar\": \"類似\",\n  \"components.RequestModal.requestfrom\": \"{username} 的請求待處理。\",\n  \"components.Settings.validationPortRequired\": \"請輸入有效的通訊埠\",\n  \"components.Settings.validationHostnameRequired\": \"請輸入有效的主機名稱或 IP 位址\",\n  \"components.Settings.SonarrModal.validationPortRequired\": \"請輸入有效的通訊埠\",\n  \"components.Settings.SonarrModal.validationNameRequired\": \"請輸入伺服器名稱\",\n  \"components.Settings.SonarrModal.validationHostnameRequired\": \"請輸入有效的主機名稱或 IP 位址\",\n  \"components.Settings.RadarrModal.validationPortRequired\": \"請輸入有效的通訊埠\",\n  \"components.Settings.SonarrModal.validationApiKeyRequired\": \"請輸入應用程式密鑰\",\n  \"components.Settings.RadarrModal.validationNameRequired\": \"請輸入伺服器名稱\",\n  \"components.Settings.RadarrModal.validationHostnameRequired\": \"請輸入有效的主機名稱或 IP 位址\",\n  \"components.Settings.RadarrModal.validationApiKeyRequired\": \"請輸入應用程式密鑰\",\n  \"components.Settings.Notifications.validationChatIdRequired\": \"請輸入有效的聊天室 ID\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired\": \"請輸入有效的 JSON 有效負載\",\n  \"components.Settings.Notifications.NotificationsWebhook.authheader\": \"Authorization 頭欄位\",\n  \"components.Settings.RadarrModal.minimumAvailability\": \"最低狀態\",\n  \"components.Settings.Notifications.allowselfsigned\": \"允許自簽名證書\",\n  \"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired\": \"請輸入應用程式 API 令牌\",\n  \"components.Settings.RadarrModal.hostname\": \"主機名稱或 IP 位址\",\n  \"components.Settings.SonarrModal.hostname\": \"主機名稱或 IP 位址\",\n  \"components.Settings.hostname\": \"主機名稱或 IP 位址\",\n  \"components.Settings.RadarrModal.toastRadarrTestFailure\": \"Radarr 伺服器連線失敗。\",\n  \"components.Settings.RadarrModal.server4k\": \"4K 伺服器\",\n  \"components.Settings.SonarrModal.animequalityprofile\": \"動漫品質設定\",\n  \"components.Settings.SonarrModal.qualityprofile\": \"品質設定\",\n  \"components.Settings.RadarrModal.qualityprofile\": \"品質設定\",\n  \"components.Settings.Notifications.telegramsettingsfailed\": \"Telegram 通知設定儲存失敗。\",\n  \"components.Settings.Notifications.telegramsettingssaved\": \"Telegram 通知設定儲存成功！\",\n  \"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved\": \"Pushover 通知設定儲存成功！\",\n  \"components.UserList.created\": \"加入日期\",\n  \"components.UserList.create\": \"建立\",\n  \"components.Settings.SonarrModal.createsonarr\": \"新增 Sonarr 伺服器\",\n  \"components.Settings.RadarrModal.createradarr\": \"新增 Radarr 伺服器\",\n  \"components.Settings.SonarrModal.servername\": \"伺服器名稱\",\n  \"components.Settings.SonarrModal.editsonarr\": \"編輯 Sonarr 伺服器\",\n  \"components.Settings.SonarrModal.add\": \"新增伺服器\",\n  \"components.Settings.RadarrModal.servername\": \"伺服器名稱\",\n  \"components.Settings.RadarrModal.editradarr\": \"編輯 Radarr 伺服器\",\n  \"components.Settings.RadarrModal.defaultserver\": \"預設伺服器\",\n  \"components.Settings.RadarrModal.add\": \"新增伺服器\",\n  \"components.RequestModal.requestcancelled\": \"<strong>{title}</strong> 的請求已被取消。\",\n  \"components.RequestModal.AdvancedRequester.qualityprofile\": \"品質設定\",\n  \"components.RequestModal.AdvancedRequester.animenote\": \"※這是個動漫影集。\",\n  \"components.RequestModal.AdvancedRequester.advancedoptions\": \"進階選項\",\n  \"components.RequestModal.AdvancedRequester.default\": \"{name}（預設）\",\n  \"components.RequestModal.AdvancedRequester.destinationserver\": \"目標伺服器\",\n  \"components.RequestBlock.server\": \"目標伺服器\",\n  \"components.RequestModal.AdvancedRequester.rootfolder\": \"根目錄\",\n  \"components.RequestBlock.rootfolder\": \"根目錄\",\n  \"components.MediaSlider.ShowMoreCard.seemore\": \"更多\",\n  \"components.Login.signinwithplex\": \"使用您的 Plex 帳戶\",\n  \"components.Login.signinheader\": \"請先登入\",\n  \"components.Login.signingin\": \"登入中…\",\n  \"components.Login.signin\": \"登入\",\n  \"components.Settings.SonarrModal.toastSonarrTestFailure\": \"Sonarr 伺服器連線失敗。\",\n  \"components.Settings.serverpreset\": \"伺服器\",\n  \"components.RequestModal.autoapproval\": \"自動批准\",\n  \"components.PermissionEdit.autoapproveSeries\": \"影集自動批准\",\n  \"components.PermissionEdit.autoapproveMovies\": \"電影自動批准\",\n  \"components.PermissionEdit.autoapprove\": \"自動批准\",\n  \"components.PermissionEdit.admin\": \"管理員\",\n  \"components.Settings.toastPlexConnecting\": \"連線中…\",\n  \"components.Settings.toastPlexRefresh\": \"載入中…\",\n  \"components.Settings.serverpresetRefreshing\": \"載入中…\",\n  \"components.Settings.SonarrModal.syncEnabled\": \"啟用掃描\",\n  \"components.UserList.userssaved\": \"使用者權限儲存成功！\",\n  \"components.Settings.SonarrModal.externalUrl\": \"外部網址\",\n  \"components.Settings.RadarrModal.externalUrl\": \"外部網址\",\n  \"components.RequestBlock.requestoverrides\": \"覆寫請求\",\n  \"components.Settings.toastPlexConnectingSuccess\": \"Plex 伺服器連線成功！\",\n  \"components.Settings.serverRemote\": \"遠端\",\n  \"components.Settings.serverLocal\": \"本地\",\n  \"components.MovieDetails.mark4kavailable\": \"標記 4K 版為可觀看\",\n  \"components.MovieDetails.markavailable\": \"標記為可觀看\",\n  \"components.Settings.RadarrModal.syncEnabled\": \"啟用掃描\",\n  \"i18n.experimental\": \"實驗性\",\n  \"components.UserList.bulkedit\": \"批次編輯\",\n  \"i18n.edit\": \"編輯\",\n  \"components.Settings.serverpresetManualMessage\": \"手動設定\",\n  \"components.NotificationTypeSelector.mediadeclined\": \"請求拒絕\",\n  \"components.PermissionEdit.users\": \"管理使用者\",\n  \"components.PermissionEdit.request4kTv\": \"提出 4K 影集請求\",\n  \"components.PermissionEdit.request4kMovies\": \"提出 4K 電影請求\",\n  \"components.PermissionEdit.request4k\": \"提出 4K 請求\",\n  \"components.PermissionEdit.request\": \"提出請求\",\n  \"components.PermissionEdit.managerequests\": \"管理請求\",\n  \"components.RequestBlock.profilechanged\": \"品質設定\",\n  \"components.PermissionEdit.advancedrequest\": \"進階請求\",\n  \"components.RequestModal.requestedited\": \"<strong>{title}</strong> 的請求編輯成功！\",\n  \"components.RequestModal.errorediting\": \"編輯請求時出了點問題。\",\n  \"components.RequestModal.requesterror\": \"提出請求時出了點問題。\",\n  \"components.Settings.SettingsJobsCache.cachekeys\": \"鍵數\",\n  \"components.Settings.SettingsJobsCache.cachevsize\": \"值儲存大小\",\n  \"components.Settings.SettingsJobsCache.cacheksize\": \"鍵儲存大小\",\n  \"components.Settings.SettingsJobsCache.cacheflushed\": \"{cachename} 快取清除成功！\",\n  \"components.Settings.SettingsJobsCache.cachemisses\": \"失誤數\",\n  \"components.Settings.SettingsJobsCache.cachehits\": \"擊中數\",\n  \"components.Settings.SettingsJobsCache.cachename\": \"快取名稱\",\n  \"components.Settings.SettingsJobsCache.runnow\": \"執行\",\n  \"components.Settings.SettingsJobsCache.nextexecution\": \"下一次執行時間\",\n  \"components.Settings.SettingsJobsCache.jobtype\": \"作業類型\",\n  \"components.Settings.SettingsJobsCache.jobstarted\": \"{jobname} 已開始運行。\",\n  \"components.Settings.SettingsJobsCache.jobcancelled\": \"{jobname}已被取消。\",\n  \"components.Settings.SettingsJobsCache.jobs\": \"作業\",\n  \"components.Settings.SettingsJobsCache.jobname\": \"作業名稱\",\n  \"components.Settings.SettingsJobsCache.flushcache\": \"清除快取\",\n  \"components.Settings.SettingsJobsCache.canceljob\": \"取消作業\",\n  \"components.Settings.SettingsJobsCache.cache\": \"快取\",\n  \"components.Settings.SonarrModal.toastSonarrTestSuccess\": \"Sonarr 伺服器連線成功！\",\n  \"components.Settings.SettingsJobsCache.command\": \"指令\",\n  \"components.Settings.SettingsJobsCache.process\": \"程序\",\n  \"i18n.advanced\": \"進階\",\n  \"components.Settings.serverpresetLoad\": \"請點右邊的按鈕\",\n  \"components.Settings.toastPlexRefreshSuccess\": \"獲取 Plex 伺服器列表成功！\",\n  \"components.Settings.toastPlexRefreshFailure\": \"獲取 Plex 伺服器列表失敗。\",\n  \"components.Settings.toastPlexConnectingFailure\": \"Plex 伺服器連線失敗。\",\n  \"components.UserList.users\": \"使用者\",\n  \"components.Search.search\": \"搜尋\",\n  \"components.Setup.setup\": \"設定\",\n  \"components.Discover.discover\": \"探索\",\n  \"components.AppDataWarning.dockerVolumeMissingDescription\": \"<code>{appDataPath}</code> 的掛載路徑設定有誤。當容器停止或重新啟動時，所有資料都會被清除。\",\n  \"components.RequestModal.AdvancedRequester.requestas\": \"請求者\",\n  \"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash\": \"請刪除結尾斜線\",\n  \"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash\": \"請刪除結尾斜線\",\n  \"components.Settings.SonarrModal.validationApplicationUrl\": \"請輸入有效的網址\",\n  \"components.Settings.RadarrModal.validationApplicationUrl\": \"請輸入有效的網址\",\n  \"components.PermissionEdit.viewrequests\": \"查看請求\",\n  \"components.Settings.RadarrModal.validationBaseUrlLeadingSlash\": \"請加前置斜線\",\n  \"components.Settings.SonarrModal.validationBaseUrlLeadingSlash\": \"請加前置斜線\",\n  \"components.Settings.SonarrModal.validationBaseUrlTrailingSlash\": \"請刪除結尾斜線\",\n  \"components.Settings.RadarrModal.validationBaseUrlTrailingSlash\": \"請刪除結尾斜線\",\n  \"components.UserList.validationEmail\": \"請輸入有效的電子郵件地址\",\n  \"components.Settings.Notifications.validationEmail\": \"請輸入有效的電子郵件地址\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl\": \"請輸入有效的網址\",\n  \"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl\": \"請輸入有效的網址\",\n  \"components.ResetPassword.confirmpassword\": \"確認密碼\",\n  \"components.ResetPassword.emailresetlink\": \"發送密碼重設電子郵件\",\n  \"components.ResetPassword.email\": \"電子郵件地址\",\n  \"components.ResetPassword.gobacklogin\": \"返回\",\n  \"components.ResetPassword.resetpassword\": \"重設密碼\",\n  \"components.ResetPassword.validationpasswordmatch\": \"密碼必須匹配\",\n  \"components.ResetPassword.validationpasswordminchars\": \"密碼必須至少包含八個字符\",\n  \"components.ResetPassword.validationemailrequired\": \"請輸入有效的電子郵件地址\",\n  \"components.ResetPassword.validationpasswordrequired\": \"請輸入密碼\",\n  \"components.ResetPassword.password\": \"密碼\",\n  \"components.Login.forgotpassword\": \"忘記密碼？\",\n  \"components.TvDetails.nextAirDate\": \"下一次播出日期\",\n  \"components.NotificationTypeSelector.mediarequestedDescription\": \"當使用者提出需要管理員批准的請求時發送通知。\",\n  \"components.NotificationTypeSelector.mediafailedDescription\": \"當 Radarr 或 Sonarr 處理請求失敗時發送通知。\",\n  \"components.NotificationTypeSelector.mediadeclinedDescription\": \"當請求拒被絕時發送通知。\",\n  \"components.PermissionEdit.request4kDescription\": \"授予提出 4K 媒體請求的權限。\",\n  \"components.PermissionEdit.request4kMoviesDescription\": \"授予提出 4K 電影請求的權限。\",\n  \"components.PermissionEdit.request4kTvDescription\": \"授予提出 4K 影集請求的權限。\",\n  \"components.PermissionEdit.requestDescription\": \"授予提出非 4K 媒體請求的權限。\",\n  \"components.PermissionEdit.viewrequestsDescription\": \"授予查看其他使用者提出的媒體請求的權限。\",\n  \"components.Settings.SonarrModal.validationLanguageProfileRequired\": \"請設定語言\",\n  \"components.Settings.SonarrModal.testFirstLanguageProfiles\": \"請先測試連線\",\n  \"components.Settings.SonarrModal.selectLanguageProfile\": \"設定語言\",\n  \"components.Settings.SonarrModal.loadinglanguageprofiles\": \"載入中…\",\n  \"components.Settings.SonarrModal.languageprofile\": \"語言設定\",\n  \"components.Settings.SonarrModal.animelanguageprofile\": \"動漫語言設定\",\n  \"components.RequestModal.AdvancedRequester.languageprofile\": \"語言設定\",\n  \"components.PermissionEdit.usersDescription\": \"授予管理使用者的權限。有此權限的使用者不能編輯管理員或授予管理員權限。\",\n  \"components.PermissionEdit.autoapproveSeriesDescription\": \"自動批准非 4K 影集請求。\",\n  \"components.PermissionEdit.autoapproveMoviesDescription\": \"自動批准非 4K 電影請求。\",\n  \"components.PermissionEdit.autoapproveDescription\": \"自動批准所有非 4K 媒體請求。\",\n  \"components.PermissionEdit.advancedrequestDescription\": \"授予使用進階媒體請求選項的權限。\",\n  \"components.PermissionEdit.adminDescription\": \"授予最高權限；旁路所有權限檢查。\",\n  \"components.PermissionEdit.managerequestsDescription\": \"授予管理媒體請求的權限，以及所有自動批准的權限。\",\n  \"components.Settings.SettingsJobsCache.cacheDescription\": \"外部應用程式介面（external API）請求將存到快取記憶體，以減少 API 呼叫次數。\",\n  \"components.Settings.librariesRemaining\": \"媒體庫剩餘數： {count}\",\n  \"components.Settings.Notifications.sendSilentlyTip\": \"發送沒有警報音的通知\",\n  \"components.Settings.Notifications.sendSilently\": \"無聲通知\",\n  \"components.UserList.sortCreated\": \"加入日期\",\n  \"components.UserList.sortDisplayName\": \"顯示名稱\",\n  \"components.UserList.sortRequests\": \"請求數\",\n  \"components.PermissionEdit.autoapprove4kSeriesDescription\": \"自動批准 4K 影集請求。\",\n  \"components.PermissionEdit.autoapprove4kSeries\": \"4K 影集自動批准\",\n  \"components.PermissionEdit.autoapprove4kMoviesDescription\": \"自動批准 4K 電影請求。\",\n  \"components.PermissionEdit.autoapprove4kMovies\": \"4K 電影自動批准\",\n  \"components.PermissionEdit.autoapprove4kDescription\": \"自動批准所有 4K 媒體請求。\",\n  \"components.PermissionEdit.autoapprove4k\": \"自動批准 4K\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess\": \"權限設定儲存成功！\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess\": \"設定儲存成功！\",\n  \"components.UserProfile.recentrequests\": \"最新請求\",\n  \"components.UserProfile.UserSettings.UserPermissions.permissions\": \"權限設定\",\n  \"components.UserProfile.UserSettings.menuPermissions\": \"權限\",\n  \"components.UserProfile.UserSettings.menuNotifications\": \"通知\",\n  \"components.UserProfile.UserSettings.menuGeneralSettings\": \"一般\",\n  \"components.UserProfile.UserSettings.menuChangePass\": \"密碼\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength\": \"密碼必須至少包含八個字符\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame\": \"密碼必須匹配\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.password\": \"密碼設定\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword\": \"確認密碼\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings\": \"通知設定\",\n  \"components.UserList.edituser\": \"編輯使用者權限\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed\": \"Pushbullet 通知設定儲存失敗。\",\n  \"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved\": \"Pushbullet 通知設定儲存成功！\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired\": \"請輸入 API 令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordId\": \"使用者 ID\",\n  \"components.UserProfile.ProfileHeader.profile\": \"顯示個人資料\",\n  \"components.UserProfile.ProfileHeader.settings\": \"使用者設定\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.displayName\": \"顯示名稱\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings\": \"一般設定\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexuser\": \"Plex 使用者\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.localuser\": \"本地使用者\",\n  \"components.UserList.userfail\": \"使用者權限儲存時出了點問題。\",\n  \"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure\": \"儲存設定時出了點問題。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure\": \"儲存設定時出了點問題。\",\n  \"components.Settings.Notifications.NotificationsPushbullet.agentEnabled\": \"啟用通知\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessToken\": \"API 令牌\",\n  \"components.Layout.UserDropdown.settings\": \"設定\",\n  \"components.Layout.UserDropdown.myprofile\": \"個人資料\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword\": \"密碼必須匹配\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.currentpassword\": \"目前的密碼\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.newpassword\": \"新密碼\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword\": \"請輸入當前的密碼\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword\": \"請輸入新密碼\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess\": \"密碼設定成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId\": \"請輸入有效的使用者 ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip\": \"您的<FindDiscordIdLink>使用者 ID 號碼</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure\": \"重設密碼時出了點問題。\",\n  \"components.RequestModal.SearchByNameModal.notvdbiddescription\": \"無法自動配對此影集的數據。 請在以下選擇正確的媒體項。\",\n  \"components.CollectionDetails.requestcollection4k\": \"提出 4K 電影系列請求\",\n  \"components.ResetPassword.requestresetlinksuccessmessage\": \"通過電子郵件發送了密碼重設鏈接。\",\n  \"components.ResetPassword.resetpasswordsuccessmessage\": \"密碼重設成功！\",\n  \"components.RegionSelector.regionDefault\": \"所有地區\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.region\": \"「探索」地區\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage\": \"「探索」語言\",\n  \"components.Discover.upcomingtv\": \"即將上映的影集\",\n  \"components.Settings.webhook\": \"Webhook\",\n  \"components.Settings.email\": \"電子郵件\",\n  \"components.Settings.notificationAgentSettingsDescription\": \"設定通知類型和代理服務。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.regionTip\": \"以地區可用性篩選結果\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip\": \"以原始語言篩選結果\",\n  \"components.Settings.SettingsJobsCache.jobsDescription\": \"Jellyseerr 將定時運行以下的維護任務。手動執行工作不會影響它正常的行程。\",\n  \"components.Settings.plexsettingsDescription\": \"關於 Plex 伺服器的設定。Jellyseerr 將定時執行媒體庫掃描。\",\n  \"components.Settings.manualscanDescription\": \"在正常情況下，Jellyseerr 會每24小時掃描您的 Plex 媒體庫。最近新增的媒體將更頻繁掃描。設定新的 Plex 伺服器時，我們建議您執行一次手動掃描！\",\n  \"components.RegionSelector.regionServerDefault\": \"預設設定（{region}）\",\n  \"components.Settings.settingUpPlexDescription\": \"您可以手動輸入您的 Plex 伺服器資料，或從 <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink> 返回的數據做選擇。請點下拉式選單右邊的按鈕獲取伺服器列表。\",\n  \"components.Settings.plexlibrariesDescription\": \"Jellyseerr 將掃描的媒體庫。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription\": \"您無權設定此使用者的密碼。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.user\": \"使用者\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.accounttype\": \"使用者類型\",\n  \"components.UserList.accounttype\": \"類型\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.role\": \"角色\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.admin\": \"管理員\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.owner\": \"所有者\",\n  \"components.UserList.owner\": \"所有者\",\n  \"components.Settings.SettingsJobsCache.download-sync-reset\": \"下載狀態同步復位\",\n  \"components.Settings.SettingsJobsCache.download-sync\": \"下載狀態同步\",\n  \"components.Settings.SettingsJobsCache.unknownJob\": \"未知作業\",\n  \"components.TvDetails.seasons\": \"{seasonCount} 季\",\n  \"components.Discover.DiscoverTvGenre.genreSeries\": \"{genre}影集\",\n  \"components.Discover.DiscoverNetwork.networkSeries\": \"{network} 影集\",\n  \"components.Discover.DiscoverStudio.studioMovies\": \"{studio} 電影\",\n  \"components.Discover.DiscoverMovieGenre.genreMovies\": \"{genre}電影\",\n  \"i18n.loading\": \"載入中…\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId\": \"請輸入聊天室 ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId\": \"聊天室 ID\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently\": \"無聲通知\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription\": \"發送沒有警報音的通知\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong\": \"先<TelegramBotLink>建立一個聊天室</TelegramBotLink>以及把 <GetIdBotLink>@get_id_bot</GetIdBotLink> 加到聊天室，然後在聊天室裡發出 <code>/my_id</code> 命令\",\n  \"components.Settings.Notifications.botUsername\": \"Bot 機器人名稱\",\n  \"components.Discover.NetworkSlider.networks\": \"影視平台\",\n  \"components.Discover.StudioSlider.studios\": \"製作公司\",\n  \"components.Settings.Notifications.validationUrl\": \"請輸入有效的網址\",\n  \"components.Settings.Notifications.botAvatarUrl\": \"Bot 機器人頭像網址\",\n  \"components.RequestList.RequestItem.modified\": \"最後修改者\",\n  \"components.RequestList.RequestItem.modifieduserdate\": \"{user}（{date}）\",\n  \"components.RequestList.RequestItem.requested\": \"請求者\",\n  \"components.Settings.scanning\": \"同步中…\",\n  \"components.Settings.scan\": \"媒體庫同步\",\n  \"components.Settings.SettingsJobsCache.sonarr-scan\": \"Sonarr 掃描\",\n  \"components.Settings.SettingsJobsCache.radarr-scan\": \"Radarr 掃描\",\n  \"components.Settings.SettingsJobsCache.plex-recently-added-scan\": \"Plex 最近新增掃描\",\n  \"components.Settings.SettingsJobsCache.plex-full-scan\": \"Plex 媒體庫掃描\",\n  \"components.Discover.DiscoverTvLanguage.languageSeries\": \"{language}影集\",\n  \"components.Discover.DiscoverMovieLanguage.languageMovies\": \"{language}電影\",\n  \"components.UserProfile.ProfileHeader.userid\": \"使用者 ID：{userid}\",\n  \"components.UserProfile.ProfileHeader.joindate\": \"加入日期：{joindate}\",\n  \"components.Settings.SettingsUsers.localLogin\": \"允許本地登入\",\n  \"components.Settings.SettingsUsers.defaultPermissions\": \"預設權限\",\n  \"components.Settings.SettingsUsers.userSettingsDescription\": \"關於使用者的全域和預設設定。\",\n  \"components.Settings.SettingsUsers.userSettings\": \"使用者設定\",\n  \"components.Settings.menuUsers\": \"使用者\",\n  \"components.Settings.SettingsUsers.toastSettingsSuccess\": \"使用者設定儲存成功！\",\n  \"components.Settings.SettingsUsers.toastSettingsFailure\": \"儲存設定時出了點問題。\",\n  \"components.NotificationTypeSelector.mediaAutoApprovedDescription\": \"當使用者提出自動批准的請求時發送通知。\",\n  \"components.NotificationTypeSelector.mediaAutoApproved\": \"請求自動批准\",\n  \"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription\": \"您不能編輯自己的權限。\",\n  \"components.UserProfile.UserSettings.unauthorizedDescription\": \"您無權編輯此使用者的設定。\",\n  \"components.Settings.Notifications.pgpPrivateKeyTip\": \"使用 <OpenPgpLink>OpenPGP</OpenPgpLink> 電子郵件加密與簽章\",\n  \"components.Settings.Notifications.pgpPasswordTip\": \"使用 <OpenPgpLink>OpenPGP</OpenPgpLink> 電子郵件加密與簽章\",\n  \"components.Settings.Notifications.pgpPassword\": \"PGP 解密密碼\",\n  \"components.Settings.Notifications.pgpPrivateKey\": \"PGP 私鑰\",\n  \"components.TvDetails.episodeRuntime\": \"劇集片長\",\n  \"components.TvDetails.episodeRuntimeMinutes\": \"{runtime} 分鐘\",\n  \"components.RequestModal.AdvancedRequester.folder\": \"{path}（{space}）\",\n  \"components.Discover.TvGenreSlider.tvgenres\": \"影集類型\",\n  \"components.Discover.MovieGenreSlider.moviegenres\": \"電影類型\",\n  \"components.Discover.MovieGenreList.moviegenres\": \"電影類型\",\n  \"components.Discover.TvGenreList.seriesgenres\": \"影集類型\",\n  \"components.RequestModal.alreadyrequested\": \"已經有請求\",\n  \"components.Settings.SettingsLogs.time\": \"時間戳\",\n  \"components.Settings.SettingsLogs.resumeLogs\": \"恢復\",\n  \"components.Settings.SettingsLogs.pauseLogs\": \"暫停\",\n  \"components.Settings.SettingsLogs.filterWarn\": \"警告\",\n  \"components.Settings.SettingsLogs.filterInfo\": \"訊息\",\n  \"components.Settings.SettingsLogs.filterError\": \"錯誤\",\n  \"components.Settings.SettingsLogs.filterDebug\": \"除錯\",\n  \"components.Settings.SettingsLogs.label\": \"標籤\",\n  \"components.Settings.SettingsLogs.level\": \"等級\",\n  \"components.Settings.SettingsLogs.logs\": \"日誌\",\n  \"components.Settings.SettingsLogs.showall\": \"查看所有日誌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.notifications\": \"通知\",\n  \"components.Settings.SettingsUsers.users\": \"使用者\",\n  \"pages.errormessagewithcode\": \"{statusCode}－{error}\",\n  \"pages.somethingwentwrong\": \"出了點問題\",\n  \"pages.serviceunavailable\": \"伺服器無法使用\",\n  \"pages.pagenotfound\": \"頁面不存在\",\n  \"pages.internalservererror\": \"內部伺服器錯誤\",\n  \"i18n.usersettings\": \"使用者設定\",\n  \"i18n.settings\": \"設定\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent\": \"重設密碼時出了點問題。您確定輸入的當前密碼是正確的嗎？\",\n  \"components.ResetPassword.passwordreset\": \"密碼重設\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.general\": \"一般\",\n  \"components.Settings.services\": \"伺服器\",\n  \"components.Settings.plex\": \"Plex\",\n  \"components.Settings.notifications\": \"通知\",\n  \"components.Settings.SettingsLogs.message\": \"訊息\",\n  \"components.Settings.SettingsJobsCache.jobsandcache\": \"作業和快取\",\n  \"components.Settings.SettingsAbout.about\": \"關於 Jellyseerr\",\n  \"components.Settings.SettingsLogs.logsDescription\": \"您也能直接查看 <code>stdout</code> 數據流或位置於 <code>{appDataPath}/logs/seerr.log</code> 的日誌檔案。\",\n  \"components.Settings.SettingsLogs.logDetails\": \"日誌詳細信息\",\n  \"components.Settings.SettingsLogs.extraData\": \"附加數據\",\n  \"components.Settings.SettingsLogs.copyToClipboard\": \"複製到剪貼板\",\n  \"components.Settings.SettingsLogs.copiedLogMessage\": \"日誌訊息已複製到剪貼板。\",\n  \"components.Settings.enablessl\": \"使用安全通訊協定（SSL）\",\n  \"components.UserList.nouserstoimport\": \"沒有未匯入的 Plex 使用者。\",\n  \"components.PersonDetails.birthdate\": \"{birthdate}－\",\n  \"components.PersonDetails.lifespan\": \"{birthdate}－{deathdate}\",\n  \"components.PersonDetails.alsoknownas\": \"別名：{names}\",\n  \"i18n.delimitedlist\": \"{a}、{b}\",\n  \"components.Settings.SettingsUsers.tvRequestLimitLabel\": \"影集請求全域限制\",\n  \"components.Settings.SettingsUsers.movieRequestLimitLabel\": \"電影請求全域限制\",\n  \"components.RequestModal.QuotaDisplay.seasonlimit\": \"季數\",\n  \"components.RequestModal.QuotaDisplay.season\": \"影集季數\",\n  \"components.RequestModal.QuotaDisplay.requestsremaining\": \"{remaining, plural, =0 {電影請求剩餘數不足} other {剩餘 <strong>#</strong> 個{type}請求}}\",\n  \"components.RequestModal.QuotaDisplay.notenoughseasonrequests\": \"請求剩餘數不足\",\n  \"components.RequestModal.QuotaDisplay.movielimit\": \"電影\",\n  \"components.RequestModal.QuotaDisplay.allowedRequestsUser\": \"此使用者每 <strong>{days}</strong> 天能提出 <strong>{limit}</strong> 個{type}請求。\",\n  \"components.RequestModal.QuotaDisplay.allowedRequests\": \"您每 <strong>{days}</strong> 天能提出 <strong>{limit}</strong> 個{type}請求。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit\": \"影集請求限制\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.movierequestlimit\": \"電影請求限制\",\n  \"components.UserProfile.movierequests\": \"電影請求\",\n  \"components.UserProfile.limit\": \"{limit} 之 {remaining}\",\n  \"components.UserProfile.pastdays\": \"{type}（前 {days} 天）\",\n  \"components.UserProfile.requestsperdays\": \"剩餘 {limit}\",\n  \"components.QuotaSelector.unlimited\": \"無限\",\n  \"components.RequestModal.QuotaDisplay.movie\": \"電影\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.enableOverride\": \"覆寫全域限制\",\n  \"components.UserProfile.unlimited\": \"無限\",\n  \"components.UserProfile.totalrequests\": \"請求總數\",\n  \"components.UserProfile.seriesrequest\": \"影集請求\",\n  \"i18n.view\": \"檢視\",\n  \"i18n.tvshow\": \"影集\",\n  \"i18n.testing\": \"測試中…\",\n  \"i18n.test\": \"測試\",\n  \"i18n.status\": \"狀態\",\n  \"i18n.showingresults\": \"<strong>{from}</strong>－<strong>{to}</strong> 列（共 <strong>{total}</strong> 列）\",\n  \"i18n.saving\": \"儲存中…\",\n  \"i18n.save\": \"儲存變更\",\n  \"i18n.resultsperpage\": \"每頁顯示 {pageSize} 列\",\n  \"i18n.requesting\": \"提出請求中…\",\n  \"i18n.request4k\": \"提出 4K 請求\",\n  \"i18n.previous\": \"上一頁\",\n  \"i18n.notrequested\": \"沒有請求\",\n  \"i18n.noresults\": \"沒有結果。\",\n  \"i18n.next\": \"下一頁\",\n  \"i18n.movie\": \"電影\",\n  \"i18n.canceling\": \"取消中…\",\n  \"i18n.back\": \"返回\",\n  \"i18n.all\": \"所有\",\n  \"i18n.areyousure\": \"確定嗎？\",\n  \"components.RequestModal.QuotaDisplay.requiredquotaUser\": \"此使用者的影集請求數量必須至少剩餘 <strong>{seasons}</strong> 個季數才能提出此影集請求。\",\n  \"components.RequestModal.QuotaDisplay.requiredquota\": \"您的影集請求數量必須至少剩餘 <strong>{seasons}</strong> 個季數才能提出此影集請求。\",\n  \"components.TvDetails.originaltitle\": \"原始標題\",\n  \"components.MovieDetails.originaltitle\": \"原始標題\",\n  \"components.RequestModal.QuotaDisplay.quotaLinkUser\": \"訪問此使用者的<ProfileLink>個人資料頁面</ProfileLink>以查看使用者的請求限制 。\",\n  \"components.RequestModal.QuotaDisplay.quotaLink\": \"訪問您的<ProfileLink>個人資料頁面</ProfileLink>以查看您的請求限制 。\",\n  \"components.LanguageSelector.languageServerDefault\": \"預設設定（{language}）\",\n  \"components.LanguageSelector.originalLanguageDefault\": \"所有語言\",\n  \"components.RequestModal.AdvancedRequester.selecttags\": \"設定標籤\",\n  \"components.Settings.SonarrModal.selecttags\": \"設定標籤\",\n  \"components.Settings.RadarrModal.selecttags\": \"設定標籤\",\n  \"components.Settings.SonarrModal.notagoptions\": \"沒有標籤。\",\n  \"components.Settings.RadarrModal.notagoptions\": \"沒有標籤。\",\n  \"components.RequestModal.AdvancedRequester.notagoptions\": \"沒有標籤。\",\n  \"components.Settings.SonarrModal.edit4ksonarr\": \"編輯 4K Sonarr 伺服器\",\n  \"components.Settings.RadarrModal.edit4kradarr\": \"編輯 4K Radarr 伺服器\",\n  \"components.Settings.RadarrModal.create4kradarr\": \"新增 4K Radarr 伺服器\",\n  \"components.Settings.SonarrModal.create4ksonarr\": \"新增 4K Sonarr 伺服器\",\n  \"components.Settings.SonarrModal.default4kserver\": \"預設 4K 伺服器\",\n  \"components.Settings.RadarrModal.default4kserver\": \"預設 4K 伺服器\",\n  \"components.Settings.SonarrModal.testFirstTags\": \"請先測試連線\",\n  \"components.Settings.RadarrModal.testFirstTags\": \"請先測試連線\",\n  \"components.Settings.SonarrModal.loadingTags\": \"載入中…\",\n  \"components.Settings.SonarrModal.animeTags\": \"動漫標籤\",\n  \"components.Settings.SonarrModal.tags\": \"標籤\",\n  \"components.Settings.RadarrModal.tags\": \"標籤\",\n  \"components.RequestModal.AdvancedRequester.tags\": \"標籤\",\n  \"components.Settings.RadarrModal.loadingTags\": \"載入中…\",\n  \"components.RequestList.RequestItem.mediaerror\": \"找不到{mediaType}\",\n  \"components.RequestCard.mediaerror\": \"找不到{mediaType}\",\n  \"components.RequestList.RequestItem.deleterequest\": \"刪除請求\",\n  \"components.RequestCard.deleterequest\": \"刪除請求\",\n  \"components.Settings.Notifications.botUsernameTip\": \"允許使用者也把機器人加到自己的聊天室以及設定自己的通知\",\n  \"components.RequestModal.pendingapproval\": \"您的請求正在等待管理員批准。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed\": \"Telegram 通知設定儲存失敗。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingsfailed\": \"電子郵件通知設定儲存失敗。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed\": \"Discord 通知設定儲存失敗。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved\": \"Telegram 通知設定儲存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.emailsettingssaved\": \"電子郵件通知設定儲存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingssaved\": \"Discord 通知設定儲存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.email\": \"電子郵件\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKeyTip\": \"使用 <OpenPgpLink>OpenPGP</OpenPgpLink> 電子郵件加密\",\n  \"components.Settings.Notifications.validationPgpPassword\": \"請輸入 PGP 解密密碼\",\n  \"components.Settings.Notifications.validationPgpPrivateKey\": \"請輸入有效的 PGP 私鑰\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPgpPublicKey\": \"請輸入有效的 PGP 公鑰\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pgpPublicKey\": \"PGP 公鑰\",\n  \"components.RequestList.RequestItem.cancelRequest\": \"取消請求\",\n  \"components.NotificationTypeSelector.notificationTypes\": \"通知類型\",\n  \"components.Layout.VersionStatus.commitsbehind\": \"落後 {commitsBehind} 個提交\",\n  \"components.Layout.VersionStatus.outofdate\": \"非最新版本\",\n  \"components.Layout.VersionStatus.streamstable\": \"Seerr 穩定版\",\n  \"components.Layout.VersionStatus.streamdevelop\": \"Seerr 開發版\",\n  \"components.Settings.SettingsAbout.outofdate\": \"非最新版本\",\n  \"components.Settings.SettingsAbout.uptodate\": \"最新\",\n  \"components.Settings.noDefaultNon4kServer\": \"如果您只有一個 {serverType} 伺服器，請勿把它設定為 4K 伺服器。\",\n  \"components.Settings.noDefaultServer\": \"您必須至少指定一個預設 {serverType} 伺服器，才能處理{mediaType}請求。\",\n  \"components.Settings.serviceSettingsDescription\": \"關於 {serverType} 伺服器的設定。{serverType} 伺服器數沒有最大值限制，但您只能指定兩個預設伺服器（一個非 4K、一個 4K）。\",\n  \"components.Settings.mediaTypeSeries\": \"影集\",\n  \"components.Settings.mediaTypeMovie\": \"電影\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet\": \"此使用者的帳戶目前沒有設密碼。若在以下設定密碼，此使用者就能使用「本地登入」。\",\n  \"components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount\": \"您的帳戶目前沒有設密碼。若在以下設定密碼，您就能使用「本地登入」。\",\n  \"components.UserList.autogeneratepasswordTip\": \"通過電子郵件發送伺服器生成的密碼給使用者\",\n  \"i18n.retrying\": \"重試中…\",\n  \"components.Settings.serverSecure\": \"SSL\",\n  \"components.UserList.usercreatedfailedexisting\": \"您提供的電子郵件地址已由其他使用者使用。\",\n  \"components.RequestModal.edit\": \"編輯請求\",\n  \"components.RequestList.RequestItem.editrequest\": \"編輯請求\",\n  \"components.Settings.RadarrModal.enableSearch\": \"啟用自動搜尋\",\n  \"components.Settings.SonarrModal.enableSearch\": \"啟用自動搜尋\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.webpush\": \"網路推送\",\n  \"components.Settings.webpush\": \"網路推送\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingssaved\": \"網路推送通知設定儲存成功！\",\n  \"components.Settings.Notifications.NotificationsWebPush.webpushsettingsfailed\": \"網路推送通知設定儲存失敗。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.applanguage\": \"顯示語言\",\n  \"components.Settings.Notifications.NotificationsWebPush.agentenabled\": \"啟用通知\",\n  \"components.Settings.is4k\": \"4K\",\n  \"components.Settings.Notifications.toastEmailTestSuccess\": \"電子郵件測試通知已發送！\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSuccess\": \"網路推送測試通知已發送！\",\n  \"components.Settings.Notifications.toastTelegramTestSuccess\": \"Telegram 測試通知已發送！\",\n  \"components.Settings.Notifications.toastDiscordTestSuccess\": \"Discord 測試通知已發送！\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSuccess\": \"Slack 測試通知已發送！\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess\": \"Pushover 測試通知已發送！\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSuccess\": \"Pushbullet 測試通知已發送！\",\n  \"components.Settings.noDefault4kServer\": \"您必須指定一個 4K {serverType} 伺服器為預設，才能處理 4K 的{mediaType}請求。\",\n  \"components.Settings.Notifications.toastTelegramTestSending\": \"發送 Telegram 測試通知中…\",\n  \"components.Settings.Notifications.toastEmailTestSending\": \"發送電子郵件測試通知中…\",\n  \"components.Settings.Notifications.toastDiscordTestSending\": \"發送 Discord 測試通知中…\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSending\": \"發送 webhook 測試通知中…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestSending\": \"發送網路推送測試通知中…\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestSending\": \"發送 Slack 測試通知中…\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending\": \"發送 Pushover 測試通知中…\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestSending\": \"發送 Pushbullet 測試通知中…\",\n  \"components.Settings.Notifications.NotificationsWebPush.toastWebPushTestFailed\": \"網路推送測試通知發送失敗。\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestFailed\": \"Webhook 測試通知發送失敗。\",\n  \"components.Settings.Notifications.toastEmailTestFailed\": \"電子郵件測試通知發送失敗。\",\n  \"components.Settings.Notifications.toastTelegramTestFailed\": \"Telegram 測試通知發送失敗。\",\n  \"components.Settings.Notifications.toastDiscordTestFailed\": \"Discord 測試通知發送失敗。\",\n  \"components.Settings.Notifications.NotificationsSlack.toastSlackTestFailed\": \"Slack 測試通知發送失敗。\",\n  \"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed\": \"Pushover 測試通知發送失敗。\",\n  \"components.Settings.Notifications.NotificationsPushbullet.toastPushbulletTestFailed\": \"Pushbullet 測試通知發送失敗。\",\n  \"components.Settings.Notifications.NotificationsWebhook.toastWebhookTestSuccess\": \"Webhook 測試通知已發送！\",\n  \"components.Settings.SettingsUsers.newPlexLoginTip\": \"讓還沒匯入的 Plex 使用者登入\",\n  \"components.Settings.SettingsUsers.newPlexLogin\": \"允許新的 Plex 登入\",\n  \"components.PermissionEdit.requestTv\": \"提出影集請求\",\n  \"components.PermissionEdit.requestMovies\": \"提出電影請求\",\n  \"components.PermissionEdit.requestMoviesDescription\": \"授予提出非 4K 電影請求的權限。\",\n  \"components.PermissionEdit.requestTvDescription\": \"授予提出非 4K 影集請求的權限。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.languageDefault\": \"預設設定（{language}）\",\n  \"components.DownloadBlock.estimatedtime\": \"預計：{time}\",\n  \"components.Settings.Notifications.encryptionTip\": \"TLS 通常會使用通訊埠 465，而 STARTTLS 通常會使用通訊埠 587\",\n  \"components.Settings.Notifications.encryptionDefault\": \"盡可能使用 STARTTLS\",\n  \"components.Settings.Notifications.encryptionImplicitTls\": \"使用傳輸層安全標準（TLS）\",\n  \"components.Settings.Notifications.encryptionOpportunisticTls\": \"始終使用 STARTTLS\",\n  \"components.Settings.Notifications.encryptionNone\": \"不使用加密\",\n  \"components.Settings.Notifications.encryption\": \"加密方式\",\n  \"components.Settings.Notifications.NotificationsPushover.userTokenTip\": \"您 30 個字符的<UsersGroupsLink>使用者或群組識別碼</UsersGroupsLink>\",\n  \"components.Settings.Notifications.NotificationsPushbullet.accessTokenTip\": \"從您的<PushbulletSettingsLink>帳號設定</PushbulletSettingsLink>取得 API 令牌\",\n  \"components.Settings.Notifications.NotificationsPushover.accessTokenTip\": \"建立一個 Seerr 專用的<ApplicationRegistrationLink>應用程式</ApplicationRegistrationLink>\",\n  \"components.Settings.Notifications.NotificationsSlack.webhookUrlTip\": \"創建一個「<WebhookLink>Incoming Webhook</WebhookLink>」整合\",\n  \"components.Settings.Notifications.webhookUrlTip\": \"在您的伺服器裡建立一個 <DiscordWebhookLink>webhook</DiscordWebhookLink>\",\n  \"components.Settings.Notifications.botApiTip\": \"建立一個 Jellyseerr 專用的<CreateBotLink>機器人</CreateBotLink>\",\n  \"components.Settings.Notifications.chatIdTip\": \"先與您的機器人建立一個聊天室以及把 <GetIdBotLink>@get_id_bot</GetIdBotLink> 也加到聊天室，然後在聊天室裡發出 <code>/my_id</code> 命令\",\n  \"components.Settings.webAppUrlTip\": \"使用伺服器的網路應用代替「託管」的網路應用\",\n  \"components.Settings.webAppUrl\": \"<WebAppLink>網路應用</WebAppLink>網址\",\n  \"components.Settings.Notifications.NotificationsWebPush.httpsRequirement\": \"Jellyseerr 必須通過 HTTPS 投放才能使用網路推送通知。\",\n  \"components.UserList.localLoginDisabled\": \"<strong>允許本地登入</strong>的設定目前被禁用。\",\n  \"components.RequestList.RequestItem.requesteddate\": \"請求日期\",\n  \"components.RequestCard.failedretry\": \"重試提出請求時出了點問題。\",\n  \"components.Settings.SettingsUsers.localLoginTip\": \"讓使用者使用電子郵件地址和密碼登入\",\n  \"components.Settings.SettingsUsers.defaultPermissionsTip\": \"授予給新使用者的權限\",\n  \"components.QuotaSelector.days\": \"天\",\n  \"components.QuotaSelector.seasons\": \"季\",\n  \"components.QuotaSelector.movies\": \"部電影\",\n  \"components.QuotaSelector.movieRequests\": \"<quotaUnits>每 {quotaDays} {days} </quotaUnits>{quotaLimit}<quotaUnits> {movies}</quotaUnits>\",\n  \"components.QuotaSelector.tvRequests\": \"<quotaUnits>每 {quotaDays} {days} </quotaUnits>{quotaLimit}<quotaUnits> {seasons}</quotaUnits>\",\n  \"components.Settings.Notifications.validationTypes\": \"請選擇通知類型\",\n  \"components.Settings.Notifications.NotificationsWebhook.validationTypes\": \"請選擇通知類型\",\n  \"components.Settings.Notifications.NotificationsSlack.validationTypes\": \"請選擇通知類型\",\n  \"components.Settings.Notifications.NotificationsPushover.validationTypes\": \"請選擇通知類型\",\n  \"components.Settings.Notifications.NotificationsPushbullet.validationTypes\": \"請選擇通知類型\",\n  \"components.NotificationTypeSelector.usermediarequestedDescription\": \"當其他使用者提出需要管理員批准的請求時取得通知。\",\n  \"components.NotificationTypeSelector.usermediafailedDescription\": \"當 Radarr 或 Sonarr 處理請求失敗時取得通知。\",\n  \"components.NotificationTypeSelector.usermediadeclinedDescription\": \"當您的請求被拒絕時取得通知。\",\n  \"components.NotificationTypeSelector.usermediaavailableDescription\": \"當您請求的媒體可觀看時取得通知。\",\n  \"components.NotificationTypeSelector.usermediaapprovedDescription\": \"當您的請求獲批准時取得通知。\",\n  \"components.NotificationTypeSelector.usermediaAutoApprovedDescription\": \"當其他使用者提出自動獲批准的請求時取得通知。\",\n  \"components.Layout.LanguagePicker.displaylanguage\": \"顯示語言\",\n  \"components.MovieDetails.showmore\": \"顯示更多\",\n  \"components.MovieDetails.showless\": \"顯示更少\",\n  \"components.TvDetails.streamingproviders\": \"播放平台\",\n  \"components.MovieDetails.streamingproviders\": \"播放平台\",\n  \"components.Settings.SettingsJobsCache.editJobSchedule\": \"編輯作業\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorHours\": \"每 {jobScheduleHours} 小時\",\n  \"components.Settings.SettingsJobsCache.editJobSchedulePrompt\": \"新的頻率\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorMinutes\": \"每 {jobScheduleMinutes} 分鐘\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditFailed\": \"儲存作業設定時出了點問題。\",\n  \"components.Settings.SettingsJobsCache.jobScheduleEditSaved\": \"作業編輯成功！\",\n  \"components.Settings.SettingsAbout.runningDevelop\": \"您正在使用 Jellyseerr 的 <code>develop</code> 開發版。我們只建議開發者和協助測試的人員使用。\",\n  \"components.StatusBadge.status\": \"{status}\",\n  \"components.IssueDetails.season\": \"第 {seasonNumber} 季\",\n  \"components.IssueList.IssueItem.problemepisode\": \"有問題的集數\",\n  \"components.IssueDetails.problemseason\": \"有問題的季數\",\n  \"components.IssueModal.CreateIssueModal.season\": \"第 {seasonNumber} 季\",\n  \"components.Layout.Sidebar.issues\": \"問題\",\n  \"components.IssueDetails.deleteissue\": \"刪除問題\",\n  \"components.IssueDetails.issuetype\": \"類型\",\n  \"components.IssueDetails.allseasons\": \"所有季數\",\n  \"components.IssueDetails.IssueDescription.description\": \"說明\",\n  \"components.IssueDetails.IssueDescription.edit\": \"編輯說明\",\n  \"components.IssueDetails.IssueDescription.deleteissue\": \"刪除問題\",\n  \"components.IssueDetails.deleteissueconfirm\": \"確定要刪除這個問題嗎？\",\n  \"components.IssueDetails.issuepagetitle\": \"問題\",\n  \"components.IssueDetails.lastupdated\": \"最後更新時間\",\n  \"components.IssueDetails.unknownissuetype\": \"不明\",\n  \"components.IssueList.issues\": \"問題\",\n  \"components.IssueList.IssueItem.viewissue\": \"查看問題\",\n  \"components.IssueModal.CreateIssueModal.episode\": \"第 {episodeNumber} 集\",\n  \"components.IssueModal.CreateIssueModal.problemepisode\": \"有問題的集數\",\n  \"components.IssueModal.CreateIssueModal.problemseason\": \"有問題的季數\",\n  \"components.IssueModal.CreateIssueModal.toastviewissue\": \"查看問題\",\n  \"components.ManageSlideOver.manageModalClearMedia\": \"清除儲存資料\",\n  \"components.ManageSlideOver.manageModalRequests\": \"請求\",\n  \"components.ManageSlideOver.manageModalNoRequests\": \"沒有請求。\",\n  \"components.ManageSlideOver.openarr\": \"開啟 {arr} 伺服器\",\n  \"components.ManageSlideOver.openarr4k\": \"開啟 4K {arr} 伺服器\",\n  \"components.ManageSlideOver.movie\": \"電影\",\n  \"components.ManageSlideOver.markavailable\": \"標記為可觀看\",\n  \"components.IssueModal.issueAudio\": \"音訊\",\n  \"components.ManageSlideOver.downloadstatus\": \"下載狀態\",\n  \"components.IssueModal.CreateIssueModal.allepisodes\": \"所有集數\",\n  \"components.ManageSlideOver.manageModalClearMediaWarning\": \"※這將會刪除包括使用者請求在內所有有關此{mediaType}的資料。如果這{mediaType}存在於您的 {mediaServerName} 伺服器，資料將會在媒體庫掃描時重新建立。\",\n  \"components.ManageSlideOver.mark4kavailable\": \"標記 4K 版為可觀看\",\n  \"components.IssueModal.issueSubtitles\": \"字幕\",\n  \"components.IssueModal.issueOther\": \"其他\",\n  \"components.ManageSlideOver.tvshow\": \"影集\",\n  \"components.ManageSlideOver.manageModalTitle\": \"管理{mediaType}\",\n  \"components.IssueModal.issueVideo\": \"影片\",\n  \"components.IssueList.IssueItem.issuetype\": \"類型\",\n  \"components.IssueDetails.problemepisode\": \"有問題的集數\",\n  \"components.IssueList.IssueItem.unknownissuetype\": \"不明\",\n  \"components.IssueList.IssueItem.issuestatus\": \"狀態\",\n  \"components.IssueModal.CreateIssueModal.allseasons\": \"所有季數\",\n  \"components.IssueDetails.allepisodes\": \"所有集數\",\n  \"components.IssueDetails.episode\": \"第 {episodeNumber} 集\",\n  \"components.PermissionEdit.viewissues\": \"查看問題\",\n  \"components.PermissionEdit.manageissuesDescription\": \"授予管理媒體問題的權限。\",\n  \"components.PermissionEdit.viewissuesDescription\": \"授予查看其他使用者提出的媒體問題的權限。\",\n  \"components.PermissionEdit.manageissues\": \"管理問題\",\n  \"components.IssueDetails.comments\": \"評論\",\n  \"components.IssueDetails.nocomments\": \"沒有評論。\",\n  \"components.IssueDetails.openedby\": \"#{issueId} 由 {username} {relativeTime}報告\",\n  \"components.IssueDetails.toastissuedeleted\": \"問題刪除成功！\",\n  \"components.IssueDetails.toaststatusupdated\": \"問題狀態編輯成功！\",\n  \"components.IssueDetails.toastissuedeletefailed\": \"刪除問題狀態時出了點問題。\",\n  \"components.IssueList.IssueItem.openeduserdate\": \"{user}（{date}）\",\n  \"components.IssueModal.CreateIssueModal.providedetail\": \"請詳細解釋您遇到的問題。\",\n  \"components.IssueModal.CreateIssueModal.submitissue\": \"報告問題\",\n  \"components.IssueModal.CreateIssueModal.toastFailedCreate\": \"提出問題報告時出了點問題。\",\n  \"components.NotificationTypeSelector.userissueresolvedDescription\": \"當您報告的問題解決時取得通知。\",\n  \"components.PermissionEdit.createissues\": \"報告問題\",\n  \"components.PermissionEdit.createissuesDescription\": \"授予報告媒體問題的權限。\",\n  \"components.IssueDetails.leavecomment\": \"發表評論\",\n  \"components.IssueDetails.toasteditdescriptionfailed\": \"編輯問題說明時出了點問題。\",\n  \"components.IssueList.showallissues\": \"查看所有問題\",\n  \"components.IssueDetails.toaststatusupdatefailed\": \"編輯問題狀態時出了點問題。\",\n  \"components.IssueModal.CreateIssueModal.reportissue\": \"報告問題\",\n  \"components.IssueList.IssueItem.opened\": \"報告者\",\n  \"components.IssueModal.CreateIssueModal.whatswrong\": \"請解釋您遇到的問題。\",\n  \"components.IssueModal.CreateIssueModal.validationMessageRequired\": \"請輸入問題說明\",\n  \"components.NotificationTypeSelector.issueresolved\": \"問題解決\",\n  \"components.NotificationTypeSelector.issuecreated\": \"問題報告\",\n  \"components.NotificationTypeSelector.issuecreatedDescription\": \"當使用者報告問題時發送通知。\",\n  \"components.NotificationTypeSelector.issuecomment\": \"問題評論\",\n  \"components.NotificationTypeSelector.adminissuecommentDescription\": \"當其他使用者加新評論時取得通知。\",\n  \"components.NotificationTypeSelector.issuecommentDescription\": \"當問題有新評論時發送通知。\",\n  \"components.NotificationTypeSelector.issueresolvedDescription\": \"當問題解決時發送通知。\",\n  \"components.IssueDetails.openinarr\": \"開啟 {arr} 伺服器\",\n  \"i18n.resolved\": \"已解決\",\n  \"i18n.open\": \"未解決\",\n  \"components.IssueList.sortAdded\": \"最新\",\n  \"components.IssueList.sortModified\": \"最後修改\",\n  \"components.IssueDetails.toasteditdescriptionsuccess\": \"問題說明編輯成功！\",\n  \"components.NotificationTypeSelector.userissuecreatedDescription\": \"當其他使用者報告問題時取得通知。\",\n  \"components.IssueDetails.IssueComment.delete\": \"刪除評論\",\n  \"components.IssueDetails.IssueComment.edit\": \"編輯評論\",\n  \"components.IssueDetails.IssueComment.validationComment\": \"請輸入評論\",\n  \"components.IssueDetails.IssueComment.areyousuredelete\": \"確定要刪除這個評論嗎？\",\n  \"components.IssueModal.CreateIssueModal.toastSuccessCreate\": \"為 <strong>{title}</strong> 報告問題成功！\",\n  \"components.NotificationTypeSelector.userissuecommentDescription\": \"當您報告的問題有新評論時取得通知。\",\n  \"components.IssueDetails.IssueComment.postedby\": \"由 {username} {relativeTime}發表\",\n  \"components.IssueDetails.IssueComment.postedbyedited\": \"由 {username} {relativeTime}發表（已編輯）\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushbulletAccessToken\": \"請輸入 API 令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken\": \"請輸入應用程式 API 令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingsfailed\": \"Pushbullet 通知設定儲存失敗。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationToken\": \"應用程式 API 令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved\": \"Pushover 通知設定儲存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessToken\": \"API 令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKeyTip\": \"您 30 個字符的<UsersGroupsLink>使用者或群組識別碼</UsersGroupsLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingsfailed\": \"Pushover 通知設定儲存失敗。\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletAccessTokenTip\": \"從您的<PushbulletSettingsLink>帳號設定</PushbulletSettingsLink>取得 API 令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushbulletsettingssaved\": \"Pushbullet 通知設定儲存成功！\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverApplicationTokenTip\": \"建立一個 {applicationTitle} 專用的<ApplicationRegistrationLink>應用程式</ApplicationRegistrationLink>\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.pushoverUserKey\": \"使用者或群組令牌\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey\": \"請輸入有效的使用者或群組令牌\",\n  \"components.IssueDetails.openin4karr\": \"開啟 4K {arr} 伺服器\",\n  \"components.IssueDetails.play4konplex\": \"在 Plex 上觀看 4K 版\",\n  \"components.IssueDetails.playonplex\": \"在 Plex 上觀看\",\n  \"components.IssueList.IssueItem.episodes\": \"集數\",\n  \"components.IssueList.IssueItem.seasons\": \"季數\",\n  \"components.IssueDetails.closeissue\": \"關閉問題\",\n  \"components.IssueDetails.closeissueandcomment\": \"發表評論及關閉問題\",\n  \"components.IssueDetails.reopenissueandcomment\": \"發表評論及重新開啟問題\",\n  \"components.IssueDetails.reopenissue\": \"重新開啟問題\",\n  \"components.ManageSlideOver.manageModalIssues\": \"未解決問題\",\n  \"components.IssueModal.CreateIssueModal.extras\": \"特輯\",\n  \"components.NotificationTypeSelector.issuereopened\": \"問題重新開啟\",\n  \"components.NotificationTypeSelector.adminissuereopenedDescription\": \"當其他使用者重新開啟問題時取得通知。\",\n  \"components.NotificationTypeSelector.adminissueresolvedDescription\": \"當其他使用者解決問題時取得通知。\",\n  \"components.NotificationTypeSelector.issuereopenedDescription\": \"當問題重新開啟時發送通知。\",\n  \"components.NotificationTypeSelector.userissuereopenedDescription\": \"當您報告的問題重新開啟時取得通知。\",\n  \"components.RequestModal.requestmovies4k\": \"提出 4K 請求\",\n  \"components.RequestModal.requestseasons4k\": \"提出 4K 請求\",\n  \"components.RequestModal.requestmovies\": \"提出請求\",\n  \"components.MovieDetails.productioncountries\": \"製作國家\",\n  \"components.RequestModal.selectmovies\": \"請選擇電影\",\n  \"components.TvDetails.productioncountries\": \"製作國家\",\n  \"components.IssueDetails.commentplaceholder\": \"發表評論…\",\n  \"components.RequestModal.requestApproved\": \"<strong>{title}</strong> 的請求已獲批准。\",\n  \"components.RequestModal.approve\": \"批准請求\",\n  \"components.Settings.RadarrModal.inCinemas\": \"已上映\",\n  \"components.Settings.RadarrModal.released\": \"已發佈\",\n  \"components.Settings.RadarrModal.announced\": \"已公佈\",\n  \"components.Settings.Notifications.enableMentions\": \"允許提及\",\n  \"components.Settings.Notifications.NotificationsGotify.agentenabled\": \"啟用通知\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSuccess\": \"Gotify 測試通知已發送！\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash\": \"請刪除結尾斜線\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingsfailed\": \"Gotify 通知設定儲存失敗。\",\n  \"components.Settings.Notifications.NotificationsGotify.gotifysettingssaved\": \"Gotify 通知設定儲存成功！\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestFailed\": \"Gotify 測試通知發送失敗。\",\n  \"components.Settings.Notifications.NotificationsGotify.toastGotifyTestSending\": \"發送 Gotify 測試通知中…\",\n  \"components.Settings.Notifications.NotificationsGotify.token\": \"應用程式令牌\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTokenRequired\": \"請輸入應用程式令牌\",\n  \"components.Settings.Notifications.NotificationsGotify.url\": \"伺服器網址\",\n  \"components.Settings.Notifications.NotificationsGotify.validationTypes\": \"請選擇通知類型\",\n  \"components.Settings.Notifications.NotificationsGotify.validationUrlRequired\": \"請輸入有效的網址\",\n  \"i18n.import\": \"匯入\",\n  \"i18n.importing\": \"匯入中…\",\n  \"components.ManageSlideOver.manageModalMedia\": \"媒體\",\n  \"components.ManageSlideOver.manageModalMedia4k\": \"4K 媒體\",\n  \"components.ManageSlideOver.manageModalAdvanced\": \"進階\",\n  \"components.ManageSlideOver.alltime\": \"歷史\",\n  \"components.ManageSlideOver.opentautulli\": \"開啟 Tautulli 伺服器\",\n  \"components.ManageSlideOver.pastdays\": \"過去 {days, number} 天\",\n  \"components.ManageSlideOver.playedby\": \"觀看者\",\n  \"components.ManageSlideOver.plays\": \"<strong>{playCount, number}</strong> 次\",\n  \"components.Settings.validationUrlTrailingSlash\": \"請刪除結尾斜線\",\n  \"components.Settings.externalUrl\": \"外部網址\",\n  \"components.Settings.toastTautulliSettingsSuccess\": \"Tautulli 設定儲存成功！\",\n  \"components.ManageSlideOver.markallseasons4kavailable\": \"標記 4K 版的所有季數為可觀看\",\n  \"components.ManageSlideOver.markallseasonsavailable\": \"標記所有季數為可觀看\",\n  \"components.Settings.tautulliSettings\": \"Tautulli 設定\",\n  \"components.Settings.tautulliApiKey\": \"應用程式密鑰\",\n  \"components.Settings.validationUrlBaseTrailingSlash\": \"請刪除結尾斜線\",\n  \"components.UserProfile.recentlywatched\": \"最近觀看\",\n  \"components.Settings.toastTautulliSettingsFailure\": \"儲存 Tautulli 設定時出了點問題。\",\n  \"components.Settings.urlBase\": \"網站根目錄\",\n  \"components.Settings.validationApiKey\": \"請輸入應用程式密鑰\",\n  \"components.Settings.validationUrlBaseLeadingSlash\": \"請加前置斜線\",\n  \"components.Settings.Notifications.NotificationsPushbullet.channelTag\": \"頻道標籤\",\n  \"components.Settings.validationUrl\": \"請輸入有效的網址\",\n  \"components.UserList.newplexsigninenabled\": \"<strong>允許新的 Plex 登入</strong> 的設定目前已啟用。還沒匯入的 Plex 使用者也能登入。\",\n  \"components.Settings.tautulliSettingsDescription\": \"關於 Tautulli 伺服器的設定。Jellyseerr 會從 Tautulli 獲取 Plex 媒體的觀看歷史記錄。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordId\": \"Discord 使用者 ID\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discordIdTip\": \"您的<FindDiscordIdLink>Discord 使用者 ID 號碼</FindDiscordIdLink>\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId\": \"請輸入有效的 Discord 使用者 ID\",\n  \"components.Settings.SettingsAbout.appDataPath\": \"資料目錄\",\n  \"components.RequestBlock.languageprofile\": \"語言設定\",\n  \"components.StatusChecker.appUpdated\": \"{applicationTitle} 軟體已更新\",\n  \"components.StatusChecker.reloadApp\": \"刷新頁面\",\n  \"components.StatusChecker.restartRequired\": \"必須重新啟動伺服器\",\n  \"i18n.restartRequired\": \"必須重新啟動伺服器\",\n  \"components.Settings.deleteServer\": \"刪除 {serverType} 伺服器\",\n  \"components.StatusChecker.appUpdatedDescription\": \"請點擊以下的按鈕刷新頁面。\",\n  \"components.StatusChecker.restartRequiredDescription\": \"請重新啟動伺服器以應用設定的變更。\",\n  \"components.MovieDetails.physicalrelease\": \"實體光碟\",\n  \"components.MovieDetails.theatricalrelease\": \"影院\",\n  \"components.MovieDetails.digitalrelease\": \"數字版本\",\n  \"components.PermissionEdit.viewrecent\": \"查看最近新增\",\n  \"components.PermissionEdit.viewrecentDescription\": \"授予查看最近新增的媒體的權限。\",\n  \"components.RequestList.RequestItem.tmdbid\": \"TMDB ID\",\n  \"components.TitleCard.mediaerror\": \"找不到{mediaType}\",\n  \"components.TitleCard.tvdbid\": \"TheTVDB ID\",\n  \"components.RequestCard.tvdbid\": \"TheTVDB ID\",\n  \"components.TitleCard.cleardata\": \"清除儲存資料\",\n  \"components.TitleCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestCard.tmdbid\": \"TMDB ID\",\n  \"components.RequestList.RequestItem.tvdbid\": \"TheTVDB ID\",\n  \"components.Discover.plexwatchlist\": \"您的 Plex 關注列表\",\n  \"components.PermissionEdit.autorequestMovies\": \"自動提出電影請求\",\n  \"components.PermissionEdit.autorequestSeries\": \"自動提出影集請求\",\n  \"components.Settings.SettingsJobsCache.plex-watchlist-sync\": \"Plex 關注列表同步\",\n  \"components.PermissionEdit.autorequest\": \"自動提出請求\",\n  \"components.Discover.DiscoverWatchlist.discoverwatchlist\": \"您的 Plex 關注列表\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmovies\": \"自動提出電影請求\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseries\": \"自動提出影集請求\",\n  \"components.NotificationTypeSelector.mediaautorequested\": \"請求自動提出\",\n  \"components.PermissionEdit.autorequestMoviesDescription\": \"授予從 Plex 關注列表中自動提出非 4K 電影請求的權限。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncmoviestip\": \"從您的 <PlexWatchlistSupportLink>Plex 關注列表</PlexWatchlistSupportLink>中自動提出電影請求\",\n  \"components.NotificationTypeSelector.mediaautorequestedDescription\": \"當您的 Plex 關注列表中的媒體自動提出請求時取得通知。\",\n  \"components.PermissionEdit.autorequestDescription\": \"授予從 Plex 關注列表中自動提出非 4K 媒體請求的權限。\",\n  \"components.PermissionEdit.autorequestSeriesDescription\": \"授予從 Plex 關注列表中自動提出非 4K 影集請求的權限。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.plexwatchlistsyncseriestip\": \"從您的 <PlexWatchlistSupportLink>Plex 關注列表</PlexWatchlistSupportLink>中自動提出影集請求\",\n  \"components.Settings.SettingsLogs.viewdetails\": \"查看詳細信息\",\n  \"components.TvDetails.reportissue\": \"報告問題\",\n  \"components.MovieDetails.managemovie\": \"管理電影\",\n  \"components.Discover.DiscoverWatchlist.watchlist\": \"Plex 關注列表\",\n  \"components.UserProfile.plexwatchlist\": \"Plex 關注列表\",\n  \"components.MovieDetails.reportissue\": \"報告問題\",\n  \"components.PermissionEdit.viewwatchlists\": \"查看 Plex 關注列表\",\n  \"components.PermissionEdit.viewwatchlistsDescription\": \"授予查看其他使用者的 Plex 關注列表的權限。\",\n  \"components.TvDetails.manageseries\": \"管理影集\",\n  \"components.Settings.restartrequiredTooltip\": \"Jellyseerr 必須重新啟動才能應用設定的變更\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.movierequests\": \"電影請求\",\n  \"components.Layout.UserDropdown.MiniQuotaDisplay.seriesrequests\": \"影集請求\",\n  \"components.Layout.UserDropdown.requests\": \"請求\",\n  \"components.TvDetails.seasonstitle\": \"季數\",\n  \"components.RequestBlock.decline\": \"拒絕請求\",\n  \"components.RequestBlock.edit\": \"編輯請求\",\n  \"components.RequestBlock.lastmodifiedby\": \"最後修改者\",\n  \"components.RequestBlock.requestdate\": \"請求日期\",\n  \"components.RequestCard.approverequest\": \"批准請求\",\n  \"components.RequestCard.cancelrequest\": \"取消請求\",\n  \"components.RequestCard.declinerequest\": \"拒絕請求\",\n  \"components.TvDetails.seasonnumber\": \"第 {seasonNumber} 季\",\n  \"components.RequestBlock.approve\": \"批准請求\",\n  \"components.RequestBlock.delete\": \"刪除請求\",\n  \"components.RequestCard.editrequest\": \"編輯請求\",\n  \"components.RequestBlock.requestedby\": \"請求者\",\n  \"components.StatusBadge.playonplex\": \"在 {mediaServerName} 上觀看\",\n  \"components.StatusBadge.managemedia\": \"管理{mediaType}\",\n  \"components.StatusBadge.openinarr\": \"開啟 {arr} 伺服器\",\n  \"components.TvDetails.status4k\": \"4K 版{status}\",\n  \"components.TvDetails.episodeCount\": \"{episodeCount} 集\",\n  \"components.AirDateBadge.airedrelative\": \"{relativeTime}播出\",\n  \"components.MovieDetails.rtaudiencescore\": \"爛番茄觀眾評分\",\n  \"components.TvDetails.Season.somethingwentwrong\": \"檢索數據時出了點問題。\",\n  \"components.TvDetails.tmdbuserscore\": \"TMDB 使用者評分\",\n  \"components.TvDetails.rtcriticsscore\": \"爛番茄專業評分\",\n  \"components.AirDateBadge.airsrelative\": \"{relativeTime}播出\",\n  \"components.MovieDetails.tmdbuserscore\": \"TMDB 使用者評分\",\n  \"components.MovieDetails.rtcriticsscore\": \"爛番茄專業評分\",\n  \"components.TvDetails.rtaudiencescore\": \"爛番茄觀眾評分\",\n  \"components.RequestModal.requestmovietitle\": \"提出電影請求\",\n  \"components.RequestModal.requestmovie4ktitle\": \"提出 4K 電影請求\",\n  \"components.RequestModal.requestcollection4ktitle\": \"提出 4K 電影系列請求\",\n  \"components.RequestModal.requestseriestitle\": \"提出影集請求\",\n  \"components.RequestModal.requestseries4ktitle\": \"提出 4K 影集請求\",\n  \"components.RequestModal.requestcollectiontitle\": \"提出電影系列請求\",\n  \"components.RequestModal.SearchByNameModal.nomatches\": \"找不到此影集的數據。\",\n  \"components.UserProfile.emptywatchlist\": \"您的 <PlexWatchlistSupportLink>Plex 關注列表</PlexWatchlistSupportLink>中的媒體會顯示在這裡。\",\n  \"components.Discover.emptywatchlist\": \"您的 <PlexWatchlistSupportLink>Plex 關注列表</PlexWatchlistSupportLink>中的媒體會顯示在這裡。\",\n  \"components.Settings.advancedTooltip\": \"錯誤的設定可能會破壞應用程式功能\",\n  \"components.Settings.experimentalTooltip\": \"啟用此設定可能會出現意外的應用程式行為\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleCurrent\": \"目前的頻率\",\n  \"components.TvDetails.Season.noepisodes\": \"没有剧集列表。\",\n  \"components.Discover.CreateSlider.providetmdbgenreid\": \"提供一個 TMDB 類型 ID\",\n  \"components.Discover.CreateSlider.nooptions\": \"沒有結果。\",\n  \"components.Discover.CreateSlider.providetmdbkeywordid\": \"提供一個 TMDB 關鍵字 ID\",\n  \"components.Discover.CreateSlider.needresults\": \"您必須至少擁有一個結果。\",\n  \"components.Discover.FilterSlideover.tmdbuserscore\": \"TMDB 使用者評分\",\n  \"components.Discover.tmdbsearch\": \"TMDB 搜尋\",\n  \"components.Discover.CreateSlider.providetmdbsearch\": \"提供一個搜尋詞\",\n  \"components.Discover.CreateSlider.searchStudios\": \"搜尋工作室…\",\n  \"components.Discover.CreateSlider.providetmdbnetwork\": \"提供一個 TMDB 影視平台 ID\",\n  \"components.Discover.CreateSlider.providetmdbstudio\": \"提供一個 TMDB 工作室 ID\",\n  \"components.Discover.CreateSlider.searchGenres\": \"搜尋種類…\",\n  \"components.Discover.CreateSlider.searchKeywords\": \"搜尋關鍵字…\",\n  \"components.Discover.DiscoverTv.discovertv\": \"影集\",\n  \"components.Discover.FilterSlideover.studio\": \"工作室\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingDesc\": \"TMDB 評分降序排列\",\n  \"components.Discover.DiscoverTv.sortTitleDesc\": \"標題字母 (Z-A) 降序排列\",\n  \"components.Discover.FilterSlideover.firstAirDate\": \"首集播映日期\",\n  \"components.Discover.FilterSlideover.releaseDate\": \"發行日期\",\n  \"components.Discover.FilterSlideover.to\": \"到\",\n  \"components.Discover.DiscoverMovies.sortTmdbRatingAsc\": \"TMDB 評分升序排列\",\n  \"components.Discover.DiscoverMovies.discovermovies\": \"電影\",\n  \"components.Discover.DiscoverMovies.sortPopularityAsc\": \"人氣升序排列\",\n  \"components.Discover.DiscoverMovies.sortPopularityDesc\": \"人氣降序排列\",\n  \"components.Discover.FilterSlideover.from\": \"從\",\n  \"components.Discover.FilterSlideover.genres\": \"種類\",\n  \"components.Discover.FilterSlideover.keywords\": \"關鍵字\",\n  \"components.Discover.FilterSlideover.runtime\": \"播放時間\",\n  \"components.Discover.DiscoverMovies.sortTitleDesc\": \"標題字母 (Z-A) 降序排列\",\n  \"components.Discover.FilterSlideover.originalLanguage\": \"原始語言\",\n  \"components.Discover.customizediscover\": \"客製化「探索」\",\n  \"components.Discover.CreateSlider.addSlider\": \"新增模塊\",\n  \"components.Discover.CreateSlider.addcustomslider\": \"建立客製化模塊\",\n  \"components.Discover.CreateSlider.addfail\": \"新建模塊失敗。\",\n  \"components.Discover.FilterSlideover.ratingText\": \"介於 {minValue} 和 {maxValue} 之間的評分\",\n  \"components.Discover.CreateSlider.addsuccess\": \"成功建立新模塊並儲存客製化設定。\",\n  \"components.Discover.DiscoverTv.sortPopularityAsc\": \"人氣升序排列\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingAsc\": \"TMDB 評分升序排列\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateAsc\": \"最早播映日期升序排列\",\n  \"components.Discover.DiscoverTv.sortFirstAirDateDesc\": \"最早播映日期降序排列\",\n  \"components.Discover.DiscoverTv.sortPopularityDesc\": \"人氣降序排列\",\n  \"components.Discover.DiscoverTv.sortTmdbRatingDesc\": \"TMDB 評分降序排列\",\n  \"components.Discover.DiscoverSliderEdit.deletefail\": \"刪除模塊失敗。\",\n  \"components.Discover.CreateSlider.editfail\": \"編輯模塊失敗。\",\n  \"components.DownloadBlock.formattedTitle\": \"{title}: 第{seasonNumber}季第{episodeNumber}集\",\n  \"components.Discover.CreateSlider.editSlider\": \"編輯模塊\",\n  \"components.Discover.CreateSlider.editsuccess\": \"成功編輯模塊並儲存「探索」客製化設定。\",\n  \"components.Discover.DiscoverSliderEdit.deletesuccess\": \"成功刪除模塊。\",\n  \"components.Discover.createnewslider\": \"新建模塊\",\n  \"components.Settings.SettingsJobsCache.imagecacheDescription\": \"當啟用此設定，Jellyseerr 將會代理並快取來自預設外部來源的影像。快取的影像將會儲存到您的設定資料夾中。您可以在<code>{appDataPath}/cache/images</code>找到這些檔案。\",\n  \"components.Settings.SettingsJobsCache.imagecachecount\": \"快取的影像\",\n  \"components.Discover.PlexWatchlistSlider.emptywatchlist\": \"新增到您 <PlexWatchlistSupportLink>Plex 觀看清單</PlexWatchlistSupportLink> 的媒體將會在這裡顯示。\",\n  \"components.Discover.resettodefault\": \"重置為預設\",\n  \"components.Discover.tmdbtvgenre\": \"TMDB 影集類型\",\n  \"components.Layout.Sidebar.browsemovies\": \"電影\",\n  \"components.Selector.searchKeywords\": \"搜尋關鍵字…\",\n  \"components.Selector.showmore\": \"顯示更多\",\n  \"components.Layout.Sidebar.browsetv\": \"影集\",\n  \"components.Selector.searchGenres\": \"選擇種類…\",\n  \"components.Selector.searchStudios\": \"搜尋工作室…\",\n  \"components.Selector.nooptions\": \"沒有結果。\",\n  \"components.Selector.showless\": \"檢視較少\",\n  \"components.Selector.starttyping\": \"輸入文字以開始搜尋。\",\n  \"components.Settings.SettingsJobsCache.imagecache\": \"影像快取\",\n  \"components.Settings.SettingsJobsCache.image-cache-cleanup\": \"清理影像快取\",\n  \"components.Settings.SettingsMain.hideAvailable\": \"隱藏可觀看的媒體\",\n  \"components.Settings.SettingsMain.locale\": \"顯示語言\",\n  \"components.Discover.resetsuccess\": \"成功重設「探索」客製化設定。\",\n  \"components.Settings.SettingsMain.toastApiKeySuccess\": \"成功產生 API 密鑰！\",\n  \"components.Settings.SettingsMain.toastSettingsFailure\": \"儲存設定時發生問題。\",\n  \"components.Settings.SettingsMain.toastSettingsSuccess\": \"設定儲存成功！\",\n  \"components.Settings.SettingsMain.validationApplicationUrl\": \"請輸入有效的網址\",\n  \"components.Settings.SettingsMain.validationApplicationTitle\": \"請輸入應用程式名稱\",\n  \"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash\": \"請刪除結尾斜線\",\n  \"components.Discover.DiscoverMovieKeyword.keywordMovies\": \"{keywordTitle} 電影\",\n  \"components.Discover.tmdbtvkeyword\": \"TMDB 影集關鍵字\",\n  \"components.Discover.tvgenres\": \"影集種類\",\n  \"components.Settings.SettingsMain.apikey\": \"API 密鑰\",\n  \"components.Settings.SettingsMain.applicationTitle\": \"應用程式名稱\",\n  \"components.Discover.CreateSlider.slidernameplaceholder\": \"模塊名稱\",\n  \"components.Discover.CreateSlider.starttyping\": \"輸入文字以搜尋。\",\n  \"components.Discover.CreateSlider.validationDatarequired\": \"您必須提供一個資料值。\",\n  \"components.Discover.CreateSlider.validationTitlerequired\": \"您必須提供一個標題。\",\n  \"components.Discover.DiscoverSliderEdit.enable\": \"切換顯示\",\n  \"components.Discover.DiscoverSliderEdit.remove\": \"移除\",\n  \"components.Discover.DiscoverMovies.sortTitleAsc\": \"標題字母 (A-Z) 升序排列\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateAsc\": \"發行日期升序排列\",\n  \"components.Discover.DiscoverMovies.sortReleaseDateDesc\": \"發行日期降序排列\",\n  \"components.Discover.DiscoverTvKeyword.keywordSeries\": \"{keywordTitle} 影集\",\n  \"components.Discover.DiscoverTv.sortTitleAsc\": \"標題字母 (A-Z) 升序排列\",\n  \"components.Discover.FilterSlideover.clearfilters\": \"清除現行過濾器\",\n  \"components.Discover.FilterSlideover.filters\": \"過濾器\",\n  \"components.Discover.FilterSlideover.runtimeText\": \"{minValue}-{maxValue} 分鐘的播放時間\",\n  \"components.Discover.PlexWatchlistSlider.plexwatchlist\": \"您的 Plex 觀看清單\",\n  \"components.Discover.RecentlyAddedSlider.recentlyAdded\": \"最近新增\",\n  \"components.Discover.moviegenres\": \"電影種類\",\n  \"components.Discover.networks\": \"影視平台\",\n  \"components.Discover.resetfailed\": \"重設「探索」客製化設定時發生錯誤。\",\n  \"components.Discover.resetwarning\": \"所有模塊已重置為預設。這將同時刪除所有客製模塊！\",\n  \"components.Discover.stopediting\": \"停止編輯\",\n  \"components.Discover.studios\": \"工作室\",\n  \"components.Discover.tmdbmoviegenre\": \"TMDB 電影種類\",\n  \"components.Discover.tmdbmoviekeyword\": \"TMDB 電影關鍵字\",\n  \"components.Discover.tmdbnetwork\": \"TMDB 影視平台\",\n  \"components.Discover.tmdbstudio\": \"TMDB 工作室\",\n  \"components.Discover.updatefailed\": \"更新「探索」客製化設定時發生錯誤。\",\n  \"components.Discover.updatesuccess\": \"已更新「探索」客製化設定。\",\n  \"components.RequestCard.unknowntitle\": \"未知標題\",\n  \"components.RequestList.RequestItem.unknowntitle\": \"未知標題\",\n  \"components.Settings.SettingsMain.general\": \"一般\",\n  \"components.Settings.SettingsMain.generalsettings\": \"一般設定\",\n  \"components.Settings.SettingsMain.generalsettingsDescription\": \"Jellyseerr 的全域與預設設定。\",\n  \"components.Settings.SettingsMain.originallanguage\": \"「探索」語言\",\n  \"components.Settings.SettingsMain.originallanguageTip\": \"根據原始語言過濾內容\",\n  \"components.Settings.SettingsMain.partialRequestsEnabled\": \"允許不完整的影集請求\",\n  \"components.Settings.SettingsMain.toastApiKeyFailure\": \"產生 API 密鑰時發生問題。\",\n  \"components.StatusBadge.seasonepisodenumber\": \"S{seasonNumber}E{episodeNumber}\",\n  \"components.Discover.FilterSlideover.streamingservices\": \"串流服務\",\n  \"components.Settings.SettingsJobsCache.imagecachesize\": \"總快取大小\",\n  \"components.Settings.SettingsMain.applicationurl\": \"應用程式網址\",\n  \"components.Settings.SettingsMain.cacheImages\": \"啟用影像快取\",\n  \"components.Settings.SettingsMain.cacheImagesTip\": \"快取外部來源影像（需要大量磁碟空間）\",\n  \"components.Discover.DiscoverMovies.activefilters\": \"{count, plural, one {# 個使用中的篩選項目} other {# 個使用中的篩選項目}}\",\n  \"components.Discover.DiscoverTv.activefilters\": \"{count, plural, one {# 個使用中的篩選項目} other {# 個使用中的篩選項目}}\",\n  \"components.Discover.FilterSlideover.activefilters\": \"{count, plural, one {# 個使用中的篩選項目} other {# 個使用中的篩選項目}}\",\n  \"components.Discover.FilterSlideover.tmdbuservotecount\": \"TMDB 用戶評分數\",\n  \"components.Discover.FilterSlideover.voteCount\": \"在 {minValue} 和 {maxValue} 之間的評分數\",\n  \"components.Discover.tmdbmoviestreamingservices\": \"TMDB 電影串流服務\",\n  \"components.Settings.Notifications.NotificationsPushover.deviceDefault\": \"預設裝置\",\n  \"components.Settings.Notifications.NotificationsPushover.sound\": \"通知提示聲\",\n  \"components.Discover.tmdbtvstreamingservices\": \"TMDB 電視串流服務\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorSeconds\": \"每 {jobScheduleSeconds} 秒\",\n  \"components.Settings.SettingsJobsCache.availability-sync\": \"同步媒體可用性\",\n  \"components.Settings.SonarrModal.seriesType\": \"劇集類型\",\n  \"components.Settings.SonarrModal.tagRequests\": \"標記請求\",\n  \"components.Settings.SonarrModal.tagRequestsInfo\": \"自動新增帶有請求者的用户 ID 和顯示名稱的附加標籤\",\n  \"components.Settings.RadarrModal.tagRequests\": \"標籤請求\",\n  \"components.Settings.RadarrModal.tagRequestsInfo\": \"自動新增帶有請求者的用户 ID 和顯示名稱的附加標籤\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.sound\": \"通知提示聲\",\n  \"i18n.collection\": \"合集\",\n  \"components.MovieDetails.imdbuserscore\": \"IMDB 用戶評分\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault\": \"預設裝置\",\n  \"components.Settings.SonarrModal.animeSeriesType\": \"動漫劇集類型\",\n  \"components.Discover.FilterSlideover.certification\": \"\",\n  \"components.Discover.FilterSlideover.excludeKeywords\": \"\",\n  \"components.DiscoverTvUpcoming.upcomingtv\": \"\",\n  \"components.IssueList.IssueItem.descriptionpreview\": \"\",\n  \"components.Layout.UserWarnings.emailInvalid\": \"Email 不正確\",\n  \"components.Layout.UserWarnings.emailRequired\": \"請填入 Email\",\n  \"components.Layout.UserWarnings.passwordRequired\": \"請填入密碼\",\n  \"components.Login.adminerror\": \"\",\n  \"components.Login.back\": \"\",\n  \"components.Login.credentialerror\": \"使用者名稱或密碼錯誤\",\n  \"components.Login.description\": \"\",\n  \"components.Login.emailtooltip\": \"\",\n  \"components.Login.enablessl\": \"\",\n  \"components.Login.hostname\": \"\",\n  \"components.Login.initialsigningin\": \"\",\n  \"components.Login.invalidurlerror\": \"\",\n  \"components.Login.loginwithapp\": \"\",\n  \"components.Login.noadminerror\": \"\",\n  \"components.Login.orsigninwith\": \"\",\n  \"components.Login.port\": \"\",\n  \"components.Login.save\": \"\",\n  \"components.Login.saving\": \"\",\n  \"components.Login.servertype\": \"\",\n  \"components.Login.signinwithjellyfin\": \"\",\n  \"components.Login.title\": \"\",\n  \"components.Login.urlBase\": \"\",\n  \"components.Login.username\": \"使用者名稱\",\n  \"components.Login.validationEmailFormat\": \"\",\n  \"components.Login.validationPortRequired\": \"\",\n  \"components.Login.validationUrlBaseLeadingSlash\": \"\",\n  \"components.Login.validationUrlBaseTrailingSlash\": \"\",\n  \"components.Login.validationUrlTrailingSlash\": \"\",\n  \"components.Login.validationemailformat\": \"\",\n  \"components.Login.validationhostformat\": \"\",\n  \"components.Login.validationhostrequired\": \"\",\n  \"components.Login.validationservertyperequired\": \"\",\n  \"components.Login.validationusernamerequired\": \"\",\n  \"components.ManageSlideOver.manageModalRemoveMediaWarning\": \"\",\n  \"components.ManageSlideOver.removearr\": \"\",\n  \"components.ManageSlideOver.removearr4k\": \"\",\n  \"components.MetadataSelector.selectMetdataProvider\": \"\",\n  \"components.MetadataSelector.tmdbLabel\": \"\",\n  \"components.MetadataSelector.tvdbLabel\": \"\",\n  \"components.MovieDetails.addtowatchlist\": \"\",\n  \"components.MovieDetails.downloadstatus\": \"\",\n  \"components.MovieDetails.openradarr\": \"\",\n  \"components.MovieDetails.openradarr4k\": \"\",\n  \"components.MovieDetails.play\": \"\",\n  \"components.MovieDetails.play4k\": \"\",\n  \"components.MovieDetails.removefromwatchlist\": \"\",\n  \"components.MovieDetails.watchlistDeleted\": \"\",\n  \"components.MovieDetails.watchlistError\": \"\",\n  \"components.MovieDetails.watchlistSuccess\": \"\",\n  \"components.RequestList.RequestItem.profileName\": \"\",\n  \"components.RequestList.RequestItem.removearr\": \"\",\n  \"components.RequestList.sortDirection\": \"\",\n  \"components.Selector.CertificationSelector.errorLoading\": \"\",\n  \"components.Selector.CertificationSelector.maxRating\": \"\",\n  \"components.Selector.CertificationSelector.minRating\": \"\",\n  \"components.Selector.CertificationSelector.noOptions\": \"\",\n  \"components.Selector.CertificationSelector.selectCertification\": \"\",\n  \"components.Selector.CertificationSelector.selectCountry\": \"\",\n  \"components.Selector.CertificationSelector.starttyping\": \"\",\n  \"components.Selector.canceled\": \"\",\n  \"components.Selector.ended\": \"\",\n  \"components.Selector.inProduction\": \"\",\n  \"components.Selector.pilot\": \"\",\n  \"components.Selector.planned\": \"\",\n  \"components.Selector.returningSeries\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.priority\": \"\",\n  \"components.Settings.Notifications.NotificationsGotify.validationPriorityRequired\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.agentenabled\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.password\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestFailed\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSending\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.toastNtfyTestSuccess\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.token\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.tokenAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.topic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.url\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.username\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.usernamePasswordAuth\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyTopic\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationNtfyUrl\": \"\",\n  \"components.Settings.Notifications.NotificationsNtfy.validationTypes\": \"\",\n  \"components.Settings.Notifications.NotificationsPushover.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsSlack.embedPoster\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariables\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.supportVariablesTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebhook.webhookUrlTip\": \"\",\n  \"components.Settings.Notifications.NotificationsWebPush.embedPoster\": \"\",\n  \"components.Settings.Notifications.embedPoster\": \"\",\n  \"components.Settings.Notifications.messageThreadId\": \"\",\n  \"components.Settings.Notifications.messageThreadIdTip\": \"\",\n  \"components.Settings.Notifications.userEmailRequired\": \"\",\n  \"components.Settings.Notifications.validationMessageThreadId\": \"\",\n  \"components.Settings.Notifications.validationWebhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleId\": \"\",\n  \"components.Settings.Notifications.webhookRoleIdTip\": \"\",\n  \"components.Settings.OverrideRuleModal.conditions\": \"\",\n  \"components.Settings.OverrideRuleModal.conditionsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.create\": \"\",\n  \"components.Settings.OverrideRuleModal.createrule\": \"\",\n  \"components.Settings.OverrideRuleModal.editrule\": \"\",\n  \"components.Settings.OverrideRuleModal.genres\": \"\",\n  \"components.Settings.OverrideRuleModal.keywords\": \"\",\n  \"components.Settings.OverrideRuleModal.languages\": \"\",\n  \"components.Settings.OverrideRuleModal.notagoptions\": \"\",\n  \"components.Settings.OverrideRuleModal.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleModal.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleCreated\": \"\",\n  \"components.Settings.OverrideRuleModal.ruleUpdated\": \"\",\n  \"components.Settings.OverrideRuleModal.selectQualityProfile\": \"\",\n  \"components.Settings.OverrideRuleModal.selectRootFolder\": \"\",\n  \"components.Settings.OverrideRuleModal.selectService\": \"\",\n  \"components.Settings.OverrideRuleModal.selecttags\": \"\",\n  \"components.Settings.OverrideRuleModal.service\": \"\",\n  \"components.Settings.OverrideRuleModal.serviceDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.settings\": \"\",\n  \"components.Settings.OverrideRuleModal.settingsDescription\": \"\",\n  \"components.Settings.OverrideRuleModal.tags\": \"\",\n  \"components.Settings.OverrideRuleModal.users\": \"\",\n  \"components.Settings.OverrideRuleTile.conditions\": \"\",\n  \"components.Settings.OverrideRuleTile.genre\": \"\",\n  \"components.Settings.OverrideRuleTile.keywords\": \"\",\n  \"components.Settings.OverrideRuleTile.language\": \"\",\n  \"components.Settings.OverrideRuleTile.qualityprofile\": \"\",\n  \"components.Settings.OverrideRuleTile.rootfolder\": \"\",\n  \"components.Settings.OverrideRuleTile.settings\": \"\",\n  \"components.Settings.OverrideRuleTile.tags\": \"\",\n  \"components.Settings.OverrideRuleTile.users\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCache\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStats\": \"\",\n  \"components.Settings.SettingsJobsCache.dnsCacheGlobalStatsDescription\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheactiveaddress\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheage\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscacheflushed\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachehits\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachemisses\": \"\",\n  \"components.Settings.SettingsJobsCache.dnscachename\": \"\",\n  \"components.Settings.SettingsJobsCache.editJobScheduleSelectorDays\": \"\",\n  \"components.Settings.SettingsJobsCache.failures\": \"\",\n  \"components.Settings.SettingsJobsCache.flushdnscache\": \"\",\n  \"components.Settings.SettingsJobsCache.hitRate\": \"\",\n  \"components.Settings.SettingsJobsCache.hits\": \"\",\n  \"components.Settings.SettingsJobsCache.ipv4Fallbacks\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-full-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.jellyfin-recently-added-scan\": \"\",\n  \"components.Settings.SettingsJobsCache.misses\": \"\",\n  \"components.Settings.SettingsJobsCache.plex-refresh-token\": \"\",\n  \"components.Settings.SettingsJobsCache.size\": \"\",\n  \"components.Settings.SettingsJobsCache.usersavatars\": \"\",\n  \"components.Settings.SettingsMain.apikeyCopied\": \"\",\n  \"components.Settings.SettingsMain.discoverRegion\": \"\",\n  \"components.Settings.SettingsMain.discoverRegionTip\": \"\",\n  \"components.Settings.SettingsMain.enableSpecialEpisodes\": \"\",\n  \"components.Settings.SettingsMain.hideAvailableTip\": \"\",\n  \"components.Settings.SettingsMain.streamingRegion\": \"\",\n  \"components.Settings.SettingsMain.validationUrl\": \"\",\n  \"components.Settings.SettingsMain.validationUrlTrailingSlash\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrl\": \"\",\n  \"components.Settings.SettingsMain.youtubeUrlTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtection\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.csrfProtectionTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCache\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheForceMinTtl\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheHoverTip\": \"\",\n  \"components.Settings.SettingsNetwork.dnsCacheTip\": \"\",\n  \"components.Settings.SettingsNetwork.docs\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4First\": \"\",\n  \"components.Settings.SettingsNetwork.forceIpv4FirstTip\": \"\",\n  \"components.Settings.SettingsNetwork.network\": \"\",\n  \"components.Settings.SettingsNetwork.networkDisclaimer\": \"\",\n  \"components.Settings.SettingsNetwork.networksettings\": \"\",\n  \"components.Settings.SettingsNetwork.networksettingsDescription\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilter\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassFilterTip\": \"\",\n  \"components.Settings.SettingsNetwork.proxyBypassLocalAddresses\": \"\",\n  \"components.Settings.SettingsNetwork.proxyEnabled\": \"\",\n  \"components.Settings.SettingsNetwork.proxyHostname\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPassword\": \"\",\n  \"components.Settings.SettingsNetwork.proxyPort\": \"\",\n  \"components.Settings.SettingsNetwork.proxySsl\": \"\",\n  \"components.Settings.SettingsNetwork.proxyUser\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsFailure\": \"\",\n  \"components.Settings.SettingsNetwork.toastSettingsSuccess\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxy\": \"\",\n  \"components.Settings.SettingsNetwork.trustProxyTip\": \"\",\n  \"components.Settings.SettingsNetwork.validationProxyPort\": \"\",\n  \"components.Settings.SettingsUsers.atLeastOneAuth\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLogin\": \"\",\n  \"components.Settings.SettingsUsers.mediaServerLoginTip\": \"\",\n  \"components.Settings.addrule\": \"\",\n  \"components.Settings.allChosenProvidersAreOperational\": \"\",\n  \"components.Settings.animeMetadataProvider\": \"\",\n  \"components.Settings.apiKey\": \"\",\n  \"components.Settings.chooseProvider\": \"\",\n  \"components.Settings.clickTest\": \"\",\n  \"components.Settings.connectionTestFailed\": \"\",\n  \"components.Settings.failed\": \"\",\n  \"components.Settings.failedToSaveMetadataSettings\": \"\",\n  \"components.Settings.general\": \"\",\n  \"components.Settings.invalidKeyword\": \"\",\n  \"components.Settings.invalidurlerror\": \"\",\n  \"components.Settings.jellyfinForgotPasswordUrl\": \"\",\n  \"components.Settings.jellyfinSettings\": \"\",\n  \"components.Settings.jellyfinSettingsDescription\": \"\",\n  \"components.Settings.jellyfinSettingsFailure\": \"\",\n  \"components.Settings.jellyfinSettingsSuccess\": \"\",\n  \"components.Settings.jellyfinSyncFailedAutomaticGroupedFolders\": \"\",\n  \"components.Settings.jellyfinSyncFailedGenericError\": \"\",\n  \"components.Settings.jellyfinSyncFailedNoLibrariesFound\": \"\",\n  \"components.Settings.jellyfinlibraries\": \"\",\n  \"components.Settings.jellyfinlibrariesDescription\": \"\",\n  \"components.Settings.jellyfinsettings\": \"\",\n  \"components.Settings.jellyfinsettingsDescription\": \"\",\n  \"components.Settings.manualscanDescriptionJellyfin\": \"\",\n  \"components.Settings.manualscanJellyfin\": \"\",\n  \"components.Settings.menuJellyfinSettings\": \"\",\n  \"components.Settings.menuMetadataProviders\": \"\",\n  \"components.Settings.menuNetwork\": \"\",\n  \"components.Settings.metadataProviderSelection\": \"\",\n  \"components.Settings.metadataProviderSettings\": \"\",\n  \"components.Settings.metadataSettings\": \"\",\n  \"components.Settings.metadataSettingsSaved\": \"\",\n  \"components.Settings.no\": \"\",\n  \"components.Settings.noSpecialCharacters\": \"\",\n  \"components.Settings.nooptions\": \"\",\n  \"components.Settings.notTested\": \"\",\n  \"components.Settings.operational\": \"\",\n  \"components.Settings.overrideRules\": \"\",\n  \"components.Settings.overrideRulesDescription\": \"\",\n  \"components.Settings.providerStatus\": \"\",\n  \"components.Settings.save\": \"\",\n  \"components.Settings.saving\": \"\",\n  \"components.Settings.scanbackground\": \"\",\n  \"components.Settings.searchKeywords\": \"\",\n  \"components.Settings.seriesMetadataProvider\": \"\",\n  \"components.Settings.settings\": \"\",\n  \"components.Settings.starttyping\": \"\",\n  \"components.Settings.syncJellyfin\": \"\",\n  \"components.Settings.syncing\": \"\",\n  \"components.Settings.timeout\": \"\",\n  \"components.Settings.tip\": \"\",\n  \"components.Settings.tmdbProviderDoesnotWork\": \"\",\n  \"components.Settings.tvdbProviderDoesnotWork\": \"\",\n  \"components.Settings.valueRequired\": \"\",\n  \"components.Settings.yes\": \"\",\n  \"components.Setup.back\": \"\",\n  \"components.Setup.configemby\": \"\",\n  \"components.Setup.configjellyfin\": \"\",\n  \"components.Setup.configplex\": \"\",\n  \"components.Setup.configuremediaserver\": \"\",\n  \"components.Setup.librarieserror\": \"\",\n  \"components.Setup.servertype\": \"\",\n  \"components.Setup.signin\": \"\",\n  \"components.Setup.signinWithEmby\": \"\",\n  \"components.Setup.signinWithJellyfin\": \"\",\n  \"components.Setup.signinWithPlex\": \"\",\n  \"components.Setup.subtitle\": \"\",\n  \"components.StatusBadge.seasonnumber\": \"\",\n  \"components.TitleCard.addToWatchList\": \"\",\n  \"components.TitleCard.watchlistCancel\": \"\",\n  \"components.TitleCard.watchlistDeleted\": \"\",\n  \"components.TitleCard.watchlistError\": \"\",\n  \"components.TitleCard.watchlistSuccess\": \"\",\n  \"components.TvDetails.addtowatchlist\": \"\",\n  \"components.TvDetails.play\": \"\",\n  \"components.TvDetails.play4k\": \"\",\n  \"components.TvDetails.removefromwatchlist\": \"\",\n  \"components.TvDetails.watchlistDeleted\": \"\",\n  \"components.TvDetails.watchlistError\": \"\",\n  \"components.TvDetails.watchlistSuccess\": \"\",\n  \"components.UserList.importedfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfin\": \"\",\n  \"components.UserList.importfromJellyfinerror\": \"\",\n  \"components.UserList.importfrommediaserver\": \"\",\n  \"components.UserList.mediaServerUser\": \"\",\n  \"components.UserList.newJellyfinsigninenabled\": \"\",\n  \"components.UserList.noJellyfinuserstoimport\": \"\",\n  \"components.UserList.username\": \"\",\n  \"components.UserList.validationUsername\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.description\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorExists\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.password\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.passwordRequired\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.save\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.saving\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.title\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.username\": \"\",\n  \"components.UserProfile.UserSettings.LinkJellyfinModal.usernameRequired\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegion\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.discoverRegionTip\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.email\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.mediaServerUser\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.save\": \"儲存變更\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.saving\": \"儲存中…\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegion\": \"串流地區\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.streamingRegionTip\": \"顯示各個地區可收看的平台\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmail\": \"此電子郵件地址已被使用！\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailureEmailEmpty\": \"此使用者名稱已被佔用，請先設定您的電子郵件。\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat\": \"\",\n  \"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.deleteFailed\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.errorUnknown\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.noPermissionDescription\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorExists\": \"\",\n  \"components.UserProfile.UserSettings.UserLinkedAccountsSettings.plexErrorUnauthorized\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.unknown\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled\": \"已停用網頁推播\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled\": \"已啟用網頁推播\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed\": \"無法儲存網頁推播通知設定\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved\": \"已儲存網頁推播通知設定\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId\": \"\",\n  \"components.UserProfile.UserSettings.menuLinkedAccounts\": \"帳號連結\",\n  \"components.UserProfile.localWatchlist\": \"{username}的收藏清單\",\n  \"i18n.completed\": \"已完成\",\n  \"i18n.deleted\": \"已刪除\",\n  \"i18n.specials\": \"\",\n  \"components.Discover.FilterSlideover.status\": \"\",\n  \"components.Login.initialsignin\": \"\",\n  \"components.Login.validationEmailRequired\": \"\",\n  \"components.Selector.searchStatus\": \"\",\n  \"components.Selector.searchUsers\": \"\",\n  \"components.Settings.SettingsMain.streamingRegionTip\": \"\",\n  \"components.Settings.SettingsUsers.loginMethods\": \"\",\n  \"components.Settings.SettingsUsers.loginMethodsTip\": \"\",\n  \"components.Settings.SettingsAbout.aboutseerr\": \"\",\n  \"components.Settings.SettingsAbout.contribute\": \"\",\n  \"components.Settings.SettingsAbout.supportseerr\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMaxTtl\": \"\",\n  \"components.Settings.SettingsNetwork.validationDnsCacheMinTtl\": \"\",\n  \"components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.activesubscription\": \"\",\n  \"component.BlocklistBlock.blocklistdate\": \"封鎖日期\",\n  \"component.BlocklistBlock.blocklistedby\": \"封鎖者\",\n  \"component.BlocklistModal.blocklisting\": \"封鎖清單\",\n  \"components.Blocklist.blocklistNotFoundError\": \"<strong>{title}</strong> 不在封鎖清單\",\n  \"components.Blocklist.blocklistSettingsDescription\": \"管理已封鎖媒體\",\n  \"components.Blocklist.blocklistdate\": \"日期\",\n  \"components.Blocklist.blocklistedby\": \"{date} 由 {user} 封鎖\",\n  \"components.Blocklist.showAllBlocklisted\": \"顯示所有封鎖媒體\",\n  \"components.Layout.Sidebar.blocklist\": \"封鎖\",\n  \"components.Blocklist.blocklistsettings\": \"封鎖清單設定\",\n  \"components.Blocklist.filterBlocklistedTags\": \"封鎖清單標籤\",\n  \"components.Blocklist.filterManual\": \"手動\",\n  \"i18n.removefromBlocklist\": \"取消封鎖\",\n  \"i18n.removeFromBlocklistSuccess\": \"<strong>{title}</strong> 已從封鎖名單中移除\",\n  \"i18n.blocklisted\": \"已封鎖\",\n  \"i18n.blocklistSuccess\": \"已將 <strong>{title}</strong> 加入封鎖清單\",\n  \"i18n.blocklistError\": \"啊！出了點問題，請再試一次。\",\n  \"i18n.blocklistDuplicateError\": \"<strong>{title}</strong> 已經在封鎖清單中\",\n  \"i18n.blocklist\": \"封鎖\",\n  \"i18n.addToBlocklist\": \"加到封鎖清單\"\n}\n"
  },
  {
    "path": "src/pages/404.tsx",
    "content": "import PageTitle from '@app/components/Common/PageTitle';\nimport defineMessages from '@app/utils/defineMessages';\nimport { ArrowRightCircleIcon } from '@heroicons/react/24/outline';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\n\nconst messages = defineMessages('pages', {\n  errormessagewithcode: '{statusCode} - {error}',\n  pagenotfound: 'Page Not Found',\n  returnHome: 'Return Home',\n});\n\nconst Custom404 = () => {\n  const intl = useIntl();\n\n  return (\n    <div className=\"error-message\">\n      <PageTitle title={intl.formatMessage(messages.pagenotfound)} />\n      <div className=\"text-4xl\">\n        {intl.formatMessage(messages.errormessagewithcode, {\n          statusCode: 404,\n          error: intl.formatMessage(messages.pagenotfound),\n        })}\n      </div>\n      <Link href=\"/\" className=\"mt-2 flex\">\n        {intl.formatMessage(messages.returnHome)}\n        <ArrowRightCircleIcon className=\"ml-2 h-6 w-6\" />\n      </Link>\n    </div>\n  );\n};\n\nexport default Custom404;\n"
  },
  {
    "path": "src/pages/_app.tsx",
    "content": "import Layout from '@app/components/Layout';\nimport LoadingBar from '@app/components/LoadingBar';\nimport PWAHeader from '@app/components/PWAHeader';\nimport ServiceWorkerSetup from '@app/components/ServiceWorkerSetup';\nimport StatusChecker from '@app/components/StatusChecker';\nimport Toast from '@app/components/Toast';\nimport ToastContainer from '@app/components/ToastContainer';\nimport { InteractionProvider } from '@app/context/InteractionContext';\nimport { LanguageContext } from '@app/context/LanguageContext';\nimport { SettingsProvider } from '@app/context/SettingsContext';\nimport { UserContext } from '@app/context/UserContext';\nimport type { User } from '@app/hooks/useUser';\nimport { Permission, useUser } from '@app/hooks/useUser';\nimport '@app/styles/globals.css';\nimport { polyfillIntl } from '@app/utils/polyfillIntl';\nimport '@fontsource-variable/inter';\nimport { MediaServerType } from '@server/constants/server';\nimport type { PublicSettingsResponse } from '@server/interfaces/api/settingsInterfaces';\nimport type { AvailableLocale } from '@server/types/languages';\nimport axios from 'axios';\nimport type { AppInitialProps, AppProps } from 'next/app';\nimport App from 'next/app';\nimport Head from 'next/head';\nimport { useEffect, useState } from 'react';\nimport { IntlProvider } from 'react-intl';\nimport { ToastProvider } from 'react-toast-notifications';\nimport { SWRConfig } from 'swr';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst loadLocaleData = (locale: AvailableLocale): Promise<any> => {\n  switch (locale) {\n    case 'ar':\n      return import('../i18n/locale/ar.json');\n    case 'bg':\n      return import('../i18n/locale/bg.json');\n    case 'ca':\n      return import('../i18n/locale/ca.json');\n    case 'cs':\n      return import('../i18n/locale/cs.json');\n    case 'da':\n      return import('../i18n/locale/da.json');\n    case 'de':\n      return import('../i18n/locale/de.json');\n    case 'el':\n      return import('../i18n/locale/el.json');\n    case 'es':\n      return import('../i18n/locale/es.json');\n    case 'es-MX':\n      return import('../i18n/locale/es_MX.json');\n    case 'fi':\n      return import('../i18n/locale/fi.json');\n    case 'fr':\n      return import('../i18n/locale/fr.json');\n    case 'he':\n      return import('../i18n/locale/he.json');\n    case 'hi':\n      return import('../i18n/locale/hi.json');\n    case 'hr':\n      return import('../i18n/locale/hr.json');\n    case 'hu':\n      return import('../i18n/locale/hu.json');\n    case 'it':\n      return import('../i18n/locale/it.json');\n    case 'ja':\n      return import('../i18n/locale/ja.json');\n    case 'ko':\n      return import('../i18n/locale/ko.json');\n    case 'lb':\n      return import('../i18n/locale/lb.json');\n    case 'lt':\n      return import('../i18n/locale/lt.json');\n    case 'nb-NO':\n      return import('../i18n/locale/nb_NO.json');\n    case 'nl':\n      return import('../i18n/locale/nl.json');\n    case 'pl':\n      return import('../i18n/locale/pl.json');\n    case 'pt-BR':\n      return import('../i18n/locale/pt_BR.json');\n    case 'pt-PT':\n      return import('../i18n/locale/pt_PT.json');\n    case 'ro':\n      return import('../i18n/locale/ro.json');\n    case 'ru':\n      return import('../i18n/locale/ru.json');\n    case 'sq':\n      return import('../i18n/locale/sq.json');\n    case 'sr':\n      return import('../i18n/locale/sr.json');\n    case 'sv':\n      return import('../i18n/locale/sv.json');\n    case 'tr':\n      return import('../i18n/locale/tr.json');\n    case 'uk':\n      return import('../i18n/locale/uk.json');\n    case 'vi':\n      return import('../i18n/locale/vi.json');\n    case 'zh-CN':\n      return import('../i18n/locale/zh_Hans.json');\n    case 'zh-TW':\n      return import('../i18n/locale/zh_Hant.json');\n    default:\n      return import('../i18n/locale/en.json');\n  }\n};\n\n// Custom types so we can correctly type our GetInitialProps function\n// with our combined user prop\n// This is specific to _app.tsx. Other pages will not need to do this!\ntype NextAppComponentType = typeof App;\ntype MessagesType = Record<string, string>;\n\ninterface ExtendedAppProps extends AppProps {\n  user: User;\n  messages: MessagesType;\n  locale: AvailableLocale;\n  currentSettings: PublicSettingsResponse;\n}\n\nconst CoreApp: Omit<NextAppComponentType, 'origGetInitialProps'> = ({\n  Component,\n  pageProps,\n  router,\n  user,\n  messages,\n  locale,\n  currentSettings,\n}: ExtendedAppProps) => {\n  let component: React.ReactNode;\n  const [loadedMessages, setMessages] = useState<MessagesType>(messages);\n  const [currentLocale, setLocale] = useState<AvailableLocale>(locale);\n\n  useEffect(() => {\n    loadLocaleData(currentLocale).then(setMessages);\n  }, [currentLocale]);\n\n  const { hasPermission } = useUser();\n\n  useEffect(() => {\n    const requestsCount = async () => {\n      const response = await axios.get('/api/v1/request/count');\n      return response.data;\n    };\n\n    // Cast navigator to a type that includes setAppBadge and clearAppBadge\n    // to avoid TypeScript errors while ensuring these methods exist before calling them.\n    const newNavigator = navigator as unknown as {\n      setAppBadge?: (count: number) => Promise<void>;\n      clearAppBadge?: () => Promise<void>;\n    };\n\n    const handleBadgeUpdate = () => {\n      if ('setAppBadge' in newNavigator) {\n        if (\n          !router.pathname.match(/(login|setup|resetpassword)/) &&\n          hasPermission(Permission.ADMIN)\n        ) {\n          requestsCount().then((data) => {\n            if (data.pending > 0) {\n              newNavigator.setAppBadge?.(data.pending);\n            } else {\n              newNavigator.clearAppBadge?.();\n            }\n          });\n        } else {\n          newNavigator.clearAppBadge?.();\n        }\n      }\n    };\n\n    handleBadgeUpdate();\n\n    window.addEventListener('focus', handleBadgeUpdate);\n\n    return () => {\n      window.removeEventListener('focus', handleBadgeUpdate);\n    };\n  }, [hasPermission, router.pathname]);\n\n  if (router.pathname.match(/(login|setup|resetpassword)/)) {\n    component = <Component {...pageProps} />;\n  } else {\n    component = (\n      <Layout>\n        <Component {...pageProps} />\n      </Layout>\n    );\n  }\n\n  return (\n    <SWRConfig\n      value={{\n        fetcher: (url) => axios.get(url).then((res) => res.data),\n        fallback: {\n          '/api/v1/auth/me': user,\n        },\n      }}\n    >\n      <LanguageContext.Provider value={{ locale: currentLocale, setLocale }}>\n        <IntlProvider\n          locale={currentLocale}\n          defaultLocale=\"en\"\n          messages={loadedMessages}\n        >\n          <LoadingBar />\n          <SettingsProvider currentSettings={currentSettings}>\n            <InteractionProvider>\n              <ToastProvider components={{ Toast, ToastContainer }}>\n                <Head>\n                  <title>{currentSettings.applicationTitle}</title>\n                  <meta\n                    name=\"viewport\"\n                    content=\"initial-scale=1, viewport-fit=cover, width=device-width\"\n                  />\n                  <PWAHeader\n                    applicationTitle={currentSettings.applicationTitle}\n                  />\n                </Head>\n                <StatusChecker />\n                <ServiceWorkerSetup />\n                <UserContext initialUser={user}>{component}</UserContext>\n              </ToastProvider>\n            </InteractionProvider>\n          </SettingsProvider>\n        </IntlProvider>\n      </LanguageContext.Provider>\n    </SWRConfig>\n  );\n};\n\nCoreApp.getInitialProps = async (initialProps) => {\n  const { ctx, router } = initialProps;\n  let user: User | undefined = undefined;\n  let currentSettings: PublicSettingsResponse = {\n    initialized: false,\n    applicationTitle: '',\n    applicationUrl: '',\n    hideAvailable: false,\n    hideBlocklisted: false,\n    movie4kEnabled: false,\n    series4kEnabled: false,\n    localLogin: true,\n    mediaServerLogin: true,\n    discoverRegion: '',\n    streamingRegion: '',\n    originalLanguage: '',\n    mediaServerType: MediaServerType.NOT_CONFIGURED,\n    partialRequestsEnabled: true,\n    enableSpecialEpisodes: false,\n    cacheImages: false,\n    vapidPublic: '',\n    enablePushRegistration: false,\n    locale: 'en',\n    emailEnabled: false,\n    newPlexLogin: true,\n    youtubeUrl: '',\n  };\n\n  if (ctx.res) {\n    // Check if app is initialized and redirect if necessary\n    const response = await axios.get<PublicSettingsResponse>(\n      `http://${process.env.HOST || 'localhost'}:${\n        process.env.PORT || 5055\n      }/api/v1/settings/public`\n    );\n\n    currentSettings = response.data;\n\n    const initialized = response.data.initialized;\n\n    if (!initialized) {\n      if (!router.pathname.match(/(setup|login\\/plex)/)) {\n        ctx.res.writeHead(307, {\n          Location: '/setup',\n        });\n        ctx.res.end();\n      }\n    } else {\n      try {\n        // Attempt to get the user by running a request to the local api\n        const response = await axios.get<User>(\n          `http://${process.env.HOST || 'localhost'}:${\n            process.env.PORT || 5055\n          }/api/v1/auth/me`,\n          {\n            headers:\n              ctx.req && ctx.req.headers.cookie\n                ? { cookie: ctx.req.headers.cookie }\n                : undefined,\n          }\n        );\n        user = response.data;\n\n        if (router.pathname.match(/(setup|login)/)) {\n          ctx.res.writeHead(307, {\n            Location: '/',\n          });\n          ctx.res.end();\n        }\n      } catch {\n        // If there is no user, and ctx.res is set (to check if we are on the server side)\n        // _AND_ we are not already on the login or setup route, redirect to /login with a 307\n        // before anything actually renders\n        if (!router.pathname.match(/(login|setup|resetpassword)/)) {\n          ctx.res.writeHead(307, {\n            Location: '/login',\n          });\n          ctx.res.end();\n        }\n      }\n    }\n  }\n\n  // Run the default getInitialProps for the main nextjs initialProps\n  const appInitialProps: AppInitialProps =\n    await App.getInitialProps(initialProps);\n\n  const locale = user?.settings?.locale\n    ? user.settings.locale\n    : currentSettings.locale;\n\n  const messages = await loadLocaleData(locale as AvailableLocale);\n  await polyfillIntl(locale);\n\n  return { ...appInitialProps, user, messages, locale, currentSettings };\n};\n\nexport default CoreApp;\n"
  },
  {
    "path": "src/pages/_document.tsx",
    "content": "import type { DocumentContext, DocumentInitialProps } from 'next/document';\nimport Document, { Head, Html, Main, NextScript } from 'next/document';\n\nclass MyDocument extends Document {\n  static async getInitialProps(\n    ctx: DocumentContext\n  ): Promise<DocumentInitialProps> {\n    const initialProps = await Document.getInitialProps(ctx);\n\n    return initialProps;\n  }\n\n  render(): JSX.Element {\n    return (\n      <Html>\n        <Head />\n        <body>\n          <Main />\n          <NextScript />\n        </body>\n      </Html>\n    );\n  }\n}\n\nexport default MyDocument;\n"
  },
  {
    "path": "src/pages/_error.tsx",
    "content": "import PageTitle from '@app/components/Common/PageTitle';\nimport defineMessages from '@app/utils/defineMessages';\nimport type { Undefinable } from '@app/utils/typeHelpers';\nimport { ArrowRightCircleIcon } from '@heroicons/react/24/outline';\nimport type { NextPage } from 'next';\nimport Link from 'next/link';\nimport { useIntl } from 'react-intl';\n\ninterface ErrorProps {\n  statusCode?: number;\n}\n\nconst messages = defineMessages('pages', {\n  errormessagewithcode: '{statusCode} - {error}',\n  internalservererror: 'Internal Server Error',\n  serviceunavailable: 'Service Unavailable',\n  somethingwentwrong: 'Something Went Wrong',\n  oops: 'Oops',\n  returnHome: 'Return Home',\n});\n\nconst ErrorPage: NextPage<ErrorProps> = ({ statusCode }) => {\n  const intl = useIntl();\n\n  const getErrorMessage = (statusCode?: number) => {\n    switch (statusCode) {\n      case 500:\n        return intl.formatMessage(messages.internalservererror);\n      case 503:\n        return intl.formatMessage(messages.serviceunavailable);\n      default:\n        return statusCode\n          ? intl.formatMessage(messages.somethingwentwrong)\n          : intl.formatMessage(messages.oops);\n    }\n  };\n  return (\n    <div className=\"error-message\">\n      <PageTitle title={getErrorMessage(statusCode)} />\n      <div className=\"text-4xl\">\n        {statusCode\n          ? intl.formatMessage(messages.errormessagewithcode, {\n              statusCode,\n              error: getErrorMessage(statusCode),\n            })\n          : getErrorMessage(statusCode)}\n      </div>\n      <Link href=\"/\" className=\"mt-2 flex\">\n        {intl.formatMessage(messages.returnHome)}\n        <ArrowRightCircleIcon className=\"ml-2 h-6 w-6\" />\n      </Link>\n    </div>\n  );\n};\n\nErrorPage.getInitialProps = async ({ res, err }): Promise<ErrorProps> => {\n  // Apologies for how gross ternary is but this is just temporary. Honestly,\n  // blame the nextjs docs\n  let statusCode: Undefinable<number>;\n  if (res) {\n    statusCode = res.statusCode;\n  } else {\n    statusCode = err ? err.statusCode : undefined;\n  }\n\n  return { statusCode };\n};\n\nexport default ErrorPage;\n"
  },
  {
    "path": "src/pages/blocklist/index.tsx",
    "content": "import Blocklist from '@app/components/Blocklist';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@server/lib/permissions';\nimport type { NextPage } from 'next';\n\nconst BlocklistPage: NextPage = () => {\n  useRouteGuard([Permission.MANAGE_BLOCKLIST, Permission.VIEW_BLOCKLIST], {\n    type: 'or',\n  });\n  return <Blocklist />;\n};\n\nexport default BlocklistPage;\n"
  },
  {
    "path": "src/pages/collection/[collectionId]/index.tsx",
    "content": "import CollectionDetails from '@app/components/CollectionDetails';\nimport type { Collection } from '@server/models/Collection';\nimport axios from 'axios';\nimport type { GetServerSideProps, NextPage } from 'next';\n\ninterface CollectionPageProps {\n  collection?: Collection;\n}\n\nconst CollectionPage: NextPage<CollectionPageProps> = ({ collection }) => {\n  return <CollectionDetails collection={collection} />;\n};\n\nexport const getServerSideProps: GetServerSideProps<\n  CollectionPageProps\n> = async (ctx) => {\n  const response = await axios.get<Collection>(\n    `http://${process.env.HOST || 'localhost'}:${\n      process.env.PORT || 5055\n    }/api/v1/collection/${ctx.query.collectionId}`,\n    {\n      headers: ctx.req?.headers?.cookie\n        ? { cookie: ctx.req.headers.cookie }\n        : undefined,\n    }\n  );\n\n  return {\n    props: {\n      collection: response.data,\n    },\n  };\n};\n\nexport default CollectionPage;\n"
  },
  {
    "path": "src/pages/discover/movies/genre/[genreId]/index.tsx",
    "content": "import DiscoverMovieGenre from '@app/components/Discover/DiscoverMovieGenre';\nimport type { NextPage } from 'next';\n\nconst DiscoverMoviesGenrePage: NextPage = () => {\n  return <DiscoverMovieGenre />;\n};\n\nexport default DiscoverMoviesGenrePage;\n"
  },
  {
    "path": "src/pages/discover/movies/genres.tsx",
    "content": "import MovieGenreList from '@app/components/Discover/MovieGenreList';\nimport type { NextPage } from 'next';\n\nconst MovieGenresPage: NextPage = () => {\n  return <MovieGenreList />;\n};\n\nexport default MovieGenresPage;\n"
  },
  {
    "path": "src/pages/discover/movies/index.tsx",
    "content": "import DiscoverMovies from '@app/components/Discover/DiscoverMovies';\nimport type { NextPage } from 'next';\n\nconst DiscoverMoviesPage: NextPage = () => {\n  return <DiscoverMovies />;\n};\n\nexport default DiscoverMoviesPage;\n"
  },
  {
    "path": "src/pages/discover/movies/keyword/index.tsx",
    "content": "import DiscoverMovieKeyword from '@app/components/Discover/DiscoverMovieKeyword';\nimport type { NextPage } from 'next';\n\nconst DiscoverMoviesKeywordPage: NextPage = () => {\n  return <DiscoverMovieKeyword />;\n};\n\nexport default DiscoverMoviesKeywordPage;\n"
  },
  {
    "path": "src/pages/discover/movies/language/[language]/index.tsx",
    "content": "import DiscoverMovieLanguage from '@app/components/Discover/DiscoverMovieLanguage';\nimport type { NextPage } from 'next';\n\nconst DiscoverMovieLanguagePage: NextPage = () => {\n  return <DiscoverMovieLanguage />;\n};\n\nexport default DiscoverMovieLanguagePage;\n"
  },
  {
    "path": "src/pages/discover/movies/studio/[studioId]/index.tsx",
    "content": "import DiscoverMovieStudio from '@app/components/Discover/DiscoverStudio';\nimport type { NextPage } from 'next';\n\nconst DiscoverMoviesStudioPage: NextPage = () => {\n  return <DiscoverMovieStudio />;\n};\n\nexport default DiscoverMoviesStudioPage;\n"
  },
  {
    "path": "src/pages/discover/movies/upcoming.tsx",
    "content": "import UpcomingMovies from '@app/components/Discover/Upcoming';\nimport type { NextPage } from 'next';\n\nconst UpcomingMoviesPage: NextPage = () => {\n  return <UpcomingMovies />;\n};\n\nexport default UpcomingMoviesPage;\n"
  },
  {
    "path": "src/pages/discover/trending.tsx",
    "content": "import Trending from '@app/components/Discover/Trending';\nimport type { NextPage } from 'next';\n\nconst TrendingPage: NextPage = () => {\n  return <Trending />;\n};\n\nexport default TrendingPage;\n"
  },
  {
    "path": "src/pages/discover/tv/genre/[genreId]/index.tsx",
    "content": "import DiscoverTvGenre from '@app/components/Discover/DiscoverTvGenre';\nimport type { NextPage } from 'next';\n\nconst DiscoverTvGenrePage: NextPage = () => {\n  return <DiscoverTvGenre />;\n};\n\nexport default DiscoverTvGenrePage;\n"
  },
  {
    "path": "src/pages/discover/tv/genres.tsx",
    "content": "import TvGenreList from '@app/components/Discover/TvGenreList';\nimport type { NextPage } from 'next';\n\nconst TvGenresPage: NextPage = () => {\n  return <TvGenreList />;\n};\n\nexport default TvGenresPage;\n"
  },
  {
    "path": "src/pages/discover/tv/index.tsx",
    "content": "import DiscoverTv from '@app/components/Discover/DiscoverTv';\nimport type { NextPage } from 'next';\n\nconst DiscoverTvPage: NextPage = () => {\n  return <DiscoverTv />;\n};\n\nexport default DiscoverTvPage;\n"
  },
  {
    "path": "src/pages/discover/tv/keyword/index.tsx",
    "content": "import DiscoverTvKeyword from '@app/components/Discover/DiscoverTvKeyword';\nimport type { NextPage } from 'next';\n\nconst DiscoverTvKeywordPage: NextPage = () => {\n  return <DiscoverTvKeyword />;\n};\n\nexport default DiscoverTvKeywordPage;\n"
  },
  {
    "path": "src/pages/discover/tv/language/[language]/index.tsx",
    "content": "import DiscoverTvLanguage from '@app/components/Discover/DiscoverTvLanguage';\nimport type { NextPage } from 'next';\n\nconst DiscoverTvLanguagePage: NextPage = () => {\n  return <DiscoverTvLanguage />;\n};\n\nexport default DiscoverTvLanguagePage;\n"
  },
  {
    "path": "src/pages/discover/tv/network/[networkId]/index.tsx",
    "content": "import DiscoverNetwork from '@app/components/Discover/DiscoverNetwork';\nimport type { NextPage } from 'next';\n\nconst DiscoverTvNetworkPage: NextPage = () => {\n  return <DiscoverNetwork />;\n};\n\nexport default DiscoverTvNetworkPage;\n"
  },
  {
    "path": "src/pages/discover/tv/upcoming.tsx",
    "content": "import DiscoverTvUpcoming from '@app/components/Discover/DiscoverTvUpcoming';\nimport type { NextPage } from 'next';\n\nconst DiscoverTvPage: NextPage = () => {\n  return <DiscoverTvUpcoming />;\n};\n\nexport default DiscoverTvPage;\n"
  },
  {
    "path": "src/pages/discover/watchlist.tsx",
    "content": "import DiscoverWatchlist from '@app/components/Discover/DiscoverWatchlist';\nimport type { NextPage } from 'next';\n\nconst WatchlistPage: NextPage = () => {\n  return <DiscoverWatchlist />;\n};\n\nexport default WatchlistPage;\n"
  },
  {
    "path": "src/pages/index.tsx",
    "content": "import Discover from '@app/components/Discover';\nimport type { NextPage } from 'next';\n\nconst Index: NextPage = () => {\n  return <Discover />;\n};\n\nexport default Index;\n"
  },
  {
    "path": "src/pages/issues/[issueId]/index.tsx",
    "content": "import IssueDetails from '@app/components/IssueDetails';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst IssuePage: NextPage = () => {\n  useRouteGuard(\n    [\n      Permission.MANAGE_ISSUES,\n      Permission.CREATE_ISSUES,\n      Permission.VIEW_ISSUES,\n    ],\n    {\n      type: 'or',\n    }\n  );\n  return <IssueDetails />;\n};\n\nexport default IssuePage;\n"
  },
  {
    "path": "src/pages/issues/index.tsx",
    "content": "import IssueList from '@app/components/IssueList';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst IssuePage: NextPage = () => {\n  useRouteGuard(\n    [\n      Permission.MANAGE_ISSUES,\n      Permission.CREATE_ISSUES,\n      Permission.VIEW_ISSUES,\n    ],\n    {\n      type: 'or',\n    }\n  );\n  return <IssueList />;\n};\n\nexport default IssuePage;\n"
  },
  {
    "path": "src/pages/login/index.tsx",
    "content": "import Login from '@app/components/Login';\nimport type { NextPage } from 'next';\n\nconst LoginPage: NextPage = () => {\n  return <Login />;\n};\n\nexport default LoginPage;\n"
  },
  {
    "path": "src/pages/login/plex/loading.tsx",
    "content": "import LoadingSpinner from '@app/components/Common/LoadingSpinner';\n\nconst PlexLoading = () => {\n  return (\n    <div>\n      <LoadingSpinner />\n    </div>\n  );\n};\n\nexport default PlexLoading;\n"
  },
  {
    "path": "src/pages/movie/[movieId]/cast.tsx",
    "content": "import MovieCast from '@app/components/MovieDetails/MovieCast';\nimport type { NextPage } from 'next';\n\nconst MovieCastPage: NextPage = () => {\n  return <MovieCast />;\n};\n\nexport default MovieCastPage;\n"
  },
  {
    "path": "src/pages/movie/[movieId]/crew.tsx",
    "content": "import MovieCrew from '@app/components/MovieDetails/MovieCrew';\nimport type { NextPage } from 'next';\n\nconst MovieCrewPage: NextPage = () => {\n  return <MovieCrew />;\n};\n\nexport default MovieCrewPage;\n"
  },
  {
    "path": "src/pages/movie/[movieId]/index.tsx",
    "content": "import MovieDetails from '@app/components/MovieDetails';\nimport type { MovieDetails as MovieDetailsType } from '@server/models/Movie';\nimport axios from 'axios';\nimport type { GetServerSideProps, NextPage } from 'next';\n\ninterface MoviePageProps {\n  movie?: MovieDetailsType;\n}\n\nconst MoviePage: NextPage<MoviePageProps> = ({ movie }) => {\n  return <MovieDetails movie={movie} />;\n};\n\nexport const getServerSideProps: GetServerSideProps<MoviePageProps> = async (\n  ctx\n) => {\n  const response = await axios.get<MovieDetailsType>(\n    `http://${process.env.HOST || 'localhost'}:${\n      process.env.PORT || 5055\n    }/api/v1/movie/${ctx.query.movieId}`,\n    {\n      headers: ctx.req?.headers?.cookie\n        ? { cookie: ctx.req.headers.cookie }\n        : undefined,\n    }\n  );\n\n  return {\n    props: {\n      movie: response.data,\n    },\n  };\n};\n\nexport default MoviePage;\n"
  },
  {
    "path": "src/pages/movie/[movieId]/recommendations.tsx",
    "content": "import MovieRecommendations from '@app/components/MovieDetails/MovieRecommendations';\nimport type { NextPage } from 'next';\n\nconst MovieRecommendationsPage: NextPage = () => {\n  return <MovieRecommendations />;\n};\n\nexport default MovieRecommendationsPage;\n"
  },
  {
    "path": "src/pages/movie/[movieId]/similar.tsx",
    "content": "import MovieSimilar from '@app/components/MovieDetails/MovieSimilar';\nimport type { NextPage } from 'next';\n\nconst MovieSimilarPage: NextPage = () => {\n  return <MovieSimilar />;\n};\n\nexport default MovieSimilarPage;\n"
  },
  {
    "path": "src/pages/person/[personId]/index.tsx",
    "content": "import PersonDetails from '@app/components/PersonDetails';\nimport type { NextPage } from 'next';\n\nconst MoviePage: NextPage = () => {\n  return <PersonDetails />;\n};\n\nexport default MoviePage;\n"
  },
  {
    "path": "src/pages/profile/index.tsx",
    "content": "import UserProfile from '@app/components/UserProfile';\nimport type { NextPage } from 'next';\n\nconst UserPage: NextPage = () => {\n  return <UserProfile />;\n};\n\nexport default UserPage;\n"
  },
  {
    "path": "src/pages/profile/settings/index.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserGeneralSettings from '@app/components/UserProfile/UserSettings/UserGeneralSettings';\nimport type { NextPage } from 'next';\n\nconst UserSettingsPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserGeneralSettings />\n    </UserSettings>\n  );\n};\n\nexport default UserSettingsPage;\n"
  },
  {
    "path": "src/pages/profile/settings/linked-accounts.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserLinkedAccountsSettings from '@app/components/UserProfile/UserSettings/UserLinkedAccountsSettings';\nimport type { NextPage } from 'next';\n\nconst UserSettingsLinkedAccountsPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserLinkedAccountsSettings />\n    </UserSettings>\n  );\n};\n\nexport default UserSettingsLinkedAccountsPage;\n"
  },
  {
    "path": "src/pages/profile/settings/main.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserGeneralSettings from '@app/components/UserProfile/UserSettings/UserGeneralSettings';\nimport type { NextPage } from 'next';\n\nconst UserSettingsMainPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserGeneralSettings />\n    </UserSettings>\n  );\n};\n\nexport default UserSettingsMainPage;\n"
  },
  {
    "path": "src/pages/profile/settings/notifications/discord.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsDiscord from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsDiscord';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsDiscord />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/profile/settings/notifications/email.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsEmail from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsEmail />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/profile/settings/notifications/pushbullet.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsPushbullet from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsPushbullet';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsPushbullet />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/profile/settings/notifications/pushover.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsPushover from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsPushover';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsPushover />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/profile/settings/notifications/telegram.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsTelegram from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsTelegram';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsTelegram />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/profile/settings/notifications/webpush.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserWebPushSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush';\nimport type { NextPage } from 'next';\n\nconst WebPushProfileNotificationsPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserWebPushSettings />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default WebPushProfileNotificationsPage;\n"
  },
  {
    "path": "src/pages/profile/settings/password.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserPasswordChange from '@app/components/UserProfile/UserSettings/UserPasswordChange';\nimport type { NextPage } from 'next';\n\nconst UserPassswordPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserPasswordChange />\n    </UserSettings>\n  );\n};\n\nexport default UserPassswordPage;\n"
  },
  {
    "path": "src/pages/profile/settings/permissions.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserPermissions from '@app/components/UserProfile/UserSettings/UserPermissions';\nimport type { NextPage } from 'next';\n\nconst UserPermissionsPage: NextPage = () => {\n  return (\n    <UserSettings>\n      <UserPermissions />\n    </UserSettings>\n  );\n};\n\nexport default UserPermissionsPage;\n"
  },
  {
    "path": "src/pages/profile/watchlist.tsx",
    "content": "import DiscoverWatchlist from '@app/components/Discover/DiscoverWatchlist';\nimport type { NextPage } from 'next';\n\nconst UserWatchlistPage: NextPage = () => {\n  return <DiscoverWatchlist />;\n};\n\nexport default UserWatchlistPage;\n"
  },
  {
    "path": "src/pages/requests/index.tsx",
    "content": "import RequestList from '@app/components/RequestList';\nimport type { NextPage } from 'next';\n\nconst RequestsPage: NextPage = () => {\n  return <RequestList />;\n};\n\nexport default RequestsPage;\n"
  },
  {
    "path": "src/pages/resetpassword/[guid]/index.tsx",
    "content": "import ResetPassword from '@app/components/ResetPassword';\nimport type { NextPage } from 'next';\n\nconst ResetPasswordPage: NextPage = () => {\n  return <ResetPassword />;\n};\n\nexport default ResetPasswordPage;\n"
  },
  {
    "path": "src/pages/resetpassword/index.tsx",
    "content": "import RequestResetLink from '@app/components/ResetPassword/RequestResetLink';\nimport type { NextPage } from 'next';\n\nconst RequestResetLinkPage: NextPage = () => {\n  return <RequestResetLink />;\n};\n\nexport default RequestResetLinkPage;\n"
  },
  {
    "path": "src/pages/search.tsx",
    "content": "import Search from '@app/components/Search';\n\nconst SearchPage = () => {\n  return <Search />;\n};\n\nexport default SearchPage;\n"
  },
  {
    "path": "src/pages/settings/about.tsx",
    "content": "import SettingsAbout from '@app/components/Settings/SettingsAbout';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst SettingsAboutPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsAbout />\n    </SettingsLayout>\n  );\n};\n\nexport default SettingsAboutPage;\n"
  },
  {
    "path": "src/pages/settings/index.tsx",
    "content": "import SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsMain from '@app/components/Settings/SettingsMain';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst SettingsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsMain />\n    </SettingsLayout>\n  );\n};\n\nexport default SettingsPage;\n"
  },
  {
    "path": "src/pages/settings/jellyfin.tsx",
    "content": "import SettingsJellyfin from '@app/components/Settings/SettingsJellyfin';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst JellyfinSettingsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_SETTINGS);\n  return (\n    <SettingsLayout>\n      <SettingsJellyfin />\n    </SettingsLayout>\n  );\n};\n\nexport default JellyfinSettingsPage;\n"
  },
  {
    "path": "src/pages/settings/jobs.tsx",
    "content": "import SettingsJobs from '@app/components/Settings/SettingsJobsCache';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst SettingsMainPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsJobs />\n    </SettingsLayout>\n  );\n};\n\nexport default SettingsMainPage;\n"
  },
  {
    "path": "src/pages/settings/logs.tsx",
    "content": "import SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsLogs from '@app/components/Settings/SettingsLogs';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst SettingsLogsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsLogs />\n    </SettingsLayout>\n  );\n};\n\nexport default SettingsLogsPage;\n"
  },
  {
    "path": "src/pages/settings/main.tsx",
    "content": "import SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsMain from '@app/components/Settings/SettingsMain';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst SettingsMainPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsMain />\n    </SettingsLayout>\n  );\n};\n\nexport default SettingsMainPage;\n"
  },
  {
    "path": "src/pages/settings/metadata.tsx",
    "content": "import SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsMetadata from '@app/components/Settings/SettingsMetadata';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst MetadataSettingsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsMetadata />\n    </SettingsLayout>\n  );\n};\n\nexport default MetadataSettingsPage;\n"
  },
  {
    "path": "src/pages/settings/network.tsx",
    "content": "import SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNetwork from '@app/components/Settings/SettingsNetwork';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst SettingsNetworkPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNetwork />\n    </SettingsLayout>\n  );\n};\n\nexport default SettingsNetworkPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/discord.tsx",
    "content": "import NotificationsDiscord from '@app/components/Settings/Notifications/NotificationsDiscord';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsDiscord />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/email.tsx",
    "content": "import NotificationsEmail from '@app/components/Settings/Notifications/NotificationsEmail';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsEmail />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/gotify.tsx",
    "content": "import NotificationsGotify from '@app/components/Settings/Notifications/NotificationsGotify';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsGotify />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/ntfy.tsx",
    "content": "import NotificationsNtfy from '@app/components/Settings/Notifications/NotificationsNtfy';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsNtfy />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/pushbullet.tsx",
    "content": "import NotificationsPushbullet from '@app/components/Settings/Notifications/NotificationsPushbullet';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsPushbullet />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/pushover.tsx",
    "content": "import NotificationsPushover from '@app/components/Settings/Notifications/NotificationsPushover';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsPushover />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/slack.tsx",
    "content": "import NotificationsSlack from '@app/components/Settings/Notifications/NotificationsSlack';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsSlackPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsSlack />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsSlackPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/telegram.tsx",
    "content": "import NotificationsTelegram from '@app/components/Settings/Notifications/NotificationsTelegram';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsTelegram />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/webhook.tsx",
    "content": "import NotificationsWebhook from '@app/components/Settings/Notifications/NotificationsWebhook';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsWebhook />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/settings/notifications/webpush.tsx",
    "content": "import NotificationsWebPush from '@app/components/Settings/Notifications/NotificationsWebPush';\nimport SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsNotifications from '@app/components/Settings/SettingsNotifications';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsWebPushPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsNotifications>\n        <NotificationsWebPush />\n      </SettingsNotifications>\n    </SettingsLayout>\n  );\n};\n\nexport default NotificationsWebPushPage;\n"
  },
  {
    "path": "src/pages/settings/plex.tsx",
    "content": "import SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsPlex from '@app/components/Settings/SettingsPlex';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst PlexSettingsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsPlex />\n    </SettingsLayout>\n  );\n};\n\nexport default PlexSettingsPage;\n"
  },
  {
    "path": "src/pages/settings/services.tsx",
    "content": "import SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsServices from '@app/components/Settings/SettingsServices';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst ServicesSettingsPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsServices />\n    </SettingsLayout>\n  );\n};\n\nexport default ServicesSettingsPage;\n"
  },
  {
    "path": "src/pages/settings/users.tsx",
    "content": "import SettingsLayout from '@app/components/Settings/SettingsLayout';\nimport SettingsUsers from '@app/components/Settings/SettingsUsers';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst SettingsUsersPage: NextPage = () => {\n  useRouteGuard(Permission.ADMIN);\n  return (\n    <SettingsLayout>\n      <SettingsUsers />\n    </SettingsLayout>\n  );\n};\n\nexport default SettingsUsersPage;\n"
  },
  {
    "path": "src/pages/setup.tsx",
    "content": "import Setup from '@app/components/Setup';\nimport type { NextPage } from 'next';\n\nconst SetupPage: NextPage = () => {\n  return <Setup />;\n};\n\nexport default SetupPage;\n"
  },
  {
    "path": "src/pages/tv/[tvId]/cast.tsx",
    "content": "import TvCast from '@app/components/TvDetails/TvCast';\nimport type { NextPage } from 'next';\n\nconst TvCastPage: NextPage = () => {\n  return <TvCast />;\n};\n\nexport default TvCastPage;\n"
  },
  {
    "path": "src/pages/tv/[tvId]/crew.tsx",
    "content": "import TvCrew from '@app/components/TvDetails/TvCrew';\nimport type { NextPage } from 'next';\n\nconst TvCrewPage: NextPage = () => {\n  return <TvCrew />;\n};\n\nexport default TvCrewPage;\n"
  },
  {
    "path": "src/pages/tv/[tvId]/index.tsx",
    "content": "import TvDetails from '@app/components/TvDetails';\nimport type { TvDetails as TvDetailsType } from '@server/models/Tv';\nimport axios from 'axios';\nimport type { GetServerSideProps, NextPage } from 'next';\n\ninterface TvPageProps {\n  tv?: TvDetailsType;\n}\n\nconst TvPage: NextPage<TvPageProps> = ({ tv }) => {\n  return <TvDetails tv={tv} />;\n};\n\nexport const getServerSideProps: GetServerSideProps<TvPageProps> = async (\n  ctx\n) => {\n  const response = await axios.get<TvDetailsType>(\n    `http://${process.env.HOST || 'localhost'}:${\n      process.env.PORT || 5055\n    }/api/v1/tv/${ctx.query.tvId}`,\n    {\n      headers: ctx.req?.headers?.cookie\n        ? { cookie: ctx.req.headers.cookie }\n        : undefined,\n    }\n  );\n\n  return {\n    props: {\n      tv: response.data,\n    },\n  };\n};\n\nexport default TvPage;\n"
  },
  {
    "path": "src/pages/tv/[tvId]/recommendations.tsx",
    "content": "import TvRecommendations from '@app/components/TvDetails/TvRecommendations';\nimport type { NextPage } from 'next';\n\nconst TvRecommendationsPage: NextPage = () => {\n  return <TvRecommendations />;\n};\n\nexport default TvRecommendationsPage;\n"
  },
  {
    "path": "src/pages/tv/[tvId]/similar.tsx",
    "content": "import TvSimilar from '@app/components/TvDetails/TvSimilar';\nimport type { NextPage } from 'next';\n\nconst TvSimilarPage: NextPage = () => {\n  return <TvSimilar />;\n};\n\nexport default TvSimilarPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/index.tsx",
    "content": "import UserProfile from '@app/components/UserProfile';\nimport type { NextPage } from 'next';\n\nconst UserPage: NextPage = () => {\n  return <UserProfile />;\n};\n\nexport default UserPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/requests.tsx",
    "content": "import RequestList from '@app/components/RequestList';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst UserRequestsPage: NextPage = () => {\n  useRouteGuard([Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW], {\n    type: 'or',\n  });\n  return <RequestList />;\n};\n\nexport default UserRequestsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/index.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserGeneralSettings from '@app/components/UserProfile/UserSettings/UserGeneralSettings';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst UserSettingsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserGeneralSettings />\n    </UserSettings>\n  );\n};\n\nexport default UserSettingsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/linked-accounts.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserLinkedAccountsSettings from '@app/components/UserProfile/UserSettings/UserLinkedAccountsSettings';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst UserLinkedAccountsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserLinkedAccountsSettings />\n    </UserSettings>\n  );\n};\n\nexport default UserLinkedAccountsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/main.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserGeneralSettings from '@app/components/UserProfile/UserSettings/UserGeneralSettings';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst UserSettingsMainPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserGeneralSettings />\n    </UserSettings>\n  );\n};\n\nexport default UserSettingsMainPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/notifications/discord.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsDiscord from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsDiscord';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsDiscord />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/notifications/email.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsEmail from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsEmail />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/notifications/pushbullet.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsPushbullet from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsPushbullet';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsPushbullet />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/notifications/pushover.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsPushover from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsPushover';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsPushover />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/notifications/telegram.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserNotificationsTelegram from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsTelegram';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst NotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserNotificationsTelegram />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/notifications/webpush.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserNotificationSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings';\nimport UserWebPushSettings from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst WebPushNotificationsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserNotificationSettings>\n        <UserWebPushSettings />\n      </UserNotificationSettings>\n    </UserSettings>\n  );\n};\n\nexport default WebPushNotificationsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/password.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserPasswordChange from '@app/components/UserProfile/UserSettings/UserPasswordChange';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst UserPassswordPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserPasswordChange />\n    </UserSettings>\n  );\n};\n\nexport default UserPassswordPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/settings/permissions.tsx",
    "content": "import UserSettings from '@app/components/UserProfile/UserSettings';\nimport UserPermissions from '@app/components/UserProfile/UserSettings/UserPermissions';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst UserPermissionsPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return (\n    <UserSettings>\n      <UserPermissions />\n    </UserSettings>\n  );\n};\n\nexport default UserPermissionsPage;\n"
  },
  {
    "path": "src/pages/users/[userId]/watchlist.tsx",
    "content": "import DiscoverWatchlist from '@app/components/Discover/DiscoverWatchlist';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst UserRequestsPage: NextPage = () => {\n  useRouteGuard([Permission.MANAGE_REQUESTS, Permission.WATCHLIST_VIEW], {\n    type: 'or',\n  });\n  return <DiscoverWatchlist />;\n};\n\nexport default UserRequestsPage;\n"
  },
  {
    "path": "src/pages/users/index.tsx",
    "content": "import UserList from '@app/components/UserList';\nimport useRouteGuard from '@app/hooks/useRouteGuard';\nimport { Permission } from '@app/hooks/useUser';\nimport type { NextPage } from 'next';\n\nconst UsersPage: NextPage = () => {\n  useRouteGuard(Permission.MANAGE_USERS);\n  return <UserList />;\n};\n\nexport default UsersPage;\n"
  },
  {
    "path": "src/styles/globals.css",
    "content": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n  html {\n    min-height: calc(100% + env(safe-area-inset-top));\n    padding: env(safe-area-inset-top) env(safe-area-inset-right)\n      calc(4rem + env(safe-area-inset-bottom)) env(safe-area-inset-left);\n    scrollbar-width: thin;\n    scrollbar-color: #4b5563 #1f2937;\n  }\n\n  html:hover {\n    scrollbar-color: #6b7280 #1f2937;\n  }\n\n  /* WebKit scrollbar styles */\n  html::-webkit-scrollbar {\n    width: 10px;\n  }\n\n  html::-webkit-scrollbar-track {\n    background: #1f2937;\n  }\n\n  html::-webkit-scrollbar-thumb {\n    background-color: #4b5563;\n  }\n\n  html:hover::-webkit-scrollbar-thumb {\n    background-color: #6b7280;\n  }\n\n  @media (min-width: 640px) {\n    html {\n      padding-bottom: env(safe-area-inset-bottom);\n    }\n  }\n\n  body {\n    @apply bg-gray-900;\n    -webkit-overflow-scrolling: touch;\n  }\n\n  code {\n    @apply rounded-md bg-gray-800 px-2 py-1;\n  }\n\n  input[type='search']::-webkit-search-cancel-button {\n    -webkit-appearance: none;\n  }\n}\n\n@layer components {\n  .searchbar {\n    padding-top: env(safe-area-inset-top);\n    height: calc(4rem + env(safe-area-inset-top));\n  }\n\n  .sidebar {\n    @apply border-r border-gray-700;\n    padding-top: env(safe-area-inset-top);\n    padding-left: env(safe-area-inset-left);\n    background: linear-gradient(180deg, rgba(31, 41, 55, 1) 0%, #131928 100%);\n  }\n\n  .slideover {\n    padding-top: calc(0.75rem + env(safe-area-inset-top)) !important;\n    padding-bottom: calc(0.75rem + env(safe-area-inset-top)) !important;\n  }\n\n  .sidebar-close-button {\n    top: env(safe-area-inset-top);\n  }\n\n  .server-type-button {\n    @apply rounded-md border border-gray-500 bg-gray-700 px-4 py-2 text-white transition duration-150 ease-in-out hover:bg-gray-500;\n  }\n  .jellyfin-server svg {\n    @apply h-6 w-6;\n  }\n  .emby-server svg {\n    @apply h-7 w-7;\n  }\n\n  ul.cards-vertical,\n  ul.cards-horizontal {\n    @apply grid gap-4;\n  }\n\n  ul.cards-vertical {\n    grid-template-columns: repeat(auto-fill, minmax(9.375rem, 1fr));\n  }\n\n  ul.cards-horizontal {\n    grid-template-columns: repeat(auto-fill, minmax(16.5rem, 1fr));\n  }\n\n  .provider-icons {\n    grid-template-columns: repeat(auto-fill, minmax(3.5rem, 1fr));\n  }\n\n  .slider-header {\n    @apply relative mb-4 mt-6 flex;\n  }\n\n  .service-error-banner {\n    @apply mb-2 flex items-center gap-2 rounded-md border border-yellow-500 bg-yellow-500/20 px-3 py-2 text-sm text-yellow-200;\n  }\n\n  .slider-title {\n    @apply inline-flex items-center text-xl font-bold leading-7 text-gray-300 sm:truncate sm:text-2xl sm:leading-9;\n  }\n\n  a.slider-title {\n    @apply transition duration-300 hover:text-white;\n  }\n\n  a.slider-title svg {\n    @apply ml-2 h-6 w-6;\n  }\n\n  .media-page {\n    @apply relative -mx-4 bg-cover bg-center px-4;\n    margin-top: calc(-4rem - env(safe-area-inset-top));\n    padding-top: calc(4rem + env(safe-area-inset-top));\n  }\n\n  .media-page-bg-image {\n    @apply absolute inset-0 h-full w-full;\n    z-index: -10;\n  }\n\n  .media-header {\n    @apply flex flex-col items-center pt-4 xl:flex-row xl:items-end;\n  }\n\n  .media-poster {\n    @apply w-32 overflow-hidden rounded shadow md:w-44 md:rounded-lg md:shadow-2xl xl:mr-4 xl:w-52;\n  }\n\n  .media-status {\n    @apply mb-2 space-x-2;\n  }\n\n  .media-title {\n    @apply mt-4 flex flex-1 flex-col text-center text-white xl:mr-4 xl:mt-0 xl:text-left;\n  }\n\n  .media-title > h1 {\n    @apply text-2xl font-bold xl:text-4xl;\n  }\n\n  h1 .media-year {\n    @apply text-2xl;\n  }\n\n  .media-attributes {\n    @apply mt-1 flex flex-wrap items-center justify-center space-x-1 text-xs text-gray-300 sm:text-sm xl:mt-0 xl:justify-start xl:text-base;\n  }\n\n  .media-attributes a {\n    @apply transition duration-300 hover:text-white hover:underline;\n  }\n\n  .media-actions {\n    @apply relative mt-4 flex flex-shrink-0 flex-wrap items-center justify-center sm:flex-nowrap sm:justify-end xl:mt-0;\n  }\n\n  .media-actions > * {\n    @apply mb-3 sm:mb-0;\n  }\n\n  .media-overview {\n    @apply flex flex-col pb-4 pt-8 text-white lg:flex-row;\n  }\n\n  .media-overview-left {\n    @apply flex-1 lg:mr-8;\n  }\n\n  .tagline {\n    @apply mb-4 text-xl italic text-gray-400 lg:text-2xl;\n  }\n\n  .media-overview h2 {\n    @apply text-xl font-bold text-gray-300 sm:text-2xl;\n  }\n\n  .media-overview p {\n    @apply pt-2 text-sm text-gray-400 sm:text-base;\n  }\n\n  ul.media-crew {\n    @apply mt-6 grid grid-cols-2 gap-6 sm:grid-cols-3;\n  }\n\n  ul.media-crew > li {\n    @apply col-span-1 flex flex-col font-bold text-gray-300;\n  }\n\n  a.crew-name,\n  .media-fact-value a,\n  .media-fact-value button {\n    @apply font-normal text-gray-400 transition duration-300 hover:text-gray-100 hover:underline;\n  }\n\n  .media-overview-right {\n    @apply mt-8 w-full lg:mt-0 lg:w-80;\n  }\n\n  .media-facts {\n    @apply rounded-lg border border-gray-700 bg-gray-900 text-sm font-bold text-gray-300 shadow;\n  }\n\n  .media-fact {\n    @apply flex justify-between border-b border-gray-700 px-4 py-2 last:border-b-0;\n  }\n\n  .media-fact-value {\n    @apply ml-2 text-right text-sm font-normal text-gray-400;\n  }\n\n  .media-ratings {\n    @apply flex items-center justify-center space-x-5 border-b border-gray-700 px-4 py-2 font-medium last:border-b-0;\n  }\n\n  .media-rating {\n    @apply flex items-center space-x-1;\n  }\n\n  .error-message {\n    @apply relative bottom-0 left-0 right-0 top-0 flex h-screen flex-col items-center justify-center text-center text-gray-300;\n  }\n\n  .heading {\n    @apply text-2xl font-bold leading-8 text-gray-100;\n  }\n\n  .description {\n    @apply mt-1 max-w-4xl text-sm leading-5 text-gray-400;\n  }\n\n  img.avatar-sm {\n    @apply mr-1 h-5 w-5 scale-100 transform-gpu rounded-full transition duration-300 group-hover:scale-105;\n  }\n\n  .card-field {\n    @apply flex items-center truncate py-0.5 text-sm sm:py-1;\n  }\n\n  .card-field-name {\n    @apply mr-2 font-bold;\n  }\n\n  .card-field a {\n    @apply transition duration-300 hover:text-white hover:underline;\n  }\n\n  .section {\n    @apply mb-10 mt-6 text-white;\n  }\n\n  .form-row {\n    @apply mt-6 max-w-6xl sm:mt-5 sm:grid sm:grid-cols-3 sm:items-start sm:gap-4;\n  }\n\n  .form-input-area {\n    @apply text-sm text-white sm:col-span-2;\n  }\n\n  .form-input-field {\n    @apply flex max-w-xl rounded-md shadow-sm;\n  }\n\n  .actions {\n    @apply mt-8 border-t border-gray-700 pt-5 text-white;\n  }\n\n  label,\n  .group-label {\n    @apply mb-1 block text-sm font-bold leading-5 text-gray-400;\n  }\n\n  label.checkbox-label {\n    @apply sm:mt-1;\n  }\n\n  label.text-label {\n    @apply sm:mt-2;\n  }\n\n  label a {\n    @apply text-gray-100 transition duration-300 hover:text-white hover:underline;\n  }\n\n  .label-required {\n    @apply ml-1 text-red-500;\n  }\n\n  .label-tip {\n    @apply block font-medium text-gray-500;\n  }\n\n  button,\n  input,\n  select,\n  textarea {\n    @apply disabled:cursor-not-allowed;\n  }\n\n  input[type='checkbox'] {\n    @apply h-6 w-6 rounded-md text-indigo-600 transition duration-150 ease-in-out;\n  }\n\n  input[type='text'],\n  input[type='password'],\n  select,\n  textarea {\n    @apply block w-full min-w-0 flex-1 rounded-md border border-gray-500 bg-gray-700 text-white transition duration-150 ease-in-out sm:text-sm sm:leading-5;\n  }\n\n  input.rounded-l-only,\n  select.rounded-l-only,\n  textarea.rounded-l-only {\n    @apply rounded-r-none;\n  }\n\n  input.rounded-r-only,\n  select.rounded-r-only,\n  textarea.rounded-r-only {\n    @apply rounded-l-none;\n  }\n\n  input.short {\n    @apply w-20;\n  }\n\n  select.short {\n    @apply w-min;\n  }\n\n  button > span {\n    @apply whitespace-nowrap;\n  }\n\n  button.input-action {\n    @apply relative -ml-px inline-flex items-center border border-gray-500 bg-indigo-600/80 px-3 py-2 text-sm font-medium leading-5 text-white last:rounded-r-md sm:px-3.5;\n  }\n\n  button.input-action[disabled] {\n    filter: grayscale(100%);\n  }\n\n  button.input-action:not([disabled]) {\n    @apply transition duration-150 ease-in-out hover:bg-indigo-600 active:bg-gray-100 active:text-gray-700;\n  }\n\n  .button-md :where(svg),\n  button.input-action svg {\n    @apply ml-2 mr-2 h-5 w-5 first:ml-0 last:mr-0;\n  }\n\n  .button-sm svg {\n    @apply ml-1.5 mr-1.5 h-4 w-4 first:ml-0 last:mr-0;\n  }\n\n  svg.icon-md {\n    @apply h-5 w-5;\n  }\n\n  svg.icon-sm {\n    @apply h-4 w-4;\n  }\n\n  .protocol {\n    @apply inline-flex cursor-default items-center rounded-l-md border border-r-0 border-gray-500 bg-gray-600 px-3 text-gray-100 sm:text-sm;\n  }\n\n  .error {\n    @apply mt-2 text-sm text-red-500;\n  }\n\n  .warning {\n    @apply mt-2 text-sm text-yellow-500;\n  }\n\n  .form-group {\n    @apply mt-6 text-white;\n  }\n\n  .toast {\n    width: 360px;\n  }\n\n  .react-select-container {\n    @apply w-full;\n  }\n\n  .react-select-container:has(+ .input-action) .react-select__control {\n    @apply rounded-r-none border border-gray-500 bg-gray-700 text-white hover:border-gray-500;\n  }\n\n  .react-select-container .react-select__control {\n    @apply rounded-md border border-gray-500 bg-gray-700 text-white hover:border-gray-500;\n  }\n\n  .react-select-container-dark .react-select__control {\n    @apply border border-gray-700 bg-gray-800;\n  }\n\n  .react-select-container .react-select__control--is-focused {\n    @apply rounded-md border border-gray-500 bg-gray-700 text-white shadow;\n  }\n\n  .react-select-container-dark .react-select__control--is-focused {\n    @apply border-gray-600 bg-gray-800;\n  }\n\n  .react-select-container .react-select__menu {\n    @apply bg-gray-700 text-gray-300;\n  }\n\n  .react-select-container-dark .react-select__menu {\n    @apply bg-gray-800;\n  }\n\n  .react-select-container .react-select__option--is-focused {\n    @apply bg-gray-600 text-white;\n  }\n\n  .react-select-container-dark .react-select__option--is-focused {\n    @apply bg-gray-700;\n  }\n\n  .react-select-container .react-select__indicator-separator {\n    @apply bg-gray-500;\n  }\n\n  .react-select-container .react-select__indicator {\n    @apply text-gray-500;\n  }\n\n  .react-select-container .react-select__placeholder {\n    @apply text-gray-400;\n  }\n\n  .react-select-container .react-select__multi-value {\n    @apply rounded-md border border-gray-500 bg-gray-800;\n  }\n\n  .react-select-container .react-select__multi-value__label {\n    @apply text-white;\n  }\n\n  .react-select-container .react-select__multi-value__remove {\n    @apply cursor-pointer rounded-r-md hover:bg-red-700 hover:text-red-100;\n  }\n\n  .react-select-container .react-select__input {\n    @apply border-none text-base shadow-sm ring-0;\n  }\n\n  .react-select-container .react-select__input input:focus {\n    @apply border-none;\n    box-shadow: none;\n  }\n\n  .react-select-container .react-select__input-container {\n    @apply text-white;\n  }\n\n  .react-select-container .react-select__single-value {\n    @apply text-sm text-gray-100;\n  }\n\n  .react-select-container .react-select__placeholder {\n    @apply text-sm text-gray-500;\n  }\n\n  .datepicker-wrapper > button {\n    @apply top-0;\n  }\n\n  .datepicker-wrapper > div {\n    @apply fixed left-0 right-0 w-full px-4 md:w-auto;\n  }\n\n  .datepicker-wrapper > div > div:nth-child(2) > div {\n    @apply !flex-col;\n  }\n\n  .datepicker-wrapper > div > div:nth-child(2) > div > div > div {\n    @apply !w-full !min-w-full;\n  }\n\n  .datepicker-wrapper > div > div:first-child {\n    @apply hidden;\n  }\n\n  input[type='range']::-webkit-slider-thumb {\n    @apply rounded-full border-0 bg-indigo-500;\n    pointer-events: all;\n    width: 16px;\n    height: 16px;\n    -webkit-appearance: none;\n  }\n\n  input[type='range']::-moz-range-thumb {\n    @apply rounded-full border-0 bg-indigo-500;\n    pointer-events: all;\n    width: 16px;\n    height: 16px;\n    -webkit-appearance: none;\n  }\n}\n\n@layer utilities {\n  .absolute-top-shift {\n    top: calc(-4rem - env(safe-area-inset-top));\n  }\n\n  .absolute-bottom-shift {\n    bottom: calc(5rem + env(safe-area-inset-bottom));\n  }\n\n  .safe-shift-edit-menu {\n    bottom: calc(54px + env(safe-area-inset-bottom));\n  }\n\n  .padding-bottom-safe {\n    padding-bottom: env(safe-area-inset-bottom);\n  }\n\n  .min-h-screen-shift {\n    min-height: calc(100vh + env(safe-area-inset-top));\n  }\n\n  /* Used for animating height */\n  .extra-max-height {\n    max-height: 100rem;\n  }\n\n  /* Hide scrollbar for Chrome, Safari and Opera */\n  .hide-scrollbar::-webkit-scrollbar {\n    display: none;\n  }\n\n  /* Hide scrollbar for IE, Edge and Firefox */\n  .hide-scrollbar {\n    -ms-overflow-style: none; /* IE and Edge */\n    scrollbar-width: none; /* Firefox */\n  }\n\n  .text-overseerr {\n    @apply bg-gradient-to-br from-indigo-400 to-purple-400 bg-clip-text text-transparent;\n  }\n\n  @media all and (display-mode: browser) {\n    .pwa-only {\n      @apply hidden;\n    }\n  }\n\n  .extra-bottom-space {\n    height: calc(4rem + env(safe-area-inset-bottom));\n  }\n}\n\n.ptr--ptr {\n  box-shadow: initial !important;\n  position: absolute !important;\n  z-index: 30 !important;\n}\n\n.ptr--refresh {\n  overflow: visible !important;\n  z-index: 30 !important;\n}\n\n.ptr--pull {\n  z-index: 30 !important;\n}\n\n.ptr--box {\n  margin-bottom: -13px !important;\n}\n"
  },
  {
    "path": "src/types/custom.d.ts",
    "content": "/* eslint-disable */\ndeclare module '*.svg' {\n  const content: any;\n  export default content;\n}\n\ndeclare module '*.jpg' {\n  const content: any;\n  export default content;\n}\ndeclare module '*.jpeg' {\n  const content: any;\n  export default content;\n}\n\ndeclare module '*.gif' {\n  const content: any;\n  export default content;\n}\n\ndeclare module '*.png' {\n  const content: any;\n  export default content;\n}\n\ndeclare module '*.css' {\n  interface IClassNames {\n    [className: string]: string;\n  }\n  const classNames: IClassNames;\n  export = classNames;\n}\n"
  },
  {
    "path": "src/types/react-intl-auto.d.ts",
    "content": "import type { MessageDescriptor } from 'react-intl';\n\ndeclare module 'react-intl' {\n  interface ExtractableMessage {\n    [key: string]: string;\n  }\n\n  export function defineMessages<T extends ExtractableMessage>(\n    messages: T\n  ): { [K in keyof T]: MessageDescriptor };\n}\n"
  },
  {
    "path": "src/utils/creditHelpers.ts",
    "content": "import type { Crew } from '@server/models/common';\nconst priorityJobs = [\n  'Director',\n  'Creator',\n  'Screenplay',\n  'Writer',\n  'Composer',\n  'Editor',\n  'Producer',\n  'Co-Producer',\n  'Executive Producer',\n  'Animation',\n];\n\nexport const sortCrewPriority = (crew: Crew[]): Crew[] => {\n  return crew\n    .filter((person) => priorityJobs.includes(person.job))\n    .sort((a, b) => {\n      const aScore = priorityJobs.findIndex((job) => job.includes(a.job));\n      const bScore = priorityJobs.findIndex((job) => job.includes(b.job));\n\n      return aScore - bScore;\n    });\n};\n"
  },
  {
    "path": "src/utils/defineMessages.ts",
    "content": "import { defineMessages as intlDefineMessages } from 'react-intl';\n\ntype Messages<T extends Record<string, string>> = {\n  [K in keyof T]: {\n    id: string;\n    defaultMessage: T[K];\n  };\n};\n\nexport default function defineMessages<T extends Record<string, string>>(\n  prefix: string,\n  messages: T\n): Messages<T> {\n  const keys: (keyof T)[] = Object.keys(messages);\n  const modifiedMessagesEntries = keys.map((key) => [\n    key,\n    {\n      id: `${prefix}.${key as string}`,\n      defaultMessage: messages[key],\n    },\n  ]);\n  const modifiedMessages: Messages<T> = Object.fromEntries(\n    modifiedMessagesEntries\n  );\n  return intlDefineMessages(modifiedMessages);\n}\n"
  },
  {
    "path": "src/utils/jellyfin.ts",
    "content": "import type { AxiosError, AxiosResponse } from 'axios';\nimport axios from 'axios';\n\ninterface JellyfinAuthenticationResult {\n  Id: string;\n  AccessToken: string;\n  ServerId: string;\n}\n\nclass JellyAPI {\n  public login(\n    Hostname?: string,\n    Username?: string,\n    Password?: string\n  ): Promise<JellyfinAuthenticationResult> {\n    return new Promise(\n      (\n        resolve: (result: JellyfinAuthenticationResult) => void,\n        reject: (e: Error) => void\n      ) => {\n        axios\n          .post(\n            Hostname + '/Users/AuthenticateByName',\n            {\n              Username: Username,\n              Pw: Password,\n            },\n            {\n              headers: {\n                'X-Emby-Authorization':\n                  'MediaBrowser Client=\"Jellyfin Web\", Device=\"Firefox\", DeviceId=\"TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NDsgcnY6ODUuMCkgR2Vja28vMjAxMDAxMDEgRmlyZWZveC84NS4wfDE2MTI5MjcyMDM5NzM1\", Version=\"10.8.0\"',\n              },\n            }\n          )\n          .then((resp: AxiosResponse) => {\n            const response: JellyfinAuthenticationResult = {\n              Id: resp.data.User.Id,\n              AccessToken: resp.data.AccessToken,\n              ServerId: resp.data.ServerId,\n            };\n            resolve(response);\n          })\n          .catch((e: AxiosError) => {\n            reject(e);\n          });\n      }\n    );\n  }\n}\n\nexport default JellyAPI;\n"
  },
  {
    "path": "src/utils/numberHelpers.ts",
    "content": "export const formatBytes = (bytes: number, decimals = 2): string => {\n  if (bytes === 0) return '0 Bytes';\n\n  const k = 1024;\n  const dm = decimals < 0 ? 0 : decimals;\n  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];\n\n  const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n  return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];\n};\n"
  },
  {
    "path": "src/utils/plex.ts",
    "content": "import axios from 'axios';\nimport Bowser from 'bowser';\n\ninterface PlexHeaders extends Record<string, string> {\n  Accept: string;\n  'X-Plex-Product': string;\n  'X-Plex-Version': string;\n  'X-Plex-Client-Identifier': string;\n  'X-Plex-Model': string;\n  'X-Plex-Platform': string;\n  'X-Plex-Platform-Version': string;\n  'X-Plex-Device': string;\n  'X-Plex-Device-Name': string;\n  'X-Plex-Device-Screen-Resolution': string;\n  'X-Plex-Language': string;\n}\n\nexport interface PlexPin {\n  id: number;\n  code: string;\n}\n\nconst uuidv4 = (): string => {\n  return ((1e7).toString() + -1e3 + -4e3 + -8e3 + -1e11).replace(\n    /[018]/g,\n    function (c) {\n      return (\n        parseInt(c) ^\n        (window.crypto.getRandomValues(new Uint8Array(1))[0] &\n          (15 >> (parseInt(c) / 4)))\n      ).toString(16);\n    }\n  );\n};\n\nclass PlexOAuth {\n  private plexHeaders?: PlexHeaders;\n\n  private pin?: PlexPin;\n  private popup?: Window;\n\n  private authToken?: string;\n\n  public initializeHeaders(): void {\n    if (!window) {\n      throw new Error(\n        'Window is not defined. Are you calling this in the browser?'\n      );\n    }\n\n    let clientId = localStorage.getItem('plex-client-id');\n    if (!clientId) {\n      const uuid = uuidv4();\n      localStorage.setItem('plex-client-id', uuid);\n      clientId = uuid;\n    }\n\n    const browser = Bowser.getParser(window.navigator.userAgent);\n    this.plexHeaders = {\n      Accept: 'application/json',\n      'X-Plex-Product': 'Seerr',\n      'X-Plex-Version': 'Plex OAuth',\n      'X-Plex-Client-Identifier': clientId,\n      'X-Plex-Model': 'Plex OAuth',\n      'X-Plex-Platform': browser.getBrowserName(),\n      'X-Plex-Platform-Version': browser.getBrowserVersion() || 'Unknown',\n      'X-Plex-Device': browser.getOSName(),\n      'X-Plex-Device-Name': `${browser.getBrowserName()} (Seerr)`,\n      'X-Plex-Device-Screen-Resolution':\n        window.screen.width + 'x' + window.screen.height,\n      'X-Plex-Language': 'en',\n    };\n  }\n\n  public async getPin(): Promise<PlexPin> {\n    if (!this.plexHeaders) {\n      throw new Error(\n        'You must initialize the plex headers clientside to login'\n      );\n    }\n    const response = await axios.post(\n      'https://plex.tv/api/v2/pins?strong=true',\n      undefined,\n      { headers: this.plexHeaders }\n    );\n\n    this.pin = { id: response.data.id, code: response.data.code };\n\n    return this.pin;\n  }\n\n  public preparePopup(): void {\n    this.openPopup({ title: 'Plex Auth', w: 600, h: 700 });\n  }\n\n  public async login(): Promise<string> {\n    this.initializeHeaders();\n    await this.getPin();\n\n    if (!this.plexHeaders || !this.pin) {\n      throw new Error('Unable to call login if class is not initialized.');\n    }\n\n    const params = {\n      clientID: this.plexHeaders['X-Plex-Client-Identifier'],\n      'context[device][product]': this.plexHeaders['X-Plex-Product'],\n      'context[device][version]': this.plexHeaders['X-Plex-Version'],\n      'context[device][platform]': this.plexHeaders['X-Plex-Platform'],\n      'context[device][platformVersion]':\n        this.plexHeaders['X-Plex-Platform-Version'],\n      'context[device][device]': this.plexHeaders['X-Plex-Device'],\n      'context[device][deviceName]': this.plexHeaders['X-Plex-Device-Name'],\n      'context[device][model]': this.plexHeaders['X-Plex-Model'],\n      'context[device][screenResolution]':\n        this.plexHeaders['X-Plex-Device-Screen-Resolution'],\n      'context[device][layout]': 'desktop',\n      code: this.pin.code,\n    };\n\n    if (this.popup) {\n      this.popup.location.href = `https://app.plex.tv/auth/#!?${this.encodeData(\n        params\n      )}`;\n    }\n\n    return this.pinPoll();\n  }\n\n  private async pinPoll(): Promise<string> {\n    const executePoll = async (\n      resolve: (authToken: string) => void,\n      reject: (e: Error) => void\n    ) => {\n      try {\n        if (!this.pin) {\n          throw new Error('Unable to poll when pin is not initialized.');\n        }\n\n        const response = await axios.get(\n          `https://plex.tv/api/v2/pins/${this.pin.id}`,\n          { headers: this.plexHeaders }\n        );\n\n        if (response.data?.authToken) {\n          this.authToken = response.data.authToken as string;\n          this.closePopup();\n          resolve(this.authToken);\n        } else if (!response.data?.authToken && !this.popup?.closed) {\n          setTimeout(executePoll, 1000, resolve, reject);\n        } else {\n          reject(new Error('Popup closed without completing login'));\n        }\n      } catch (e) {\n        this.closePopup();\n        reject(e);\n      }\n    };\n\n    return new Promise(executePoll);\n  }\n\n  private closePopup(): void {\n    this.popup?.close();\n    this.popup = undefined;\n  }\n\n  private openPopup({\n    title,\n    w,\n    h,\n  }: {\n    title: string;\n    w: number;\n    h: number;\n  }): Window | void {\n    if (!window) {\n      throw new Error(\n        'Window is undefined. Are you running this in the browser?'\n      );\n    }\n    // Fixes dual-screen position                         Most browsers      Firefox\n    const dualScreenLeft =\n      window.screenLeft != undefined ? window.screenLeft : window.screenX;\n    const dualScreenTop =\n      window.screenTop != undefined ? window.screenTop : window.screenY;\n    const width = window.innerWidth\n      ? window.innerWidth\n      : document.documentElement.clientWidth\n        ? document.documentElement.clientWidth\n        : screen.width;\n    const height = window.innerHeight\n      ? window.innerHeight\n      : document.documentElement.clientHeight\n        ? document.documentElement.clientHeight\n        : screen.height;\n    const left = width / 2 - w / 2 + dualScreenLeft;\n    const top = height / 2 - h / 2 + dualScreenTop;\n\n    //Set url to login/plex/loading so browser doesn't block popup\n    const newWindow = window.open(\n      '/login/plex/loading',\n      title,\n      'scrollbars=yes, width=' +\n        w +\n        ', height=' +\n        h +\n        ', top=' +\n        top +\n        ', left=' +\n        left\n    );\n    if (newWindow) {\n      newWindow.focus();\n      this.popup = newWindow;\n      return this.popup;\n    }\n  }\n\n  private encodeData(data: Record<string, string>): string {\n    return Object.keys(data)\n      .map(function (key) {\n        return [key, data[key]].map(encodeURIComponent).join('=');\n      })\n      .join('&');\n  }\n}\n\nexport default PlexOAuth;\n"
  },
  {
    "path": "src/utils/polyfillIntl.ts",
    "content": "import { shouldPolyfill as shouldPolyfillDisplayNames } from '@formatjs/intl-displaynames/should-polyfill';\nimport { shouldPolyfill as shouldPolyfillLocale } from '@formatjs/intl-locale/should-polyfill';\nimport { shouldPolyfill as shouldPolyfillPluralrules } from '@formatjs/intl-pluralrules/should-polyfill';\n\nconst polyfillLocale = async () => {\n  if (shouldPolyfillLocale()) {\n    await import('@formatjs/intl-locale/polyfill');\n  }\n};\n\nconst polyfillPluralRules = async (locale: string) => {\n  const unsupportedLocale = shouldPolyfillPluralrules(locale);\n  // This locale is supported\n  if (!unsupportedLocale) {\n    return;\n  }\n  // Load the polyfill 1st BEFORE loading data\n  await import('@formatjs/intl-pluralrules/polyfill-force');\n  await import(`@formatjs/intl-pluralrules/locale-data/${unsupportedLocale}`);\n};\n\nconst polyfillDisplayNames = async (locale: string) => {\n  const unsupportedLocale = shouldPolyfillDisplayNames(locale);\n  // This locale is supported\n  if (!unsupportedLocale) {\n    return;\n  }\n  // Load the polyfill 1st BEFORE loading data\n  await import('@formatjs/intl-displaynames/polyfill-force');\n  await import(`@formatjs/intl-displaynames/locale-data/${unsupportedLocale}`);\n};\n\nexport const polyfillIntl = async (locale: string) => {\n  await polyfillLocale();\n  await polyfillPluralRules(locale);\n  await polyfillDisplayNames(locale);\n};\n"
  },
  {
    "path": "src/utils/pushSubscriptionHelpers.ts",
    "content": "import type { UserPushSubscription } from '@server/entity/UserPushSubscription';\nimport type { PublicSettingsResponse } from '@server/interfaces/api/settingsInterfaces';\nimport axios from 'axios';\n\n// Taken from https://www.npmjs.com/package/web-push\nfunction urlBase64ToUint8Array(base64String: string) {\n  const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n  const base64 = `${base64String}${padding}`\n    .replace(/-/g, '+')\n    .replace(/_/g, '/');\n\n  const rawData = window.atob(base64);\n  const outputArray = new Uint8Array(rawData.length);\n\n  for (let i = 0; i < rawData.length; ++i)\n    outputArray[i] = rawData.charCodeAt(i);\n\n  return outputArray;\n}\n\nexport const getPushSubscription = async () => {\n  const registration = await navigator.serviceWorker.ready;\n  const subscription = await registration.pushManager.getSubscription();\n  return { registration, subscription };\n};\n\nexport const verifyPushSubscription = async (\n  userId: number | undefined,\n  currentSettings: PublicSettingsResponse\n): Promise<boolean> => {\n  if (!('serviceWorker' in navigator) || !userId) {\n    return false;\n  }\n\n  try {\n    const { subscription } = await getPushSubscription();\n\n    if (!subscription) {\n      return false;\n    }\n\n    const appServerKey = subscription.options?.applicationServerKey;\n    if (!(appServerKey instanceof ArrayBuffer)) {\n      return false;\n    }\n\n    const currentServerKey = new Uint8Array(appServerKey).toString();\n    const expectedServerKey = urlBase64ToUint8Array(\n      currentSettings.vapidPublic\n    ).toString();\n\n    if (currentServerKey !== expectedServerKey) {\n      return false;\n    }\n\n    const endpoint = subscription.endpoint;\n\n    const { data } = await axios.get<UserPushSubscription>(\n      `/api/v1/user/${userId}/pushSubscription/${encodeURIComponent(endpoint)}`\n    );\n\n    return data.endpoint === endpoint;\n  } catch {\n    return false;\n  }\n};\n\nexport const verifyAndResubscribePushSubscription = async (\n  userId: number | undefined,\n  currentSettings: PublicSettingsResponse\n): Promise<boolean> => {\n  if (!userId) {\n    return false;\n  }\n\n  const { subscription } = await getPushSubscription();\n  const isValid = await verifyPushSubscription(userId, currentSettings);\n\n  if (isValid) {\n    return true;\n  }\n\n  if (subscription) {\n    return false;\n  }\n\n  if (currentSettings.enablePushRegistration) {\n    try {\n      const oldEndpoint = await unsubscribeToPushNotifications(userId);\n\n      await subscribeToPushNotifications(userId, currentSettings);\n\n      if (oldEndpoint) {\n        try {\n          await axios.delete(\n            `/api/v1/user/${userId}/pushSubscription/${encodeURIComponent(\n              oldEndpoint\n            )}`\n          );\n        } catch {\n          // Ignore errors when deleting old endpoint (it might not exist)\n        }\n      }\n\n      return true;\n    } catch (error) {\n      throw new Error(`[SW] Resubscribe failed: ${error.message}`, {\n        cause: error,\n      });\n    }\n  }\n\n  return false;\n};\n\nexport const subscribeToPushNotifications = async (\n  userId: number | undefined,\n  currentSettings: PublicSettingsResponse\n) => {\n  if (\n    !('serviceWorker' in navigator) ||\n    !userId ||\n    !currentSettings.enablePushRegistration\n  ) {\n    return false;\n  }\n\n  try {\n    const { registration } = await getPushSubscription();\n\n    if (!registration) {\n      return false;\n    }\n\n    const subscription = await registration.pushManager.subscribe({\n      userVisibleOnly: true,\n      applicationServerKey: currentSettings.vapidPublic,\n    });\n\n    const { endpoint, keys } = subscription.toJSON();\n\n    if (keys?.p256dh && keys?.auth) {\n      await axios.post('/api/v1/user/registerPushSubscription', {\n        endpoint,\n        p256dh: keys.p256dh,\n        auth: keys.auth,\n        userAgent: navigator.userAgent,\n      });\n\n      return true;\n    }\n\n    return false;\n  } catch (error) {\n    throw new Error(\n      `Issue subscribing to push notifications: ${error.message}`,\n      { cause: error }\n    );\n  }\n};\n\nexport const unsubscribeToPushNotifications = async (\n  userId: number | undefined,\n  endpoint?: string\n): Promise<string | null> => {\n  if (!('serviceWorker' in navigator) || !userId) {\n    return null;\n  }\n\n  try {\n    const { subscription } = await getPushSubscription();\n\n    if (!subscription) {\n      return null;\n    }\n\n    const { endpoint: currentEndpoint } = subscription.toJSON();\n\n    if (!endpoint || endpoint === currentEndpoint) {\n      await subscription.unsubscribe();\n      return currentEndpoint ?? null;\n    }\n\n    return null;\n  } catch (error) {\n    throw new Error(\n      `Issue unsubscribing to push notifications: ${error.message}`,\n      { cause: error }\n    );\n  }\n};\n"
  },
  {
    "path": "src/utils/refreshIntervalHelper.ts",
    "content": "import type { DownloadingItem } from '@server/lib/downloadtracker';\n\nexport const refreshIntervalHelper = (\n  downloadItem: {\n    downloadStatus: DownloadingItem[] | undefined;\n    downloadStatus4k: DownloadingItem[] | undefined;\n  },\n  timer: number\n) => {\n  if (\n    (downloadItem.downloadStatus ?? []).length > 0 ||\n    (downloadItem.downloadStatus4k ?? []).length > 0\n  ) {\n    return timer;\n  } else {\n    return 0;\n  }\n};\n"
  },
  {
    "path": "src/utils/typeHelpers.ts",
    "content": "export type Undefinable<T> = T | undefined;\nexport type Nullable<T> = T | null;\nexport type Maybe<T> = T | null | undefined;\n\n/**\n * Helps type objects with an arbitrary number of properties that are\n * usually being defined at export.\n *\n * @param component Main object you want to apply properties to\n * @param properties Object of properties you want to type on the main component\n */\nexport function withProperties<A extends object, B extends object>(\n  component: A,\n  properties: B\n): A & B {\n  (Object.keys(properties) as (keyof B)[]).forEach((key) => {\n    Object.assign(component, { [key]: properties[key] });\n  });\n  return component as A & B;\n}\n"
  },
  {
    "path": "src/utils/urlValidationHelper.ts",
    "content": "export function isValidURL(value: unknown) {\n  try {\n    let url: URL;\n    if (value === undefined || value === null || value === '') {\n      return true;\n    } else if (typeof value === 'string') {\n      url = new URL(value);\n    } else if (value instanceof URL) {\n      url = value;\n    } else {\n      return false;\n    }\n    return url.protocol === 'http:' || url.protocol === 'https:';\n  } catch {\n    return false;\n  }\n}\n"
  },
  {
    "path": "stylelint.config.js",
    "content": "module.exports = {\n  ignoreFiles: ['**/*.js'],\n  rules: {\n    'at-rule-no-unknown': [\n      true,\n      {\n        ignoreAtRules: [\n          'tailwind',\n          'apply',\n          'variants',\n          'responsive',\n          'screen',\n          'layer',\n        ],\n      },\n    ],\n    'declaration-block-trailing-semicolon': null,\n    'no-descending-specificity': null,\n  },\n};\n"
  },
  {
    "path": "tailwind.config.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-require-imports\nconst defaultTheme = require('tailwindcss/defaultTheme');\n\n/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n  mode: 'jit',\n  content: [\n    './node_modules/@seerr-team/react-tailwindcss-datepicker/dist/index.esm.js',\n    './src/pages/**/*.{ts,tsx}',\n    './src/components/**/*.{ts,tsx}',\n  ],\n  theme: {\n    extend: {\n      transitionProperty: {\n        'max-height': 'max-height',\n        width: 'width',\n      },\n      fontFamily: {\n        sans: ['Inter Variable', ...defaultTheme.fontFamily.sans],\n      },\n      typography: (theme) => ({\n        DEFAULT: {\n          css: {\n            color: theme('colors.gray.300'),\n            a: {\n              color: theme('colors.indigo.500'),\n              '&:hover': {\n                color: theme('colors.indigo.400'),\n              },\n            },\n\n            h1: {\n              color: theme('colors.gray.300'),\n            },\n            h2: {\n              color: theme('colors.gray.300'),\n            },\n            h3: {\n              color: theme('colors.gray.300'),\n            },\n            h4: {\n              color: theme('colors.gray.300'),\n            },\n            h5: {\n              color: theme('colors.gray.300'),\n            },\n            h6: {\n              color: theme('colors.gray.300'),\n            },\n\n            strong: {\n              color: theme('colors.gray.400'),\n            },\n\n            code: {\n              color: theme('colors.gray.300'),\n            },\n\n            figcaption: {\n              color: theme('colors.gray.500'),\n            },\n          },\n        },\n      }),\n    },\n    aspectRatio: {\n      auto: 'auto',\n      square: '1 / 1',\n      video: '16 / 9',\n      1: '1',\n      2: '2',\n      3: '3',\n      4: '4',\n      5: '5',\n      6: '6',\n      7: '7',\n      8: '8',\n      9: '9',\n      10: '10',\n      11: '11',\n      12: '12',\n      13: '13',\n      14: '14',\n      15: '15',\n      16: '16',\n    },\n  },\n  plugins: [\n    require('@tailwindcss/forms'),\n    require('@tailwindcss/typography'),\n    require('@tailwindcss/aspect-ratio'),\n  ],\n};\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2021\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"strictPropertyInitialization\": false,\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n    \"useUnknownInCatchVariables\": false,\n    \"incremental\": true,\n    \"baseUrl\": \"src\",\n    \"downlevelIteration\": true,\n    \"paths\": {\n      \"@server/*\": [\"../server/*\"],\n      \"@app/*\": [\"*\"]\n    }\n  },\n  \"include\": [\"next-env.d.ts\", \"src/**/*.ts\", \"src/**/*.tsx\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  }
]